📄 ixjwin32.cxx
字号:
* Revision 1.4 1999/10/28 12:21:34 robertj
* Added AEC support and speakerphone switching button.
*
* Revision 1.3 1999/10/27 06:30:31 robertj
* Added CancelIO command when closing channel.
*
* Revision 1.2 1999/10/24 14:51:41 robertj
* Removed EnableDetectDTMF() as unix ioctl does not exist.
*
* Revision 1.1 1999/10/24 12:59:41 robertj
* Added platform independent support for Quicknet xJACK cards.
*
*/
#include <ptlib.h>
#include <lids/ixjlid.h>
////////////////////////////////////////////////
/// Get rid of LNK4221: no public symbols found;
/// archive member will be inaccessible
const char * ixjwin32_file_content = NULL;
////////////////////////////////////////////////
#if HAS_IXJ
#include <lids/QTIoctl.h>
#include <lids/ixjDefs.h>
#pragma comment(lib, "winmm.lib")
#define NEW_DRIVER_VERSION ((5<<24)|(5<<16)|141)
#define new PNEW
static enum {
IsWindows9x,
IsWindowsNT,
IsWindows2k
} GetOperatingSystem()
{
static OSVERSIONINFO version;
if (version.dwOSVersionInfoSize == 0) {
version.dwOSVersionInfoSize = sizeof(version);
GetVersionEx(&version);
}
if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
return IsWindows9x;
if (version.dwMajorVersion < 5)
return IsWindowsNT;
return IsWindows2k;
}
#define IsLineJACK() (dwCardType == 3)
/////////////////////////////////////////////////////////////////////////////
OpalIxJDevice::OpalIxJDevice()
{
hDriver = INVALID_HANDLE_VALUE;
driverVersion = 0;
readStopped = writeStopped = TRUE;
readFrameSize = writeFrameSize = 480; // 30 milliseconds of 16 bit PCM data
readCodecType = writeCodecType = P_MAX_INDEX;
currentHookState = lastHookState = FALSE;
inRawMode = FALSE;
enabledAudioLine = UINT_MAX;
exclusiveAudioMode = TRUE;
lastDTMFDigit = 0;
hReadEvent = hWriteEvent = NULL;
}
BOOL OpalIxJDevice::Open(const PString & device)
{
Close();
PTRACE(3, "xJack\tOpening IxJ device \"" << device << '"');
DWORD dwDeviceId = device.AsUnsigned(16);
PString devicePath;
const char * DevicePathPrefix = "\\\\.\\QTJACKDevice";
switch (GetOperatingSystem()) {
case IsWindows2k :
DevicePathPrefix = "\\\\.\\QTIWDMDevice";
// Flow into NT case
case IsWindowsNT :
if (dwDeviceId < 100) {
devicePath = device.Left(device.Find(' '));
if (strspn(devicePath, "0123456789") == strlen(devicePath))
devicePath = DevicePathPrefix + devicePath;
}
else {
PStringArray allDevices = GetDeviceNames();
for (PINDEX dev = 0; dev < allDevices.GetSize(); dev++) {
PString thisDevice = allDevices[dev];
if (thisDevice.Find(device) != P_MAX_INDEX) {
devicePath = thisDevice.Left(thisDevice.Find(' '));
break;
}
}
}
timeBeginPeriod(2);
break;
case IsWindows9x :
devicePath = "\\\\.\\Qtipj.vxd";
}
hDriver = CreateFile(devicePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (hDriver == INVALID_HANDLE_VALUE) {
osError = ::GetLastError()|PWIN32ErrorFlag;
return FALSE;
}
if (GetOperatingSystem() == IsWindows9x) {
DWORD dwResult = 0;
if (!IoControl(IOCTL_Device_Open, dwDeviceId, &dwResult) || dwResult == 0) {
CloseHandle(hDriver);
hDriver = INVALID_HANDLE_VALUE;
osError = ENOENT;
return FALSE;
}
deviceName = psprintf("%08X", dwDeviceId);
}
else {
dwDeviceId = GetSerialNumber();
if (dwDeviceId == 0) {
CloseHandle(hDriver);
hDriver = INVALID_HANDLE_VALUE;
osError = ENOENT;
return FALSE;
}
deviceName = devicePath;
}
dwCardType = dwDeviceId >> 28;
IoControl(IOCTL_Codec_SetKHz, 8000);
IoControl(IOCTL_Idle_SetMasterGain, 15);
IoControl(IOCTL_Filter_EnableDTMFDetect);
IoControl(IOCTL_Speakerphone_AECOn);
DWORD ver = 0;
IoControl(IOCTL_VxD_GetVersion, 0, &ver);
driverVersion = ((ver&0xff)<<24)|((ver&0xff00)<<8)|((ver>>16)&0xffff);
PTRACE(2, "xJack\tOpened IxJ device \"" << GetDescription() << "\" version "
<< ((driverVersion>>24)&0xff ) << '.'
<< ((driverVersion>>16)&0xff ) << '.'
<< ( driverVersion &0xffff));
os_handle = 1;
return TRUE;
}
BOOL OpalIxJDevice::Close()
{
if (!IsOpen())
return FALSE;
RingLine(0, 0);
StopReadCodec(0);
StopWriteCodec(0);
StopRawCodec(0);
SetLineToLineDirect(0, 1, TRUE); // Back to pass through mode
if (GetOperatingSystem() == IsWindows9x)
IoControl(IOCTL_Device_Close);
else
timeEndPeriod(2);
deviceName = PString();
if (hReadEvent != NULL) {
CloseHandle(hReadEvent);
hReadEvent = NULL;
}
if (hWriteEvent != NULL) {
CloseHandle(hWriteEvent);
hWriteEvent = NULL;
}
BOOL ok = CloseHandle(hDriver);
hDriver = INVALID_HANDLE_VALUE;
os_handle = -1;
return ok;
}
PString OpalIxJDevice::GetDeviceType() const
{
return OPAL_IXJ_TYPE_NAME;
}
PString OpalIxJDevice::GetDeviceName() const
{
return deviceName;
}
PString OpalIxJDevice::GetDescription() const
{
PStringStream name;
name << "Internet ";
switch (dwCardType) {
case 0 :
case 1 :
name << "PhoneJACK";
break;
case 3 :
name << "LineJACK";
break;
case 4 :
name << "PhoneJACK-Lite";
break;
case 5 :
name << "PhoneJACK-PCI";
break;
case 6 :
name << "PhoneCARD";
break;
default :
name << "xJACK";
}
name << " (" << deviceName << ')';
return name;
}
PStringArray OpalIxJDevice::GetAllNames() const
{
return GetDeviceNames();
}
unsigned OpalIxJDevice::GetLineCount()
{
return IsLineJACK() ? NumLines : 1;
}
BOOL OpalIxJDevice::IsLinePresent(unsigned line, BOOL force)
{
if (line >= GetLineCount())
return FALSE;
if (line != PSTNLine)
return FALSE;
int oldSlicState = -1;
DWORD dwResult = 0;
do {
if (!IoControl(IOCTL_DevCtrl_GetLineTestResult, 0, &dwResult))
return FALSE;
if (dwResult == 0xffffffff || force) {
if (dwResult == LINE_TEST_OK) {
IoControl(IOCTL_DevCtrl_GetPotsToSlic, 0, &dwResult);
oldSlicState = dwResult;
}
IoControl(IOCTL_DevCtrl_LineTest);
dwResult = LINE_TEST_TESTING;
force = FALSE;
}
} while (dwResult == LINE_TEST_TESTING);
if (oldSlicState >= 0)
IoControl(IOCTL_DevCtrl_SetPotsToSlic, oldSlicState);
return dwResult == LINE_TEST_OK;
}
BOOL OpalIxJDevice::IsLineOffHook(unsigned line)
{
if (line >= GetLineCount())
return FALSE;
DWORD dwResult = 0;
if (line == PSTNLine) {
if (!IoControl(IOCTL_DevCtrl_GetLineOnHook, 0, &dwResult))
return FALSE;
return dwResult == 0;
}
if (!IoControl(IsLineJACK() && IsLinePresent(PSTNLine)
? IOCTL_DevCtrl_GetLinePhoneOnHook
: IOCTL_DevCtrl_GetOnHook, 0, &dwResult))
return FALSE;
BOOL newHookState = dwResult == 0;
if (lastHookState != newHookState) {
lastHookState = newHookState;
hookTimeout = 250;
}
else {
if (!hookTimeout.IsRunning())
currentHookState = lastHookState;
}
return currentHookState;
}
BOOL OpalIxJDevice::SetLineOffHook(unsigned line, BOOL newState)
{
if (line >= GetLineCount())
return FALSE;
if (line != PSTNLine)
return FALSE;
return IoControl(IOCTL_DevCtrl_LineSetOnHook, !newState);
}
BOOL OpalIxJDevice::HasHookFlash(unsigned line)
{
if (line != POTSLine)
return FALSE;
DWORD dwResult;
if (!IoControl(IOCTL_DevCtrl_GetFlashState, 0, &dwResult))
return FALSE;
if (lastFlashState == dwResult)
return FALSE;
lastFlashState = dwResult;
return dwResult != 0;
}
BOOL OpalIxJDevice::IsLineRinging(unsigned line, DWORD * /*cadence*/)
{
if (line >= GetLineCount())
return FALSE;
if (line != PSTNLine)
return FALSE;
if (ringTimeout.IsRunning())
return TRUE;
DWORD dwResult = 0;
if (!IoControl(IOCTL_DevCtrl_LineGetRinging, 0, &dwResult) || dwResult == 0)
return FALSE;
ringTimeout = 2500;
return TRUE;
}
BOOL OpalIxJDevice::RingLine(unsigned line, DWORD cadence)
{
if (line >= GetLineCount())
return FALSE;
if (line != POTSLine)
return FALSE;
if (cadence == TRUE) {
switch (countryCode) {
case Australia :
static unsigned AusRing[] = { 200, 400, 200, 2000 };
return RingLine(line, PARRAYSIZE(AusRing), AusRing);
}
// United States ring pattern
cadence = 0x00f;
}
IoControl(IOCTL_DevCtrl_SetPotsToSlic, 1);
return IoControl(IOCTL_DevCtrl_SetRingPattern, cadence);
}
BOOL OpalIxJDevice::RingLine(unsigned line, PINDEX nCadence, unsigned * pattern)
{
if (line >= GetLineCount())
return FALSE;
if (line != POTSLine)
return FALSE;
IoControl(IOCTL_DevCtrl_SetPotsToSlic, 1);
DWORD dwReturn, dwSize;
DWORD cadenceArray[10];
cadenceArray[0] = (nCadence+1)/2; // Number of pairs
cadenceArray[1] = (nCadence&1) == 0; // If odd then repeat last entry
PINDEX i;
for (i = 2; i < nCadence; i++)
cadenceArray[i] = pattern[i-2];
for (; i < PARRAYSIZE(cadenceArray); i++)
cadenceArray[i] = 0;
return IoControl(IOCTL_DevCtrl_SetRingCadence,
cadenceArray, sizeof(cadenceArray),
&dwReturn, sizeof(dwReturn), &dwSize);
}
BOOL OpalIxJDevice::IsLineDisconnected(unsigned line, BOOL checkForWink)
{
if (line >= GetLineCount())
return FALSE;
if (line != PSTNLine)
return !IsLineOffHook(line);
if (checkForWink) {
DWORD dwResult = 0;
if (IoControl(IOCTL_DevCtrl_GetLineCallerOnHook, 0, &dwResult) && dwResult != 0) {
PTRACE(3, "xJack\tDetected wink, line disconnected.");
return TRUE;
}
}
/* if ((IsToneDetected(line) & (DialTone|BusyTone)) != 0) { */
if ((IsToneDetected(line) & BusyTone) != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -