📄 ixjunix.cxx
字号:
* Revision 1.19 1999/11/18 11:45:40 robertj
* Added missing function from recent tone enhancements.
*
* Revision 1.18 1999/11/16 12:44:46 robertj
* Added more tone generation functions.
*
* Revision 1.17 1999/11/06 13:01:48 craigs
* Fixed problems with GSM emulation mode
*
* Revision 1.16 1999/11/06 05:44:08 robertj
* Fixed problem with read/write locking up when stopping codec.
*
* Revision 1.15 1999/11/06 03:45:27 robertj
* Added volume control functions.
*
* Revision 1.14 1999/11/05 10:56:25 craigs
* New implementation for new channel breakdown
*
* Revision 1.13 1999/11/02 01:22:55 robertj
* Added return values to new tone functions and added GetCallerID() function
*
* Revision 1.12 1999/11/01 23:20:49 craigs
* Added country code initialisation and DTMF tone playing
*
* Revision 1.11 1999/11/01 09:28:36 robertj
* Added flunction to enabled/disable DTM detection
*
* Revision 1.10 1999/10/30 15:10:36 craigs
* Removed checks for return status from DSP start and stop functions
*
* Revision 1.9 1999/10/30 15:03:10 robertj
* Fixed conditions under which codec start stops are not called.
*
* Revision 1.8 1999/10/30 13:29:45 robertj
* Fixed "lock up" problem, added function to get line status.
*
* Revision 1.7 1999/10/30 07:21:46 craigs
* Removed interlock between hookstate and audio path select as Quicknet has updated the driver
*
* Revision 1.6 1999/10/30 06:41:06 craigs
* Fixed problem with badly named devices using ordinals to open
*
* Revision 1.5 1999/10/29 02:28:02 robertj
* Added backward compatibility code so can use simple number for device name.
*
* Revision 1.4 1999/10/28 12:47:23 robertj
* *** empty log message ***
*
* Revision 1.3 1999/10/28 12:38:14 robertj
* Changed AEC to enum for specific values.
*
* Revision 1.2 1999/10/26 07:13:44 craigs
* Fixed problem where handset is reported off-hook when phone not selected for audio path
*
* Revision 1.1 1999/10/24 14:43:20 robertj
* Added platform independent support for Quicknet xJACK cards.
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "ixjlid.h"
#endif
#include <lids/ixjlid.h>
#ifdef HAS_IXJ
#include <sys/time.h>
#include <math.h>
#define new PNEW
#ifndef TELEPHONY_VERSION
#if !defined(PHONE_VAD)
#warning Using extremely old telephony.h, please upgrade!
#define TELEPHONY_VERSION 1000 // Version in 2.2.16 kernel
#elif !defined(IXJCTL_VMWI)
#warning Using very old telephony.h, please upgrade!
#define TELEPHONY_VERSION 2000 // Version in 2.2.18 kernel
#else
#warning Using old telephony.h, please upgrade!
#define TELEPHONY_VERSION 3000 // Version in CVS before addition of TELEPHONY_VERSION
#endif
#endif
#define IsLineJACK() (dwCardType == LineJACK)
#define FLASH_TIME 1000
#define MANUAL_FLASH // undefine to use FLASH exception
#ifdef P_LINUX
#ifdef _DEBUG
static int traced_ioctl(const char * str, int fd, int code)
{
PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ")");
int val = ::ioctl(fd,code);
PTRACE(6,"IXJ\tIOCTL value = " << val);
return val;
}
static int traced_ioctl(const char * str, int fd, int code , unsigned long arg)
{
PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ", " << (void *)arg << ")");
int val = ::ioctl(fd,code,arg);
PTRACE(6,"IXJ\tIOCTL value = " << val);
return val;
}
#define IOCTL(fd,code) traced_ioctl(#code, fd, code)
#define IOCTL2(fd,code,arg) traced_ioctl(#code, fd, code, (unsigned long)(arg))
#define IOCTLP(fd,code,arg) ::ioctl(fd,code,arg)
#else
#define IOCTL(fd,code) ::ioctl(fd,code)
#define IOCTL2(fd,code,arg) ::ioctl(fd,code,arg)
#define IOCTLP(fd,code,arg) ::ioctl(fd,code,arg)
#endif
#endif // P_LINUX
#if TELEPHONY_VERSION < 3013
#define G729B 13
#endif
#ifdef P_FREEBSD
// BSD does not support return values from the ioctl() call
// except via the 3rd parameter.
// Also the 3rd parameter must be the 'address' of the data.
#ifdef _DEBUG
static int traced_bsd_ioctl(const char * str, int fd, int code , unsigned long arg = 0)
{
int val = arg;
int ret;
PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ", " << (void *)arg << ")");
ret = ::ioctl(fd,code, &arg);
PTRACE(6,"IXJ\tIOCTL value = " << val);
return ret;
}
#define IOCTL(fd,code) traced_bsd_ioctl(#code, fd, code)
#define IOCTL2(fd,code,arg) traced_bsd_ioctl(#code, fd, code, (unsigned long)(arg))
#define IOCTLP(fd,code,arg) ::ioctl(fd,code,arg)
#else
static int bsd_ioctl(int fd, int code , unsigned long arg = 0)
{
int val = arg;
int ret;
ret = ::ioctl(fd,code, &val);
return ret;
}
#define IOCTL(fd,code) bsd_ioctl(fd,code,0)
#define IOCTL2(fd,code,arg) bsd_ioctl(fd,code,(unsigned long)(arg))
#define IOCTLP(fd,code,arg) ::ioctl(fd,code,arg)
#endif
#endif // P_FREEBSD
OpalIxJDevice::ExceptionInfo OpalIxJDevice::exceptionInfo[OpalIxJDevice::MaxIxjDevices];
PMutex OpalIxJDevice::exceptionMutex;
BOOL OpalIxJDevice::exceptionInit = FALSE;
/////////////////////////////////////////////////////////////////////////////
/*
struct phone_except {
unsigned int dtmf_ready:1;
unsigned int hookstate:1;
unsigned int flash:1;
unsigned int pstn_ring:1;
unsigned int caller_id:1;
unsigned int pstn_wink:1;
unsigned int f0:1;
unsigned int f1:1;
unsigned int f2:1;
unsigned int f3:1;
unsigned int fc0:1;
unsigned int fc1:1;
unsigned int fc2:1;
unsigned int fc3:1;
unsigned int reserved:18;
};
union telephony_exception {
struct phone_except bits;
unsigned int bytes;
};
*/
void OpalIxJDevice::SignalHandler(int sig)
{
// construct list of fds to check
fd_set efds;
FD_ZERO(&efds);
PINDEX i;
int maxHandle = 0;
for (i = 0; i < MaxIxjDevices; i++)
if (exceptionInfo[i].fd >= 0) {
FD_SET(exceptionInfo[i].fd, &efds);
if (exceptionInfo[i].fd > maxHandle)
maxHandle = exceptionInfo[i].fd;
}
// do not delay
struct timeval tv;
tv.tv_sec = tv.tv_usec = 0;
// get exception status
int stat = select(maxHandle+1, NULL, NULL, &efds, &tv);
// check for exceptions
if (stat > 0) {
for (i = 0; i < MaxIxjDevices; i++) {
if ((exceptionInfo[i].fd >= 0) && FD_ISSET(exceptionInfo[i].fd, &efds)) {
ExceptionInfo & info = exceptionInfo[i];
int fd = info.fd;
telephony_exception & data = info.data;
data.bytes = IOCTL(fd, PHONE_EXCEPTION);
if (data.bits.dtmf_ready) {
//printf("dtmf\n");
char ch = IOCTL(fd, PHONE_GET_DTMF_ASCII);
int p = info.dtmfIn;
info.dtmf[p] = ch;
p = (p + 1) % 16;
if (p != info.dtmfOut)
info.dtmfIn = p;
}
if (data.bits.pstn_ring)
info.hasRing = TRUE;
if (data.bits.hookstate) {
BOOL newHookState = (IOCTL(fd, PHONE_HOOKSTATE) & 1) != 0;
#ifdef MANUAL_FLASH
if (newHookState != info.hookState) {
timeval now;
gettimeofday(&now, NULL);
long diff = (now.tv_sec - info.lastHookChange.tv_sec) * 1000000;
diff += now.tv_usec - info.lastHookChange.tv_usec;
diff = (diff + 500) / 1000;
if (newHookState && (diff < FLASH_TIME))
info.hasFlash = TRUE;
info.lastHookChange = now;
}
#endif
info.hookState = newHookState;
}
#ifndef MANUAL_FLASH
if (data.bits.flash) {
info.hasFlash = TRUE;
//printf("flash detected\n");
}
#endif
if (data.bits.pstn_wink)
info.hasWink = TRUE;
if (data.bits.f0) {
//printf("Filter 0 trigger\n");
info.filter[0] = TRUE;
}
if (data.bits.f1) {
//printf("Filter 0 trigger\n");
info.filter[1] = TRUE;
}
if (data.bits.f2) {
//printf("Filter 0 trigger\n");
info.filter[2] = TRUE;
}
if (data.bits.f3) {
//printf("Filter 0 trigger\n");
info.filter[3] = TRUE;
}
#if TELEPHONY_VERSION >= 2000
if (data.bits.fc0) {
//printf("Cadence 0 trigger\n");
info.cadence[0] = TRUE;
}
if (data.bits.fc1) {
//printf("Cadence 1 trigger\n");
info.cadence[1] = TRUE;
}
if (data.bits.fc2) {
//printf("Cadence 2 trigger\n");
info.cadence[2] = TRUE;
}
if (data.bits.fc3) {
//printf("Cadence 3 trigger\n");
info.cadence[3] = TRUE;
}
#endif
#if TELEPHONY_VERSION >= 3000
if (data.bits.caller_id) {
::ioctl(fd, IXJCTL_CID, &exceptionInfo[i].cid);
info.hasCid = TRUE;
//printf("caller ID signal\n");
}
#endif
}
}
}
signal(SIGIO, &OpalIxJDevice::SignalHandler);
}
/////////////////////////////////////////////////////////////////////////////
OpalIxJDevice::OpalIxJDevice()
{
os_handle = -1;
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;
aecLevel = AECOff;
tonePlaying = FALSE;
removeDTMF = FALSE;
#if TELEPHONY_VERSION >= 3000
memset(&callerIdInfo, 0, sizeof(callerIdInfo));
#endif
}
BOOL OpalIxJDevice::Open(const PString & device)
{
Close();
// initialise the exception information, if required
{
PWaitAndSignal m(exceptionMutex);
if (!exceptionInit) {
PINDEX i;
for (i = 0; i < MaxIxjDevices; i++)
exceptionInfo[i].fd = -1;
exceptionInit = TRUE;
}
}
if (isdigit(device[0]))
deviceName = psprintf("/dev/phone%u", device.AsUnsigned());
else {
PINDEX pos = device.FindLast(' ');
if (pos == P_MAX_INDEX)
deviceName = device;
else
deviceName = device.Mid(pos+1).Trim();
}
int new_handle = os_handle = ::open(deviceName, O_RDWR);
if (!ConvertOSError(new_handle))
return FALSE;
currentHookState = lastHookState =
(IOCTL(os_handle, PHONE_HOOKSTATE) != 0);
// add the new handle to the exception info
{
PWaitAndSignal m(exceptionMutex);
PINDEX i;
for (i = 0; i < MaxIxjDevices; i++)
if (exceptionInfo[i].fd < 0)
break;
PAssert(i < MaxIxjDevices, "too many IXJ devices open");
ExceptionInfo & info = exceptionInfo[i];
memset(&info, 0, sizeof(info));
info.fd = os_handle;
info.hookState = currentHookState;
info.hasRing = FALSE;
info.hasWink = FALSE;
info.hasFlash = FALSE;
timerclear(&info.lastHookChange);
#if TELEPHONY_VERSION >= 3000
info.hasCid = FALSE;
#endif
for (i = 0; i < 4; i++) {
info.cadence[i] = FALSE;
info.filter[i] = FALSE;
}
#ifdef IXJCTL_SIGCTL
// enable all events except read/write
IXJ_SIGDEF sigdef;
sigdef.signal = SIGIO;
sigdef.event = SIG_DTMF_READY; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_HOOKSTATE; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_PSTN_RING; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_CALLER_ID; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_PSTN_WINK; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_F0; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_F1; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_F2; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_F3; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_FC0; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_FC1; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_FC2; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_FC3; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
#ifndef MANUAL_FLASH
sigdef.event = SIG_FLASH; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
#endif
sigdef.signal = 0;
sigdef.event = SIG_READ_READY; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
sigdef.event = SIG_WRITE_READY; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
#ifdef MANUAL_FLASH
sigdef.event = SIG_FLASH; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
#endif
#endif
fcntl(os_handle, F_SETOWN, getpid());
int f = fcntl(os_handle, F_GETFL);
fcntl(os_handle, F_SETFL, f | FASYNC);
signal(SIGIO, &OpalIxJDevice::SignalHandler);
}
os_handle = new_handle;
// determine if the card is a phonejack or linejack
dwCardType = IOCTL(os_handle, IXJCTL_CARDTYPE);
switch (dwCardType) {
case 3:
dwCardType = PhoneJACK_PCI_TJ;
break;
case 0x100:
case 100:
dwCardType = PhoneJACK;
break;
case 0x300:
case 300:
dwCardType = LineJACK;
break;
case 0x400:
case 400:
dwCardType = PhoneJACK_Lite;
break;
case 0x500:
case 500:
dwCardType = PhoneJACK_PCI;
break;
case 0x600:
case 600:
dwCardType = PhoneCARD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -