📄 ixjunix.cxx
字号:
case 0:
case PhoneJACK:
dspMax = isPlay ? 0x100 : 0x200;
break;
case LineJACK:
dspMax = 0x200;
break;
case PhoneJACK_Lite:
dspMax = 0x200;
break;
case PhoneJACK_PCI:
dspMax = 0x100;
break;
case PhoneCARD:
dspMax = 0x200;
break;
case PhoneJACK_PCI_TJ:
if (line == POTSLine)
dspMax = 0x100;
else
dspMax = 0x60;
}
/* The dsp volume is exponential in nature.
You can plot this exponential function with gnuplot.
gnuplot
plot [t=0:100] exp((t/20) -1) / exp(4) */
PINDEX res = (PINDEX) (dspMax * exp((((double)volume) / 20.0) - 1) / exp(4.0));
return res;
}
BOOL OpalIxJDevice::SetRecordVolume(unsigned line, unsigned volume)
{
PWaitAndSignal mutex1(readMutex);
userRecVol = volume;
if ((aecLevel == AECAGC) || inRawMode)
return TRUE;
return IOCTL2(os_handle, IXJCTL_REC_VOLUME, LogScaleVolume(line, volume, FALSE));
}
BOOL OpalIxJDevice::GetRecordVolume(unsigned, unsigned & volume)
{
volume = userRecVol;
return TRUE;
}
BOOL OpalIxJDevice::SetPlayVolume(unsigned line, unsigned volume)
{
PWaitAndSignal mutex1(readMutex);
userPlayVol = volume;
if (inRawMode)
return TRUE;
return IOCTL2(os_handle, IXJCTL_PLAY_VOLUME, LogScaleVolume(line, volume, TRUE));
}
BOOL OpalIxJDevice::GetPlayVolume(unsigned, unsigned & volume)
{
volume = userPlayVol;
return TRUE;
}
OpalLineInterfaceDevice::AECLevels OpalIxJDevice::GetAEC(unsigned)
{
return aecLevel;
}
BOOL OpalIxJDevice::SetAEC(unsigned line, AECLevels level)
{
aecLevel = level;
if (inRawMode)
return TRUE;
// IXJCTL_AEC_START does not set return code
IOCTL2(os_handle, IXJCTL_AEC_START, aecLevel);
// if coming out of AGC mode, then set record volume just in case
if (aecLevel == AECAGC)
SetRecordVolume(line, userRecVol);
return TRUE;
}
unsigned OpalIxJDevice::GetWinkDuration(unsigned)
{
if (!IsOpen())
return 0;
return IOCTL2(os_handle, IXJCTL_WINK_DURATION, 0);
}
BOOL OpalIxJDevice::SetWinkDuration(unsigned, unsigned winkDuration)
{
if (!IsOpen())
return FALSE;
return IOCTL2(os_handle, IXJCTL_WINK_DURATION, winkDuration);
}
BOOL OpalIxJDevice::GetVAD(unsigned)
{
return FALSE;
}
BOOL OpalIxJDevice::SetVAD(unsigned, BOOL)
{
return FALSE;
}
BOOL OpalIxJDevice::GetCallerID(unsigned line, PString & callerId, BOOL /*full*/)
{
#if TELEPHONY_VERSION < 3000
return FALSE;
#else
if (line != PSTNLine)
return FALSE;
// string is "number <TAB> time <TAB> name"
PWaitAndSignal m(exceptionMutex);
ExceptionInfo * info = GetException();
if (info->hasCid) {
PHONE_CID cid = info->cid;
callerId = PString(cid.number, cid.numlen) + '\t';
callerId += PString(cid.hour, 3) + ':' + PString(cid.min, 3) + ' ' + PString(cid.month, 3) + '/' + PString(cid.day, 3) + '\t';
callerId += PString(cid.name, cid.namelen);
info->hasCid = FALSE;
return TRUE;
}
return FALSE;
#endif
}
#if TELEPHONY_VERSION >= 3000
static BOOL IsPhoneDigits(const PString & str)
{
PINDEX i;
for (i = 0; i < str.GetLength(); i++)
if (!isdigit(str[i]) && str[i] != '*' && str[i] != '#')
return FALSE;
return TRUE;
}
static void FormatCallerIdString(const PString & idString, PHONE_CID & callerIdInfo)
{
memset(&callerIdInfo, 0, sizeof(callerIdInfo));
if (idString.IsEmpty())
return;
PString name, number;
PTime theTime;
// string is "number <TAB> time <TAB> name"
PStringArray fields = idString.Tokenise('\t', TRUE);
int len = fields.GetSize();
// if the name is specified, then use it
if (len > 2)
name = fields[2];
// if the time is specified, then use it
if (len > 1 && !fields[1].IsEmpty())
theTime = PTime(fields[1]);
// if the number is specified, then only use it if it is legal
// otherwise put it into the name field
if (len > 0) {
if (IsPhoneDigits(fields[0]))
number = fields[0];
else if (name.IsEmpty())
name = fields[0];
}
// truncate name and number fields
if (name.GetLength() > (PINDEX)sizeof(callerIdInfo.name))
name = name.Left(sizeof(callerIdInfo.name));
if (number.GetLength() > (PINDEX)sizeof(callerIdInfo.number))
number = number.Left(sizeof(callerIdInfo.number));
sprintf(callerIdInfo.month, "%02i", theTime.GetMonth());
sprintf(callerIdInfo.day, "%02i", theTime.GetDay());
sprintf(callerIdInfo.hour, "%02i", theTime.GetHour());
sprintf(callerIdInfo.min, "%02i", theTime.GetMinute());
strncpy(callerIdInfo.name, (const char *)name, sizeof(callerIdInfo.name)-1);
callerIdInfo.namelen = name.GetLength();
strncpy(callerIdInfo.number, (const char *)number, sizeof(callerIdInfo.number)-1);
callerIdInfo.numlen = number.GetLength();
}
#endif
BOOL OpalIxJDevice::SetCallerID(unsigned line, const PString & idString)
{
#if TELEPHONY_VERSION < 3000
return FALSE;
#else
if (line != POTSLine)
return FALSE;
FormatCallerIdString(idString, callerIdInfo);
#endif
return TRUE;
}
BOOL OpalIxJDevice::SendCallerIDOnCallWaiting(unsigned line, const PString & idString)
{
#if TELEPHONY_VERSION < 3000
return FALSE;
#else
if (line != POTSLine)
return FALSE;
PHONE_CID callerInfo;
FormatCallerIdString(idString, callerInfo);
IOCTLP(os_handle, IXJCTL_CIDCW, &callerInfo);
return TRUE;
#endif
}
BOOL OpalIxJDevice::SendVisualMessageWaitingIndicator(unsigned line, BOOL on)
{
#if TELEPHONY_VERSION < 3000
return FALSE;
#else
if (line != POTSLine)
return FALSE;
IOCTL2(os_handle, IXJCTL_VMWI, on);
return TRUE;
#endif
}
BOOL OpalIxJDevice::PlayDTMF(unsigned, const char * tones, DWORD onTime, DWORD offTime)
{
PWaitAndSignal mutex(toneMutex);
if (tonePlaying)
return FALSE;
// not really needed, as we have the tone mutex locked
tonePlaying = TRUE;
IOCTL2(os_handle, PHONE_SET_TONE_ON_TIME, onTime * 4);
IOCTL2(os_handle, PHONE_SET_TONE_OFF_TIME, offTime * 4);
while (*tones != '\0') {
char tone = toupper(*tones++);
int code = -1;
if ('1' <= tone && tone <= '9')
code = tone - '0';
else if (tone == '*')
code = 10;
else if (tone == '0')
code = 11;
else if (tone == '#')
code = 12;
else if ('A' <= tone && tone <= 'D')
code = tone - 'A' + 28;
else if ('E' <= tone && tone <= ('E' + 11))
code = (tone - 'E') + 13;
PTRACE(4, "IXJ\tPlaying tone " << tone);
IOCTL2(os_handle, PHONE_PLAY_TONE, code);
PThread::Sleep(onTime + offTime);
long countDown = 200; // a tone longer than 2 seconds? I don't think so...
while ((countDown > 0) && IOCTL(os_handle, PHONE_GET_TONE_STATE) != 0) {
PThread::Sleep(10);
countDown--;
}
if (countDown == 0)
cerr << "Timeout whilst waiting for DTMF tone to end" << endl;
}
// "Realize the truth....There is no tone."
tonePlaying = FALSE;
return TRUE;
}
char OpalIxJDevice::ReadDTMF(unsigned)
{
PWaitAndSignal m(exceptionMutex);
ExceptionInfo * info = GetException();
int p = info->dtmfOut;
if (info->dtmfIn == p)
return '\0';
char ch = info->dtmf[p];
p = (p + 1) % 16;
info->dtmfOut = p;
return ch;
}
BOOL OpalIxJDevice::GetRemoveDTMF(unsigned)
{
return removeDTMF;
}
BOOL OpalIxJDevice::SetRemoveDTMF(unsigned, BOOL state)
{
removeDTMF = state;
return IOCTL2(os_handle, PHONE_DTMF_OOB, state);
}
unsigned OpalIxJDevice::IsToneDetected(unsigned)
{
PWaitAndSignal m(exceptionMutex);
ExceptionInfo * info = GetException();
int tones = NoTone;
if (info->cadence[0] != 0) {
info->cadence[0] = 0;
tones |= DialTone;
}
if (info->cadence[1] != 0) {
info->cadence[1] = 0;
tones |= RingTone;
}
if (info->cadence[2] != 0) {
info->cadence[2] = 0;
tones |= BusyTone;
}
if (info->cadence[3] != 0) {
info->cadence[3] = 0;
tones |= CNGTone;
}
return tones;
}
BOOL OpalIxJDevice::SetToneFilterParameters(unsigned /*line*/,
CallProgressTones tone,
unsigned lowFrequency,
unsigned highFrequency,
PINDEX numCadences,
const unsigned * onTimes,
const unsigned * offTimes)
{
int toneIndex;
switch (tone) {
case DialTone :
toneIndex = 0;
break;
case RingTone :
toneIndex = 1;
break;
case BusyTone :
toneIndex = 2;
break;
case CNGTone :
toneIndex = 3;
break;
default :
PTRACE(1, "xJack\tCannot set filter for tone: " << tone);
return FALSE;
}
#ifdef IXJCTL_SET_FILTER
int filterCode = -1;
int minMatch = 0, maxMatch = 0;
if (lowFrequency == highFrequency) {
static struct {
IXJ_FILTER_FREQ code;
unsigned hertz;
} const FreqToIXJFreq[] = {
{ f350, 350 }, { f300, 300 }, { f330, 330 }, { f340, 340 },
{ f392, 392 }, { f400, 400 }, { f420, 420 }, { f425, 425 },
{ f435, 435 }, { f440, 440 }, { f445, 445 }, { f450, 450 },
{ f452, 452 }, { f475, 475 }, { f480, 480 }, { f494, 494 },
{ f500, 500 }, { f520, 520 }, { f523, 523 }, { f525, 525 },
{ f587, 587 }, { f590, 590 }, { f600, 600 }, { f620, 620 },
{ f660, 660 }, { f700, 700 }, { f740, 740 }, { f750, 750 },
{ f770, 770 }, { f800, 800 }, { f816, 816 }, { f850, 850 },
{ f900, 900 }, { f942, 942 }, { f950, 950 }, { f975, 975 },
{ f1000, 1000 }, { f1020, 1020 }, { f1050, 1050 }, { f1100, 1100 },
{ f1140, 1140 }, { f1200, 1200 }, { f1209, 1209 }, { f1330, 1330 },
{ f1336, 1336 }, { f1380, 1380 }, { f1400, 1400 }, { f1477, 1477 },
{ f1600, 1600 }, { f1800, 1800 }, { f1860, 1860 }
};
PINDEX i;
for (i = 0; i < PARRAYSIZE(FreqToIXJFreq); i++) {
if (lowFrequency == FreqToIXJFreq[i].hertz) {
filterCode = FreqToIXJFreq[i].code;
minMatch = maxMatch = FreqToIXJFreq[i].hertz;
break;
}
}
} else {
static struct {
IXJ_FILTER_FREQ code;
unsigned minHertz;
unsigned maxHertz;
} const FreqToIXJFreq2[] = {
{ f20_50, 20, 50 }, { f133_200, 133, 200 }, { f300_640, 300, 640 },
{ f300_500, 300, 500 }, { f300_425, 300, 425 }, { f350_400, 350, 400 },
{ f350_440, 350, 440 }, { f350_450, 350, 450 }, { f380_420, 380, 420 },
{ f400_425, 400, 425 }, { f400_440, 400, 440 }, { f400_450, 400, 450 },
{ f425_450, 425, 450 }, { f425_475, 425, 475 }, { f440_450, 440, 450 },
{ f440_480, 440, 480 }, { f480_620, 480, 620 }, { f540_660, 540, 660 },
{ f750_1450, 750, 1450 }, { f857_1645, 857, 1645 }, { f900_1300, 900, 1300 },
{ f935_1215, 935, 1215 }, { f941_1477, 941, 1477 }, { f950_1400, 950, 1400 },
{ f1100_1750, 1100, 1750 }, { f1633_1638, 1633, 1638 }
};
PINDEX i;
// look for exact match
for (i = 0; i < PARRAYSIZE(FreqToIXJFreq2); i++) {
if ((lowFrequency == FreqToIXJFreq2[i].minHertz) && (highFrequency == FreqToIXJFreq2[i].maxHertz)) {
filterCode = FreqToIXJFreq2[i].code;
minMatch = FreqToIXJFreq2[i].minHertz;
maxMatch = FreqToIXJFreq2[i].maxHertz;
break;
}
}
// look for an approximate match
if (filterCode == -1) {
for (i = 0; i < PARRAY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -