📄 ixjwin32.cxx
字号:
if (!IoControl(IOCTL_Device_Read, NULL, 0,
reblockG729 ? temp_frame_buffer : buffer,
reblockG729 ? sizeof(temp_frame_buffer) : readFrameSize,
&dwBytesReturned, &overlap))
return FALSE;
if (reblockG729) {
switch (temp_frame_buffer[0]) {
case 1 :
memcpy(buffer, &temp_frame_buffer[1], 10);
count = 10;
break;
case 2 :
if (CodecInfo[readCodecType].vad) {
*(WORD *)buffer = temp_frame_buffer[1];
count = 2;
}
else {
memset(buffer, 0, 10);
count = 10;
}
break;
default : // Must be old driver
memcpy(buffer, temp_frame_buffer, 10);
count = 10;
}
}
else if (CodecInfo[readCodecType].isG7231) {
// Pick out special cases for G.723.1 based codecs (variable length frames)
static const PINDEX g723count[4] = { 24, 20, 4, 1 };
count = g723count[(*(BYTE *)buffer)&3];
}
else
count = (PINDEX)dwBytesReturned;
return TRUE;
}
BOOL OpalIxJDevice::WriteFrame(unsigned, const void * buffer, PINDEX count, PINDEX & written)
{
PWaitAndSignal mutex(writeMutex);
if (writeStopped)
return FALSE;
DWORD dwResult = 0;
DWORD dwBytesReturned = 0;
if (inRawMode) {
for (written = 0; written < count; written += dwResult) {
if (WaitForSingleObjectEx(hWriteEvent, 1000, TRUE) != WAIT_OBJECT_0) {
osError = EAGAIN;
PTRACE(1, "xJack\tWrite Timeout!");
return FALSE;
}
IoControl(IOCTL_Fax_Write, ((BYTE *)buffer)+written, count-written,
&dwResult, sizeof(dwResult), &dwBytesReturned);
}
return TRUE;
}
WORD temp_frame_buffer[12];
PINDEX bytesToWrite;
if (CodecInfo[writeCodecType].isG7231) {
// Pick out special cases for G.723.1 based codecs (variable length frames)
switch ((*(BYTE *)buffer)&3) {
case 0 : // 6.3kbps rate frame
written = 24;
break;
case 1 : // 5.3kbps rate frame
written = 20;
break;
case 2 : // a Silence Insertion Descriptor
memset(temp_frame_buffer, 0, sizeof(temp_frame_buffer));
*(DWORD *)(temp_frame_buffer) = *(const DWORD *)buffer;
buffer = temp_frame_buffer;
written = 4;
break;
case 3 : // repeat last CNG frame
// Check for frame erasure command
if (memcmp(buffer, "\xff\xff\xff\xff", 4) == 0)
written = 24;
else {
memset(temp_frame_buffer, 0, sizeof(temp_frame_buffer));
temp_frame_buffer[0] = 3;
buffer = temp_frame_buffer;
written = 1;
}
break;
}
bytesToWrite = 24;
}
else if (CodecInfo[writeCodecType].isG729) {
if (count == 2) {
PTRACE_IF(2, !CodecInfo[readCodecType].vad,
"xJack\tG.729B frame received, but not selected.");
temp_frame_buffer[0] = 2;
temp_frame_buffer[1] = *(const WORD *)buffer;
memset(&temp_frame_buffer[2], 0, 8);
written = 2;
}
else {
if (memcmp(buffer, "\0\0\0\0\0\0\0\0\0", 10) == 0) {
#if 0
memset(temp_frame_buffer, 0, 12);
#else
// We really should be sending a full frame of zeros here, but the codec
// makes a clicking sound if you do so send annex B CNG frames instead.
temp_frame_buffer[0] = 2;
memset(&temp_frame_buffer[1], 0, 10);
#endif
}
else {
temp_frame_buffer[0] = 1;
memcpy(&temp_frame_buffer[1], buffer, 10);
}
written = 10;
}
buffer = temp_frame_buffer;
bytesToWrite = 12;
}
else {
bytesToWrite = writeFrameSize;
written = bytesToWrite;
}
if (count < written) {
osError = EINVAL;
PTRACE(1, "xJack\tWrite of too small a buffer");
return FALSE;
}
PWin32Overlapped overlap;
return IoControl(IOCTL_Device_Write, (void *)buffer, bytesToWrite,
&dwResult, sizeof(dwResult), &dwBytesReturned, &overlap);
}
unsigned OpalIxJDevice::GetAverageSignalLevel(unsigned, BOOL playback)
{
DWORD dwLevel;
if (!IoControl(playback ? IOCTL_Playback_GetAvgPlaybackLevel
: IOCTL_Record_GetAvgRecordLevel,
0, &dwLevel))
return UINT_MAX;
return dwLevel;
}
BOOL OpalIxJDevice::EnableAudio(unsigned line, BOOL enable)
{
if (line >= GetLineCount())
return FALSE;
DWORD dwSource = ANALOG_SOURCE_SPEAKERPHONE;
if (enable) {
if (enabledAudioLine != line) {
if (enabledAudioLine != UINT_MAX && exclusiveAudioMode) {
PTRACE(3, "xJack\tEnableAudio on port when already enabled other port.");
return FALSE;
}
enabledAudioLine = line;
}
dwSource = line == POTSLine ? ANALOG_SOURCE_POTSPHONE : ANALOG_SOURCE_PSTNLINE;
}
else
enabledAudioLine = UINT_MAX;
if (!IsLineJACK())
return IoControl(IOCTL_DevCtrl_SetAnalogSource, dwSource);
BOOL connected = IsLineToLineDirect(POTSLine, PSTNLine);
IoControl(IOCTL_DevCtrl_SetLineJackMode,
dwSource == ANALOG_SOURCE_PSTNLINE ? LINEJACK_MODE_LINEJACK
: LINEJACK_MODE_PHONEJACK);
SetLineToLineDirect(POTSLine, PSTNLine, connected);
if (dwSource != ANALOG_SOURCE_PSTNLINE) {
if (!IoControl(IOCTL_DevCtrl_SetAnalogSource, dwSource))
return FALSE;
}
InternalSetVolume(TRUE, RecordMicrophone, -1, dwSource != ANALOG_SOURCE_SPEAKERPHONE);
InternalSetVolume(TRUE, RecordPhoneIn, -1, dwSource != ANALOG_SOURCE_POTSPHONE);
InternalSetVolume(FALSE,PlaybackPhoneOut, -1, dwSource != ANALOG_SOURCE_POTSPHONE);
InternalSetVolume(TRUE, RecordPhoneLineIn, -1, dwSource != ANALOG_SOURCE_PSTNLINE);
InternalSetVolume(FALSE,PlaybackPhoneLineOut,-1, dwSource != ANALOG_SOURCE_PSTNLINE);
InternalSetVolume(FALSE,PlaybackWave, -1, FALSE);
return TRUE;
}
BOOL OpalIxJDevice::IsAudioEnabled(unsigned line)
{
return enabledAudioLine == line;
}
BOOL OpalIxJDevice::InternalSetVolume(BOOL record, unsigned id, int volume, int mute)
{
MIXER_LINE mixer;
mixer.dwLineID = id;
DWORD dwSize = 0;
if (!IoControl(record ? IOCTL_Mixer_GetRecordLineControls
: IOCTL_Mixer_GetPlaybackLineControls,
&mixer, sizeof(mixer), &mixer, sizeof(mixer), &dwSize))
return FALSE;
if (volume >= 0) {
if (volume >= 100)
mixer.dwRightVolume = 65535;
else
mixer.dwRightVolume = volume*65536/100;
mixer.dwLeftVolume = mixer.dwRightVolume;
}
if (mute >= 0)
mixer.dwMute = mute != 0;
DWORD dwReturn;
return IoControl(record ? IOCTL_Mixer_SetRecordLineControls
: IOCTL_Mixer_SetPlaybackLineControls,
&mixer, sizeof(mixer), &dwReturn, sizeof(dwReturn), &dwSize);
}
BOOL OpalIxJDevice::SetRecordVolume(unsigned line, unsigned volume)
{
if (IsLineJACK()) {
if (!InternalSetVolume(TRUE,
line == POTSLine ? RecordPhoneIn : RecordPhoneLineIn,
volume,
-1))
return FALSE;
}
return InternalSetVolume(TRUE, RecordMaster, volume, -1);
}
BOOL OpalIxJDevice::SetPlayVolume(unsigned line, unsigned volume)
{
if (IsLineJACK()) {
if (!InternalSetVolume(FALSE,
line == POTSLine ? PlaybackPhoneOut : PlaybackPhoneLineOut,
volume,
-1))
return FALSE;
}
return InternalSetVolume(FALSE, PlaybackMaster, volume, -1);
}
BOOL OpalIxJDevice::GetRecordVolume(unsigned, unsigned & volume)
{
MIXER_LINE mixer;
mixer.dwLineID = 0;
DWORD dwSize = 0;
if (!IoControl(IOCTL_Mixer_GetRecordLineControls,
&mixer, sizeof(mixer), &mixer, sizeof(mixer), &dwSize))
return FALSE;
if (mixer.dwLeftVolume > 65208) // 99.5%
volume = 100;
else
volume = mixer.dwLeftVolume*100/65536;
return TRUE;
}
BOOL OpalIxJDevice::GetPlayVolume(unsigned, unsigned & volume)
{
MIXER_LINE mixer;
mixer.dwLineID = 0;
DWORD dwSize = 0;
if (!IoControl(IOCTL_Mixer_GetPlaybackLineControls,
&mixer, sizeof(mixer), &mixer, sizeof(mixer), &dwSize))
return FALSE;
if (mixer.dwLeftVolume > 65208) // 99.5%
volume = 100;
else
volume = mixer.dwLeftVolume*100/65536;
return TRUE;
}
OpalLineInterfaceDevice::AECLevels OpalIxJDevice::GetAEC(unsigned)
{
DWORD level = AECOff;
IoControl(IOCTL_Speakerphone_GetAEC, 0, &level);
return (AECLevels)level;
}
BOOL OpalIxJDevice::SetAEC(unsigned, AECLevels level)
{
return IoControl(IOCTL_Speakerphone_SetAEC, level);
}
unsigned OpalIxJDevice::GetWinkDuration(unsigned)
{
DWORD level = 0;
IoControl(IOCTL_DevCtrl_GetLineWinkDetTime, 0, &level);
return (unsigned)level;
}
BOOL OpalIxJDevice::SetWinkDuration(unsigned, unsigned winkDuration)
{
return IoControl(IOCTL_DevCtrl_SetLineWinkDetTime, winkDuration);
}
BOOL OpalIxJDevice::GetVAD(unsigned)
{
return vadEnabled;
}
BOOL OpalIxJDevice::SetVAD(unsigned, BOOL enable)
{
PTRACE(3, "xJack\tSet VAD " << (enable ? "on" : "off"));
vadEnabled = enable;
return IoControl(enable ? IOCTL_Record_EnableVAD : IOCTL_Record_DisableVAD);
}
BOOL OpalIxJDevice::GetCallerID(unsigned, PString & idString, BOOL full)
{
idString = PString();
BYTE buffer[512];
buffer[0] = 0;
DWORD dwBytesReturned;
if (!IoControl(IOCTL_DevCtrl_LineGetCallerID,
buffer, sizeof(buffer),
buffer, sizeof(buffer),
&dwBytesReturned))
return FALSE;
PTRACE_IF(3, buffer[0] != 0, "xJack\tCaller ID:\n"
<< hex << setprecision(2)
<< PBYTEArray(buffer, dwBytesReturned)
<< dec);
PString name, timeStr;
switch (buffer[0]) {
case 4 : // Single message
timeStr = PString((char *)&buffer[2], 8);
idString = PString((char *)&buffer[10], buffer[1]-8);
break;
case 128 : {
PINDEX totalLength = buffer[1];
PINDEX pos = 2;
while (pos < totalLength) {
switch (buffer[pos]) {
case 1 :
timeStr = PString((char *)&buffer[pos+2], buffer[pos+1]);
break;
case 2 :
idString = PString((char *)&buffer[pos+2], buffer[pos+1]);
break;
case 7 :
name = PString((char *)&buffer[pos+2], buffer[pos+1]);
break;
}
pos += buffer[pos+1]+2;
}
break;
}
default :
return FALSE;
}
if (full && !timeStr.IsEmpty()) {
PTime now;
int minute = timeStr(6,7).AsUnsigned() % 60;
int hour = timeStr(4,5).AsUnsigned() % 24;
int day = timeStr(2,3).AsUnsigned();
if (day < 1)
day = 1;
else if (day > 31)
day = 31;
int month = timeStr(0,1).AsUnsigned();
if (month < 1)
month = 1;
else if (month > 12)
month = 12;
PTime theTime(0, minute, hour, day, month, now.GetYear());
idString += '\t' + theTime.AsString(PTime::ShortDateTime) + '\t' + name;
}
return TRUE;
}
BOOL OpalIxJDevice::SetCallerID(unsigned line, const PString & idString)
{
if (line != POTSLine)
return FALSE;
if (idString.IsEmpty())
return TRUE;
PString name, number;
PTime theTime;
PStringArray fields = idString.Tokenise('\t', TRUE);
switch (fields.GetSize()) {
case 3 :
name = fields[2];
case 2 :
theTime = PTime(fields[1]);
case 1 :
number = fields[0];
break;
default :
return FALSE;
}
PINDEX numberLength = number.GetLength();
PINDEX nameLength = name.GetLength();
char buffer[256];
buffer[0] = 1;
buffer[1] = '\x80';
buffer[2] = (char)(14+numberLength+nameLength);
buffer[3] = 1;
buffer[4] = 8;
sprintf(&buffer[5],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -