home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / ixjunix.cxx < prev    next >
Text File  |  2003-04-29  |  64KB  |  2,357 lines

  1. /*
  2.  * ixjunix.cxx
  3.  *
  4.  * QuickNet Internet Phone/Line JACK codec interface
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1999-2000 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions of this code were written with the assisance of funding from 
  25.  * Quicknet Technologies, Inc. http://www.quicknet.net.
  26.  * 
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: ixjunix.cxx,v $
  30.  * Revision 1.136  2003/04/29 08:31:44  robertj
  31.  * Fixed return type of get wink function.
  32.  *
  33.  * Revision 1.135  2003/04/28 01:47:52  dereks
  34.  * Add ability to set/get wink duration for ixj device.
  35.  *
  36.  * Revision 1.134  2002/11/05 04:44:20  robertj
  37.  * Fixed typo
  38.  *
  39.  * Revision 1.133  2002/11/05 04:38:07  robertj
  40.  * Changed IsLineDisconnected() to work with POTSLine
  41.  *
  42.  * Revision 1.132  2002/11/05 04:27:34  robertj
  43.  * Imported RingLine() by array from OPAL.
  44.  *
  45.  * Revision 1.131  2002/10/24 21:06:28  dereks
  46.  * Add additional PTRACE statements to aid in debugging.
  47.  *
  48.  * Revision 1.130  2002/10/01 06:43:01  robertj
  49.  * Removed GNU compiler warning
  50.  *
  51.  * Revision 1.129  2002/08/30 08:20:22  craigs
  52.  * Added G.723.1A based codecs
  53.  *
  54.  * Revision 1.128  2002/08/05 10:03:47  robertj
  55.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  56.  *
  57.  * Revision 1.127  2002/07/25 09:57:57  rogerh
  58.  * Make sure we pick the G.723.1 6.3k codec before the 5.3k codec
  59.  * if it is available.
  60.  *
  61.  * Revision 1.126  2002/07/19 10:47:16  robertj
  62.  * Fixed bug where can still receive 24 byte frames even whan selected
  63.  *   G.723.1(5.3k) mode, it only controls what is transmitted.
  64.  *
  65.  * Revision 1.125  2002/06/25 09:56:07  robertj
  66.  * Fixed GNU warnings
  67.  *
  68.  * Revision 1.124  2002/05/21 10:21:39  robertj
  69.  * Fixed FLASH_TIME being correctly set, PHONE_RING_START getting correct
  70.  *   argument, correct setting of ancestor variables when stopping codec,
  71.  *   odd packet error if playout time passed, all thanks Artis Kugevics
  72.  *
  73.  * Revision 1.123  2002/05/09 06:26:34  robertj
  74.  * Added fuction to get the current audio enable state for line in device.
  75.  * Changed IxJ EnableAudio() semantics so is exclusive, no direct switching
  76.  *   from PSTN to POTS and vice versa without disabling the old one first.
  77.  *
  78.  * Revision 1.122  2002/02/08 14:38:42  craigs
  79.  * Changed codec table to use defines from mediafmt.h. Thanks to Roger Hardiman
  80.  *
  81.  * Revision 1.121  2002/02/06 06:51:17  rogerh
  82.  * Correct a comment. There are 240 samples in PCM16 audio (not 250)
  83.  *
  84.  * Revision 1.120  2002/01/23 19:09:45  rogerh
  85.  * Return PCM as a supported format type
  86.  *
  87.  * Revision 1.119  2001/12/19 07:42:52  craigs
  88.  * Fixed problem with opening devices as returned by GetDeviceName
  89.  *
  90.  * Revision 1.118  2001/12/12 21:54:33  craigs
  91.  * Changed for changes for G723.1 5k3
  92.  *
  93.  * Revision 1.117  2001/11/22 02:55:13  robertj
  94.  * Fixed bug from previous fix, caused only /dev/phone0 to work!
  95.  *
  96.  * Revision 1.116  2001/11/09 07:48:01  craigs
  97.  * Changed to allow Open to accept string returned by GetName
  98.  *
  99.  * Revision 1.115  2001/08/08 15:55:56  rogerh
  100.  * Support the new ixj FreeBSD driver which can return values from the ioctl.
  101.  * This also fixes the capabilities problem.
  102.  *
  103.  * Revision 1.114  2001/08/08 11:00:25  rogerh
  104.  * Fix the ioctl wrappers to we can use the FreeBSD port of the IXJ driver
  105.  *
  106.  * Revision 1.113  2001/07/20 06:27:30  craigs
  107.  * Bulletproofed caller id routines
  108.  *
  109.  * Revision 1.112  2001/07/19 05:54:30  robertj
  110.  * Updated interface to xJACK drivers to utilise cadence and filter functions
  111.  *   for dial tone, busy tone and ringback tone detection.
  112.  *
  113.  * Revision 1.111  2001/07/05 16:57:31  craigs
  114.  * Fixed problem with hook state not working in spkr/mic mode
  115.  *
  116.  * Revision 1.110  2001/05/25 04:54:33  robertj
  117.  * Fixed previous fix
  118.  *
  119.  * Revision 1.109  2001/05/25 02:19:53  robertj
  120.  * Fixed problem with codec data reblocking code not being reset when
  121.  *   code is stopped and restarted, thanks Artis Kugevics
  122.  *
  123.  * Revision 1.108  2001/05/21 06:40:05  craigs
  124.  * Fixed stupid problem with missing close bracket
  125.  *
  126.  * Revision 1.107  2001/05/21 06:37:06  craigs
  127.  * Changed to allow optional wink detection for line disconnect
  128.  *
  129.  * Revision 1.106  2001/05/11 04:43:43  robertj
  130.  * Added variable names for standard PCM-16 media format name.
  131.  *
  132.  * Revision 1.105  2001/05/10 01:48:03  craigs
  133.  * Added implementation of SetLineToLine
  134.  *
  135.  * Revision 1.104  2001/04/03 23:38:38  craigs
  136.  * Added extra debugging for country change
  137.  *
  138.  * Revision 1.103  2001/03/29 23:40:09  robertj
  139.  * Added ability to get average signal level for both receive and transmit.
  140.  *
  141.  * Revision 1.102  2001/03/28 20:31:29  craigs
  142.  * Added detection of '0' prefix for old PhoneJACK cards
  143.  *
  144.  * Revision 1.101  2001/02/13 05:02:39  craigs
  145.  * Extended PlayDTMF to allow generation of additional simple tones
  146.  *
  147.  * Revision 1.100  2001/02/09 05:13:56  craigs
  148.  * Added pragma implementation to (hopefully) reduce the executable image size
  149.  * under Linux
  150.  *
  151.  * Revision 1.99  2001/02/09 01:50:22  robertj
  152.  * Fixed incorrect setting of writeCodecSize variable.
  153.  *
  154.  * Revision 1.98  2001/02/07 07:19:05  robertj
  155.  * Changed to fake a TELEPHONY_VERSION variable when there isn't one.
  156.  *
  157.  * Revision 1.97  2001/02/03 01:31:20  robertj
  158.  * Used new TELEPHONY_VERSION define for selecting API options.
  159.  *
  160.  * Revision 1.96  2001/01/28 10:32:52  rogerh
  161.  * Change an ifndef for G729B
  162.  *
  163.  * Revision 1.95  2001/01/25 07:27:16  robertj
  164.  * Major changes to add more flexible OpalMediaFormat class to normalise
  165.  *   all information about media types, especially codecs.
  166.  *
  167.  * Revision 1.94  2001/01/24 05:34:49  robertj
  168.  * Altered volume control range to be percentage, ie 100 is max volume.
  169.  *
  170.  * Revision 1.93  2000/12/21 12:39:54  craigs
  171.  * Fixed debugging
  172.  *
  173.  * Revision 1.92  2000/12/11 01:23:32  craigs
  174.  * Added extra routines to allow country string manipulation
  175.  *
  176.  * Revision 1.91  2000/12/11 01:10:41  robertj
  177.  * Removed unused filter/cadence function.
  178.  *
  179.  * Revision 1.90  2000/12/05 08:19:16  craigs
  180.  * Added internal DTMF queue to ensure DTMF digits are extracted from the
  181.  * driver as soon as possible. This minimises the number of signals
  182.  * generated
  183.  *
  184.  * Revision 1.89  2000/12/04 08:04:21  craigs
  185.  * Fixed initialisation to be more friendly
  186.  *
  187.  * Revision 1.86  2000/11/30 08:48:36  robertj
  188.  * Added functions to enable/disable Voice Activity Detection in LID's
  189.  *
  190.  * Revision 1.85  2000/11/27 10:30:01  craigs
  191.  * Added SetRawCodec function
  192.  *
  193.  * Revision 1.84  2000/11/26 23:12:18  craigs
  194.  * Added hook flash detection API
  195.  *
  196.  * Revision 1.83  2000/11/24 11:19:36  robertj
  197.  * Modified the ReadFrame/WriteFrame functions to allow for variable length codecs.
  198.  *
  199.  * Revision 1.82  2000/11/22 02:36:53  robertj
  200.  * Fixed bug in supporting older drivers.
  201.  *
  202.  * Revision 1.81  2000/11/21 00:27:50  craigs
  203.  * Fixed problem with EINTR handling on ReadFrame and WriteFrame
  204.  *
  205.  * Revision 1.80  2000/11/20 03:15:13  craigs
  206.  * Changed tone detection API slightly to allow detection of multiple
  207.  * simultaneous tones
  208.  * Added fax CNG tone to tone list
  209.  *
  210.  * Revision 1.79  2000/11/12 22:34:32  craigs
  211.  * Changed Linux driver interface code to use signals
  212.  *
  213.  * Revision 1.78  2000/11/06 01:58:26  craigs
  214.  * Changed DSP buffer depths for non-PCM functions
  215.  *
  216.  * Revision 1.77  2000/10/26 06:46:18  robertj
  217.  * Removed unnecessary stop tone ioctls() on device opening. Can't do multiple open if left in.
  218.  *
  219.  * Revision 1.76  2000/10/23 05:39:07  craigs
  220.  * Added access to exception detection on Unix
  221.  * Fixed problem with detecting available devices when
  222.  * devices with lower ordinals were used
  223.  *
  224.  * Revision 1.75  2000/10/19 06:55:11  robertj
  225.  * Added functions to get xJACK card type and serial number.
  226.  *
  227.  * Revision 1.74  2000/10/06 09:05:00  rogerh
  228.  * Check the return value of ioctl PHONE_REC_START.
  229.  *
  230.  * Revision 1.73  2000/10/06 01:20:12  robertj
  231.  * Got conditional compile round the wrong way on previous fix
  232.  *
  233.  * Revision 1.72  2000/10/04 22:39:15  craigs
  234.  * Added extra guard to FormatCallerIdString so it will work on very old drivers
  235.  *
  236.  * Revision 1.71  2000/09/29 04:41:32  craigs
  237.  * Added protected for Quicknet drivers without PHONE_WINK
  238.  *
  239.  * Revision 1.70  2000/09/26 01:28:55  craigs
  240.  * Fixed problem with VMWI ioctl interface
  241.  *
  242.  * Revision 1.69  2000/09/26 00:04:19  craigs
  243.  * Added ability to send wink on POTS ports
  244.  *
  245.  * Revision 1.68  2000/09/25 23:59:42  craigs
  246.  * Finally got G.728 working on boards which use the 8021
  247.  * Added better handling for wink exceptions
  248.  *
  249.  * Revision 1.67  2000/09/23 08:04:37  robertj
  250.  * Added support for handling LID's that only do symmetric codecs.
  251.  *
  252.  * Revision 1.66  2000/09/13 10:08:03  rogerh
  253.  * BSD handles ioctls differently to Linux so add new macros for FreeBSD
  254.  *
  255.  * Revision 1.65  2000/09/08 06:43:42  craigs
  256.  * Added additional ioctl debugging
  257.  * Added attempt to reduce ioctl count for hookstate monitoring
  258.  *
  259.  * Revision 1.64  2000/08/31 13:16:07  craigs
  260.  * Disabled IOCTL debugging when in release mode
  261.  *
  262.  * Revision 1.63  2000/08/31 13:14:40  craigs
  263.  * Added functions to LID
  264.  * More bulletproofing to Linux driver
  265.  *
  266.  * Revision 1.62  2000/08/30 23:42:01  robertj
  267.  * Renamed string version of SetCountrCode() to SetCountryCodeName() to avoid
  268.  *    C++ masking ancestor overloaded function when overriding numeric version.
  269.  *
  270.  * Revision 1.61  2000/08/28 07:13:36  craigs
  271.  * Added timeout to read codec operations
  272.  *
  273.  * Revision 1.60  2000/08/25 03:19:16  craigs
  274.  * Normalised checking of error return values from IXJ driver routines
  275.  *
  276.  * Revision 1.59  2000/08/18 04:56:20  craigs
  277.  * Added mutexes to EVERY hardware access. This fixed the G.723.1
  278.  * startup problem
  279.  *
  280.  * Revision 1.58  2000/07/03 10:33:38  craigs
  281.  * Fixed autohook option to work with PhoneCARD
  282.  *
  283.  * Revision 1.57  2000/07/02 14:13:19  craigs
  284.  * Added delay when reading from codec whilst writing stopped
  285.  *
  286.  * Revision 1.56  2000/06/22 02:46:16  craigs
  287.  * Improved ring detection
  288.  *
  289.  * Revision 1.55  2000/06/17 04:11:13  craigs
  290.  * Fixed problem with potential codec startup problem in Linux IXJ driver
  291.  * Moved Linux specific variables to Linux specific section
  292.  *
  293.  * Revision 1.54  2000/05/29 01:56:36  craigs
  294.  * Added timeout on WriteFrame to help avoid lockups
  295.  *
  296.  * Revision 1.53  2000/05/25 08:42:33  craigs
  297.  * Added detection of bugus get_rec_vol in ixj driver
  298.  *
  299.  * Revision 1.52  2000/05/24 12:44:41  craigs
  300.  * Fixed compile warnings
  301.  *
  302.  * Revision 1.51  2000/05/24 06:43:16  craigs
  303.  * Added routines to get xJack volume
  304.  * Fixed problem with receiving G>723.1 NULL frames
  305.  *
  306.  * Revision 1.50  2000/05/22 14:26:38  craigs
  307.  * Added read/write interlock to avoid codec lockup due to writing whilst read not enabled
  308.  * Added select before write to avoid EINTR under debugger
  309.  *
  310.  * Revision 1.49  2000/05/18 02:28:43  craigs
  311.  * Removed possibly dangerous checkes for uninitialised return values from
  312.  * ixj driver
  313.  *
  314.  * Revision 1.48  2000/05/02 04:32:27  robertj
  315.  * Fixed copyright notice comment.
  316.  *
  317.  * Revision 1.47  2000/04/17 07:25:08  craigs
  318.  * Fixed problems with incorrect caller ID parsing, and ensured that caller ID
  319.  * is cleared after every call
  320.  *
  321.  * Revision 1.46  2000/04/17 00:58:01  craigs
  322.  * Added support for latest Quicknet driver with caller ID transmission
  323.  *
  324.  * Revision 1.45  2000/04/13 23:08:01  craigs
  325.  * Fixed problems with callerId not compiling on all systems
  326.  *
  327.  * Revision 1.44  2000/04/10 21:23:41  robertj
  328.  * Removed "return" that disabled the dynamic changing of AEC levels.
  329.  *
  330.  * Revision 1.43  2000/04/06 19:29:04  craigs
  331.  * Removed all vestiges of the old IXJ driver
  332.  *
  333.  * Revision 1.42  2000/04/05 18:25:00  robertj
  334.  * Changed caller ID code for better portability.
  335.  *
  336.  * Revision 1.41  2000/04/05 18:15:18  craigs
  337.  * Added locks to prevent problems with codec lockup during fast start
  338.  *
  339.  * Revision 1.40  2000/04/05 16:27:16  craigs
  340.  * Added caller ID transmission, and started proper ring detection etc
  341.  *
  342.  * Revision 1.39  2000/04/05 04:09:49  robertj
  343.  * Removed PCM as valid codec type.
  344.  *
  345.  * Revision 1.38  2000/04/04 08:22:14  rogerh
  346.  * Wrap GetPayloadTypes() in #ifdef LINUX_TELEPHONY
  347.  *
  348.  * Revision 1.37  2000/04/04 01:34:03  craigs
  349.  * Added better detection of open errors
  350.  * Fixed problem with PlayTone
  351.  *
  352.  * Revision 1.36  2000/03/30 19:33:37  robertj
  353.  * Added function to get available codecs from driver.
  354.  * Fixed name strings for various card types.
  355.  *
  356.  * Revision 1.35  2000/03/28 05:24:08  craigs
  357.  * Fixed problem with country code
  358.  *
  359.  * Revision 1.34  2000/03/28 04:02:53  craigs
  360.  * Added code to stop codecs when PSTN line goes onhook
  361.  *
  362.  * Revision 1.33  2000/03/28 03:42:07  craigs
  363.  * Added extra stuff to try and make tones work properly
  364.  *
  365.  * Revision 1.32  2000/03/21 03:23:46  craigs
  366.  * Added GetLineCount function
  367.  *
  368.  * Revision 1.31  2000/03/08 00:25:52  robertj
  369.  * Fixed correct setting of country DAA codes from T35 country code.
  370.  *
  371.  * Revision 1.30  2000/02/19 23:49:33  robertj
  372.  * Fixed problem with unresolved SetRemoveDTMF function when not using linux telephony.
  373.  *
  374.  * Revision 1.29  2000/01/07 11:04:03  robertj
  375.  * New telephony API compatibility
  376.  *
  377.  * Revision 1.28  2000/01/07 10:01:03  robertj
  378.  * dditions and changes to line interface device base class.
  379.  *
  380.  * Revision 1.27  2000/01/04 00:21:55  craigs
  381.  * Fixed sense of line test
  382.  *
  383.  * Revision 1.26  1999/12/29 01:18:07  craigs
  384.  * Fixed problem with codecs other than G.711 not working after reorganisation
  385.  *
  386.  * Revision 1.25  1999/12/24 00:28:03  robertj
  387.  * Changes to IXJ interface to follow LID abstraction
  388.  *
  389.  * Revision 1.24  1999/12/19 23:48:50  craigs
  390.  * Added detection of multiple xJack cards
  391.  *
  392.  * Revision 1.23  1999/12/11 00:01:39  robertj
  393.  * Added Wink indication function.
  394.  *
  395.  * Revision 1.22  1999/12/08 21:54:05  craigs
  396.  * Removed extraneous DSP reset at the advice of Ed Okerson
  397.  *
  398.  * Revision 1.21  1999/11/29 04:50:11  robertj
  399.  * Added adaptive threshold calculation to silence detection.
  400.  *
  401.  * Revision 1.20  1999/11/19 09:29:53  robertj
  402.  * Fixed problems with aycnhronous shut down of logical channels.
  403.  *
  404.  * Revision 1.19  1999/11/18 11:45:40  robertj
  405.  * Added missing function from recent tone enhancements.
  406.  *
  407.  * Revision 1.18  1999/11/16 12:44:46  robertj
  408.  * Added more tone generation functions.
  409.  *
  410.  * Revision 1.17  1999/11/06 13:01:48  craigs
  411.  * Fixed problems with GSM emulation mode
  412.  *
  413.  * Revision 1.16  1999/11/06 05:44:08  robertj
  414.  * Fixed problem with read/write locking up when stopping codec.
  415.  *
  416.  * Revision 1.15  1999/11/06 03:45:27  robertj
  417.  * Added volume control functions.
  418.  *
  419.  * Revision 1.14  1999/11/05 10:56:25  craigs
  420.  * New implementation for new channel breakdown
  421.  *
  422.  * Revision 1.13  1999/11/02 01:22:55  robertj
  423.  * Added return values to new tone functions and added GetCallerID() function
  424.  *
  425.  * Revision 1.12  1999/11/01 23:20:49  craigs
  426.  * Added country code initialisation and DTMF tone playing
  427.  *
  428.  * Revision 1.11  1999/11/01 09:28:36  robertj
  429.  * Added flunction to enabled/disable DTM detection
  430.  *
  431.  * Revision 1.10  1999/10/30 15:10:36  craigs
  432.  * Removed checks for return status from DSP start and stop functions
  433.  *
  434.  * Revision 1.9  1999/10/30 15:03:10  robertj
  435.  * Fixed conditions under which codec start stops are not called.
  436.  *
  437.  * Revision 1.8  1999/10/30 13:29:45  robertj
  438.  * Fixed "lock up" problem, added function to get line status.
  439.  *
  440.  * Revision 1.7  1999/10/30 07:21:46  craigs
  441.  * Removed interlock between hookstate and audio path select as Quicknet has updated the driver
  442.  *
  443.  * Revision 1.6  1999/10/30 06:41:06  craigs
  444.  * Fixed problem with badly named devices using ordinals to open
  445.  *
  446.  * Revision 1.5  1999/10/29 02:28:02  robertj
  447.  * Added backward compatibility code so can use simple number for device name.
  448.  *
  449.  * Revision 1.4  1999/10/28 12:47:23  robertj
  450.  * *** empty log message ***
  451.  *
  452.  * Revision 1.3  1999/10/28 12:38:14  robertj
  453.  * Changed AEC to enum for specific values.
  454.  *
  455.  * Revision 1.2  1999/10/26 07:13:44  craigs
  456.  * Fixed problem where handset is reported off-hook when phone not selected for audio path
  457.  *
  458.  * Revision 1.1  1999/10/24 14:43:20  robertj
  459.  * Added platform independent support for Quicknet xJACK cards.
  460.  *
  461.  */
  462.  
  463. #include <ptlib.h>
  464.  
  465. #ifdef __GNUC__
  466. #pragma implementation "ixjlid.h"
  467. #endif
  468.  
  469. #include "ixjlid.h"
  470.  
  471. #include <sys/time.h>
  472.  
  473. #define new PNEW
  474.  
  475. #ifndef TELEPHONY_VERSION
  476. #if   !defined(PHONE_VAD)
  477. #warning Using extremely old telephony.h, please upgrade!
  478. #define TELEPHONY_VERSION 1000  // Version in 2.2.16 kernel
  479. #elif !defined(IXJCTL_VMWI)
  480. #warning Using very old telephony.h, please upgrade!
  481. #define TELEPHONY_VERSION 2000  // Version in 2.2.18 kernel
  482. #else
  483. #warning Using old telephony.h, please upgrade!
  484. #define TELEPHONY_VERSION 3000  // Version in CVS before addition of TELEPHONY_VERSION
  485. #endif
  486. #endif
  487.  
  488.  
  489. #define    IsLineJACK()    (dwCardType==3)
  490.  
  491. #define    FLASH_TIME    1000
  492. #define    MANUAL_FLASH        // undefine to use FLASH exception
  493.  
  494. #ifdef P_LINUX
  495.  
  496. #ifdef _DEBUG
  497.  
  498. static int traced_ioctl(const char * str, int fd, int code)
  499. {
  500.   PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ")");
  501.   int val = ::ioctl(fd,code);
  502.   PTRACE(6,"IXJ\tIOCTL value = " << val);
  503.   return val;
  504. }
  505.  
  506. static int traced_ioctl(const char * str, int fd, int code , unsigned long arg)
  507. {
  508.   PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ", " << (void *)arg << ")");
  509.   int val = ::ioctl(fd,code,arg);
  510.   PTRACE(6,"IXJ\tIOCTL value = " << val);
  511.   return val;
  512. }
  513.  
  514. #define    IOCTL(fd,code)        traced_ioctl(#code, fd, code)
  515. #define    IOCTL2(fd,code,arg)    traced_ioctl(#code, fd, code, (unsigned long)(arg))
  516. #define    IOCTLP(fd,code,arg)    ::ioctl(fd,code,arg)
  517.  
  518. #else
  519.  
  520. #define    IOCTL(fd,code)        ::ioctl(fd,code)
  521. #define    IOCTL2(fd,code,arg)    ::ioctl(fd,code,arg)
  522. #define    IOCTLP(fd,code,arg)    ::ioctl(fd,code,arg)
  523.  
  524. #endif
  525. #endif  // P_LINUX
  526.  
  527. #if TELEPHONY_VERSION < 3013
  528. #define G729B 13
  529. #endif
  530.  
  531.  
  532. #ifdef P_FREEBSD
  533. // BSD does not support return values from the ioctl() call
  534. // except via the 3rd parameter.
  535. // Also the 3rd parameter must be the 'address' of the data.
  536.  
  537. #ifdef _DEBUG
  538.  
  539. static int traced_bsd_ioctl(const char * str, int fd, int code , unsigned long arg = 0)
  540. {
  541.   int val = arg;
  542.   int ret;
  543.   PTRACE(6,"IXJ\tIOCTL(" << fd << ", " << str << ", " << (void *)arg << ")");
  544.   ret = ::ioctl(fd,code, &arg);
  545.   PTRACE(6,"IXJ\tIOCTL value = " << val);
  546.   return ret;
  547. }
  548.  
  549. #define    IOCTL(fd,code)        traced_bsd_ioctl(#code, fd, code)
  550. #define    IOCTL2(fd,code,arg)    traced_bsd_ioctl(#code, fd, code, (unsigned long)(arg))
  551. #define    IOCTLP(fd,code,arg)    ::ioctl(fd,code,arg)
  552.  
  553. #else
  554.  
  555. static int bsd_ioctl(int fd, int code , unsigned long arg = 0)
  556. {
  557.   int val = arg;
  558.   int ret;
  559.   ret = ::ioctl(fd,code, &val);
  560.   return ret;
  561. }
  562.  
  563. #define    IOCTL(fd,code)        bsd_ioctl(fd,code,0)
  564. #define    IOCTL2(fd,code,arg)    bsd_ioctl(fd,code,(unsigned long)(arg))
  565. #define    IOCTLP(fd,code,arg)    ::ioctl(fd,code,arg)
  566.  
  567. #endif
  568. #endif  // P_FREEBSD
  569.  
  570. OpalIxJDevice::ExceptionInfo OpalIxJDevice::exceptionInfo[OpalIxJDevice::MaxIxjDevices];
  571. PMutex                       OpalIxJDevice::exceptionMutex;
  572. BOOL                         OpalIxJDevice::exceptionInit = FALSE;
  573.  
  574. /////////////////////////////////////////////////////////////////////////////
  575.  
  576. /*
  577.  
  578. struct phone_except {
  579.         unsigned int dtmf_ready:1;
  580.         unsigned int hookstate:1;
  581.         unsigned int flash:1;
  582.         unsigned int pstn_ring:1;
  583.         unsigned int caller_id:1;
  584.         unsigned int pstn_wink:1;
  585.         unsigned int f0:1;
  586.         unsigned int f1:1;
  587.         unsigned int f2:1;
  588.         unsigned int f3:1;
  589.         unsigned int fc0:1;
  590.         unsigned int fc1:1;
  591.         unsigned int fc2:1;
  592.         unsigned int fc3:1;
  593.         unsigned int reserved:18;
  594. };
  595.  
  596. union telephony_exception {
  597.         struct phone_except bits;
  598.         unsigned int bytes;
  599. };
  600.  
  601. */
  602.  
  603. void OpalIxJDevice::SignalHandler(int sig)
  604. {
  605.   // construct list of fds to check
  606.   fd_set  efds;
  607.   FD_ZERO(&efds);
  608.   PINDEX i;
  609.   int maxHandle = 0;
  610.   for (i = 0; i < MaxIxjDevices; i++) 
  611.     if (exceptionInfo[i].fd >= 0) {
  612.       FD_SET(exceptionInfo[i].fd, &efds);
  613.       if (exceptionInfo[i].fd > maxHandle)
  614.         maxHandle = exceptionInfo[i].fd;
  615.     }
  616.  
  617.   // do not delay
  618.   struct timeval  tv;
  619.   tv.tv_sec = tv.tv_usec = 0;
  620.  
  621.   // get exception status
  622.   int stat = select(maxHandle+1, NULL, NULL, &efds, &tv);
  623.  
  624.   // check for exceptions
  625.   if (stat > 0) {
  626.     for (i = 0; i < MaxIxjDevices; i++) {
  627.       if ((exceptionInfo[i].fd >= 0) && FD_ISSET(exceptionInfo[i].fd, &efds)) {
  628.  
  629.         ExceptionInfo & info = exceptionInfo[i];
  630.         int fd                     = info.fd;
  631.         telephony_exception & data = info.data;
  632.         data.bytes = IOCTL(fd, PHONE_EXCEPTION);
  633.  
  634.         if (data.bits.dtmf_ready) {
  635.           //printf("dtmf\n");
  636.           char ch = IOCTL(fd, PHONE_GET_DTMF_ASCII);
  637.           int p = info.dtmfIn;
  638.           info.dtmf[p] = ch;
  639.           p = (p + 1) % 16;
  640.           if (p != info.dtmfOut)
  641.             info.dtmfIn = p;
  642.         }
  643.  
  644.         if (data.bits.pstn_ring) 
  645.           info.hasRing = TRUE;
  646.  
  647.         if (data.bits.hookstate) {
  648.           BOOL newHookState = (IOCTL(fd, PHONE_HOOKSTATE) & 1) != 0;
  649. #ifdef MANUAL_FLASH
  650.           if (newHookState != info.hookState) {
  651.             timeval now;
  652.             gettimeofday(&now, NULL);
  653.             long diff = (now.tv_sec - info.lastHookChange.tv_sec) * 1000000;
  654.             diff += now.tv_usec - info.lastHookChange.tv_usec;
  655.             diff = (diff + 500) / 1000;
  656.             if (newHookState && (diff < FLASH_TIME))
  657.               info.hasFlash = TRUE;
  658.             info.lastHookChange = now;
  659.           }
  660. #endif
  661.           info.hookState = newHookState;
  662.         }
  663.  
  664. #ifndef MANUAL_FLASH
  665.         if (data.bits.flash) {
  666.           info.hasFlash = TRUE;
  667.           //printf("flash detected\n");
  668.         }
  669. #endif
  670.  
  671.         if (data.bits.pstn_wink)
  672.           info.hasWink = TRUE;
  673.  
  674.         if (data.bits.f0) {
  675.           //printf("Filter 0 trigger\n");
  676.           info.filter[0] = TRUE;
  677.         }
  678.         if (data.bits.f1) {
  679.           //printf("Filter 0 trigger\n");
  680.           info.filter[1] = TRUE;
  681.         }
  682.         if (data.bits.f2) {
  683.           //printf("Filter 0 trigger\n");
  684.           info.filter[2] = TRUE;
  685.         }
  686.         if (data.bits.f3) {
  687.           //printf("Filter 0 trigger\n");
  688.           info.filter[3] = TRUE;
  689.         }
  690.  
  691. #if TELEPHONY_VERSION >= 2000
  692.         if (data.bits.fc0) {
  693.           //printf("Cadence 0 trigger\n");
  694.           info.cadence[0] = TRUE;
  695.         }
  696.         if (data.bits.fc1) {
  697.           //printf("Cadence 1 trigger\n");
  698.           info.cadence[1] = TRUE;
  699.         }
  700.         if (data.bits.fc2) {
  701.           //printf("Cadence 2 trigger\n");
  702.           info.cadence[2] = TRUE;
  703.         }
  704.         if (data.bits.fc3) {
  705.           //printf("Cadence 3 trigger\n");
  706.           info.cadence[3] = TRUE;
  707.         }
  708. #endif
  709.  
  710. #if TELEPHONY_VERSION >= 3000
  711.         if (data.bits.caller_id) {
  712.           ::ioctl(fd, IXJCTL_CID, &exceptionInfo[i].cid);
  713.           info.hasCid = TRUE;
  714.           //printf("caller ID signal\n");
  715.         }
  716. #endif
  717.       }
  718.     }
  719.   }
  720.  
  721.   signal(SIGIO, &OpalIxJDevice::SignalHandler);
  722. }
  723.  
  724. /////////////////////////////////////////////////////////////////////////////
  725.  
  726. OpalIxJDevice::OpalIxJDevice()
  727. {
  728.   os_handle = -1;
  729.   readStopped = writeStopped = TRUE;
  730.   readFrameSize = writeFrameSize = 480;  // 30 milliseconds of 16 bit PCM data
  731.   readCodecType = writeCodecType = P_MAX_INDEX;
  732.   currentHookState = lastHookState = FALSE;
  733.   inRawMode = FALSE;
  734.   enabledAudioLine = UINT_MAX;
  735.   exclusiveAudioMode = TRUE;
  736.   aecLevel = AECOff;
  737.   tonePlaying = FALSE;
  738.   removeDTMF = FALSE;
  739. #if TELEPHONY_VERSION >= 3000
  740.   memset(&callerIdInfo, 0, sizeof(callerIdInfo));
  741. #endif
  742. }
  743.  
  744.  
  745. BOOL OpalIxJDevice::Open(const PString & device)
  746. {
  747.   Close();
  748.  
  749.   // initialise the exception information, if required
  750.   {
  751.     PWaitAndSignal m(exceptionMutex);
  752.     if (!exceptionInit) {
  753.       PINDEX i;
  754.       for (i = 0; i < MaxIxjDevices; i++)
  755.         exceptionInfo[i].fd = -1;
  756.       exceptionInit = TRUE;
  757.     }
  758.   }
  759.  
  760.   if (isdigit(device[0])) 
  761.     deviceName = psprintf("/dev/phone%u", device.AsUnsigned());
  762.   else {
  763.     PINDEX pos = device.FindLast(' ');
  764.     if (pos == P_MAX_INDEX)
  765.       deviceName = device;
  766.     else
  767.       deviceName = device.Mid(pos+1).Trim();
  768.   }
  769.  
  770.   int new_handle = os_handle = ::open(deviceName, O_RDWR);
  771.   if (!ConvertOSError(new_handle))
  772.     return FALSE;
  773.  
  774.   // add the new handle to the exception info
  775.   {
  776.     PWaitAndSignal m(exceptionMutex);
  777.     PINDEX i;
  778.     for (i = 0; i < MaxIxjDevices; i++) 
  779.       if (exceptionInfo[i].fd < 0) 
  780.         break;
  781.     PAssert(i < MaxIxjDevices, "too many IXJ devices open");
  782.  
  783.     ExceptionInfo & info = exceptionInfo[i];
  784.     memset(&info, 0, sizeof(info));
  785.  
  786.     info.fd  = os_handle;
  787.     info.hookState  = FALSE;
  788.     info.hasRing    = FALSE;
  789.     info.hasWink    = FALSE;
  790.     info.hasFlash   = FALSE;
  791.     timerclear(&info.lastHookChange);
  792.  
  793. #if TELEPHONY_VERSION >= 3000
  794.     info.hasCid     = FALSE;
  795. #endif
  796.     for (i = 0; i < 4; i++) {
  797.       info.cadence[i] = FALSE;
  798.       info.filter[i]  = FALSE;
  799.     }
  800.  
  801. #ifdef IXJCTL_SIGCTL
  802.     // enable all events except read/write
  803.     IXJ_SIGDEF sigdef;
  804.  
  805.     sigdef.signal = SIGIO;
  806.     sigdef.event = SIG_DTMF_READY; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  807.     sigdef.event = SIG_HOOKSTATE;  IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  808.     sigdef.event = SIG_PSTN_RING;  IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  809.     sigdef.event = SIG_CALLER_ID;  IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  810.     sigdef.event = SIG_PSTN_WINK;  IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  811.     sigdef.event = SIG_F0;         IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  812.     sigdef.event = SIG_F1;         IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  813.     sigdef.event = SIG_F2;         IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  814.     sigdef.event = SIG_F3;         IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  815.     sigdef.event = SIG_FC0;        IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  816.     sigdef.event = SIG_FC1;        IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  817.     sigdef.event = SIG_FC2;        IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  818.     sigdef.event = SIG_FC3;        IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  819. #ifndef MANUAL_FLASH
  820.     sigdef.event = SIG_FLASH;       IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  821. #endif
  822.  
  823.     sigdef.signal = 0;
  824.     sigdef.event  = SIG_READ_READY;  IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  825.     sigdef.event  = SIG_WRITE_READY; IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  826. #ifdef MANUAL_FLASH
  827.     sigdef.event = SIG_FLASH;       IOCTLP(os_handle, IXJCTL_SIGCTL, &sigdef);
  828. #endif
  829. #endif
  830.  
  831.     fcntl(os_handle, F_SETOWN, getpid());
  832.     int f = fcntl(os_handle, F_GETFL);
  833.     fcntl(os_handle, F_SETFL, f | FASYNC);
  834.     signal(SIGIO, &OpalIxJDevice::SignalHandler);
  835.   }
  836.  
  837.   os_handle = new_handle;
  838.  
  839.   // determine if the card is a phonejack or linejack
  840.   dwCardType = IOCTL(os_handle, IXJCTL_CARDTYPE)/100;
  841.  
  842.   char * str = ::getenv("IXJ_COUNTRY");
  843.   if (str != NULL) {
  844.     if (isdigit(*str))
  845.       SetCountryCode((T35CountryCodes)atoi(str));
  846.     else
  847.       SetCountryCodeName(PString(str));
  848.   }
  849.  
  850.   // make sure the PSTN line is on-hook
  851.   pstnIsOffHook = FALSE;
  852.   gotWink       = FALSE;
  853.   IOCTL2(os_handle, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK);
  854.  
  855.   lastHookState = FALSE;
  856.  
  857.   inRawMode     = FALSE;
  858.  
  859.   SetAEC         (0, AECOff);
  860.   SetRecordVolume(0, 100);
  861.   SetPlayVolume  (0, 100);
  862.  
  863.   return TRUE;
  864. }
  865.  
  866. BOOL OpalIxJDevice::Close()
  867. {
  868.   if (!IsOpen())
  869.     return FALSE;
  870.  
  871.   StopReadCodec(0);
  872.   StopWriteCodec(0);
  873.   RingLine(0, 0);
  874.   SetLineToLineDirect(0, 1, TRUE);
  875.   deviceName = PString();
  876.  
  877.   // close the device
  878.   int stat = ::close(os_handle);
  879.  
  880.   // remove the device from the exception information
  881.   {
  882.     PWaitAndSignal m(exceptionMutex);
  883.     ExceptionInfo * info = GetException();
  884.     info->fd = -1;
  885.   }
  886.  
  887.   os_handle = -1;
  888.  
  889.   return ConvertOSError(stat);
  890. }
  891.  
  892.  
  893. PString OpalIxJDevice::GetName() const
  894. {
  895.   switch (dwCardType) {
  896.     case 0:
  897.     case 1:
  898.       return "Internet PhoneJACK-ISA " + deviceName;
  899.  
  900.     case 3:
  901.       return "Internet LineJACK " + deviceName;
  902.  
  903.     case 4:
  904.       return "Internet PhoneJACK-Lite " + deviceName;
  905.  
  906.     case 5:
  907.       return "Internet PhoneJACK-PCI " + deviceName;
  908.  
  909.     case 6:
  910.       return "Internet PhoneCARD " + deviceName;
  911.   }
  912.  
  913.   return "xJACK " + deviceName;
  914. }
  915.  
  916. unsigned OpalIxJDevice::GetLineCount()
  917. {
  918.   return IsLineJACK() ? NumLines : 1;
  919. }
  920.  
  921. BOOL OpalIxJDevice::IsLinePresent(unsigned line, BOOL /* force */)
  922. {
  923.   if (line != PSTNLine)
  924.     return FALSE;
  925.  
  926.   BOOL stat = IOCTL(os_handle, IXJCTL_PSTN_LINETEST) == 1;
  927.   PThread::Current()->Sleep(2000);
  928.  
  929.   // clear ring signal status
  930.   IsLineRinging(line);
  931.  
  932.   return stat;
  933. }
  934.  
  935.  
  936. BOOL OpalIxJDevice::IsLineOffHook(unsigned line)
  937. {
  938.   if (line == PSTNLine) 
  939.     return pstnIsOffHook;
  940.   
  941.   PWaitAndSignal m(exceptionMutex);
  942.   ExceptionInfo * info = GetException();
  943.  
  944. #ifdef MANUAL_FLASH
  945.   if (info->hookState != lastHookState) {
  946.     lastHookState = info->hookState;
  947.     if (lastHookState) {
  948.     currentHookState = lastHookState;
  949.     } else {
  950.     hookTimeout = FLASH_TIME;
  951.     }
  952.   } else if (!hookTimeout.IsRunning() && (currentHookState != info->hookState)) 
  953.     currentHookState = info->hookState;
  954.  
  955.   return currentHookState;
  956. #else
  957.   return info->hookState;
  958. #endif
  959. }
  960.  
  961. BOOL OpalIxJDevice::HasHookFlash(unsigned line)
  962.   if (line != POTSLine)
  963.     return FALSE;
  964.   
  965.   PWaitAndSignal m(exceptionMutex);
  966.   ExceptionInfo * info = GetException();
  967.   
  968.   BOOL flash = info->hasFlash;
  969.   info->hasFlash = FALSE;
  970.   return flash;
  971. }
  972.  
  973.  
  974. BOOL OpalIxJDevice::SetLineOffHook(unsigned line, BOOL newState)
  975. {
  976.   if (line == POTSLine) {
  977. #ifdef PHONE_WINK
  978.     IOCTL(os_handle, PHONE_WINK);
  979.     return TRUE;
  980. #else
  981.     return FALSE;
  982. #endif
  983.   }
  984.  
  985.   pstnIsOffHook = newState;
  986.  
  987.   if (!pstnIsOffHook) {
  988.     StopReadCodec(line);
  989.     StopWriteCodec(line);
  990.   }
  991.  
  992.   // reset wink detected state going on or off hook 
  993.   gotWink = FALSE;
  994.  
  995.   IOCTL2(os_handle, PHONE_PSTN_SET_STATE, pstnIsOffHook ? PSTN_OFF_HOOK : PSTN_ON_HOOK);
  996.  
  997.   return TRUE;
  998. }
  999.  
  1000. OpalIxJDevice::ExceptionInfo * OpalIxJDevice::GetException()
  1001. {
  1002.   PINDEX i;
  1003.   for (i = 0; i < MaxIxjDevices; i++) 
  1004.     if (exceptionInfo[i].fd == os_handle) 
  1005.       return &exceptionInfo[i];
  1006.  
  1007.   PAssertAlways("Cannot find open device in exception list");
  1008.   return NULL;
  1009. }
  1010.  
  1011.  
  1012. BOOL OpalIxJDevice::IsLineRinging(unsigned line, DWORD * /*cadence*/)
  1013. {
  1014.   if (line != PSTNLine)
  1015.     return FALSE;
  1016.  
  1017.   PWaitAndSignal m(exceptionMutex);
  1018.   ExceptionInfo * info = GetException();
  1019.  
  1020.   BOOL ring = info->hasRing;
  1021.   info->hasRing = FALSE;
  1022.   return ring;
  1023. }
  1024.  
  1025.  
  1026. BOOL OpalIxJDevice::RingLine(unsigned line, DWORD cadence)
  1027. {
  1028.   if (line != POTSLine)
  1029.     return FALSE;
  1030.  
  1031.   if (cadence == 0)
  1032.     return ConvertOSError(IOCTL(os_handle, PHONE_RING_STOP));
  1033.  
  1034.   //if (!ConvertOSError(IOCTL2(os_handle, PHONE_RING_CADENCE, cadence)))
  1035.   //  return FALSE;
  1036.  
  1037.   int stat;
  1038.  
  1039.   // Need to add something to set caller ID here
  1040. #if TELEPHONY_VERSION >= 3000
  1041.   if (callerIdInfo.name[0] != '\0') {
  1042.     stat = IOCTLP(os_handle, PHONE_RING_START, &callerIdInfo);
  1043.     SetCallerID(line, "");
  1044.   } else
  1045. #endif
  1046.     stat = IOCTL2(os_handle, PHONE_RING_START, 0);
  1047.  
  1048.   return ConvertOSError(stat);
  1049. }
  1050.  
  1051.  
  1052. BOOL OpalIxJDevice::RingLine(unsigned line, PINDEX nCadence, unsigned * pattern)
  1053. {
  1054.   if (line >= GetLineCount())
  1055.     return FALSE;
  1056.  
  1057.   if (line != POTSLine)
  1058.     return FALSE;
  1059.  
  1060.   return RingLine(line, nCadence != 0 ? 0xaaa : 0);
  1061. }
  1062.  
  1063.  
  1064. BOOL OpalIxJDevice::IsLineDisconnected(unsigned line, BOOL checkForWink)
  1065. {
  1066.   if (line >= GetLineCount())
  1067.     return FALSE;
  1068.  
  1069.   if (line != PSTNLine)
  1070.     return !IsLineOffHook(line);
  1071.  
  1072.   if (checkForWink) {
  1073.  
  1074.     // if we got a wink previously, hangup
  1075.     if (gotWink)
  1076.       return TRUE;
  1077.  
  1078.     // if we have not got a wink, then check for one
  1079.     PWaitAndSignal m(exceptionMutex);
  1080.     ExceptionInfo * info = GetException();
  1081.  
  1082.     gotWink = info->hasWink;
  1083.     info->hasWink = FALSE;
  1084.     if (gotWink) {
  1085.       PTRACE(3, "xJack\tDetected wink");
  1086.       return TRUE;
  1087.     }
  1088.   }
  1089.  
  1090.  
  1091.   if (IsToneDetected(line) & (BusyTone)) {
  1092.     PTRACE(3, "xJack\tDetected end of call tone");
  1093.     return TRUE;
  1094.   }
  1095.  
  1096.   return FALSE;
  1097. }
  1098.  
  1099. BOOL OpalIxJDevice::SetLineToLineDirect(unsigned line1, unsigned line2, BOOL connect)
  1100. {
  1101.   if (connect && (line1 != line2)) 
  1102.     IOCTL2(os_handle, IXJCTL_POTS_PSTN, 1);
  1103.   else 
  1104.     IOCTL2(os_handle, IXJCTL_POTS_PSTN, 0);
  1105.  
  1106.   return TRUE;
  1107. }
  1108.  
  1109.  
  1110. BOOL OpalIxJDevice::IsLineToLineDirect(unsigned line1, unsigned line2)
  1111. {
  1112.   return FALSE;
  1113. }
  1114.  
  1115. BOOL OpalIxJDevice::ConvertOSError(int err) 
  1116. {
  1117.   PChannel::Errors normalisedError;
  1118.   return PChannel::ConvertOSError(err, normalisedError, osError);
  1119. }
  1120.  
  1121.  
  1122. static const struct {
  1123.   const char * mediaFormat;
  1124.   PINDEX writeFrameSize;
  1125.   PINDEX readFrameSize;
  1126.   int mode;
  1127.   int frameTime;
  1128.   BOOL vad;
  1129. } CodecInfo[] = {
  1130.   /* NOTE: These are enumerated in reverse order. */
  1131.   { OPAL_PCM16,         480, 480, LINEAR16, 30, FALSE },   // 480 bytes = 240 samples = 30ms
  1132.   { OPAL_G711_ULAW_64K, 240, 240, ULAW,     30, FALSE },   // 240 bytes = 240 samples = 30ms
  1133.   { OPAL_G711_ALAW_64K, 240, 240, ALAW,     30, FALSE },   // 240 bytes = 240 samples = 30ms
  1134.   { OPAL_G728,           60,  60, G728,     30, FALSE },   // 60 bytes  = 12 frames   = 30ms
  1135.   { OPAL_G729A,          10,  10, G729,     10, FALSE },   // 10 bytes = 1 frame = 10 ms
  1136.   { OPAL_G729AB,         10,  10, G729B,    10,  TRUE },   // 10 bytes = 1 frame = 10 ms
  1137.   { OPAL_G7231_5k3 ,     24,  20, G723_53,  30, FALSE },   // 20 bytes = 1 frame = 30 ms
  1138.   { OPAL_G7231_6k3,      24,  24, G723_63,  30, FALSE },   // 24 bytes = 1 frame = 30 ms
  1139.   { OPAL_G7231A_5k3 ,    24,  20, G723_53,  30,  TRUE },   // 20 bytes = 1 frame = 30 ms
  1140.   { OPAL_G7231A_6k3,     24,  24, G723_63,  30,  TRUE }    // 24 bytes = 1 frame = 30 ms
  1141. };
  1142.  
  1143.  
  1144.  
  1145. OpalMediaFormat::List OpalIxJDevice::GetMediaFormats() const
  1146. {
  1147.   OpalMediaFormat::List codecs;
  1148.  
  1149.   PINDEX idx = PARRAYSIZE(CodecInfo);
  1150.   while (idx-- > 0) {
  1151.     phone_capability cap;
  1152.     cap.captype = codec;
  1153.     cap.cap = CodecInfo[idx].mode;
  1154.     if (IOCTLP(os_handle, PHONE_CAPABILITIES_CHECK, &cap))
  1155.       codecs.Append(new OpalMediaFormat(CodecInfo[idx].mediaFormat));
  1156.   }
  1157.  
  1158.   return codecs;
  1159. }
  1160.  
  1161.  
  1162. static PINDEX FindCodec(const OpalMediaFormat & mediaFormat)
  1163. {
  1164.   for (PINDEX codecType = 0; codecType < PARRAYSIZE(CodecInfo); codecType++) {
  1165.     if (mediaFormat == CodecInfo[codecType].mediaFormat)
  1166.       return codecType;
  1167.   }
  1168.  
  1169.   return P_MAX_INDEX;
  1170. }
  1171.  
  1172.  
  1173. BOOL OpalIxJDevice::SetReadFormat(unsigned line, const OpalMediaFormat & mediaFormat)
  1174. {
  1175.   {
  1176.     PWaitAndSignal mutex(toneMutex);
  1177.     if (tonePlaying) {
  1178.       tonePlaying = FALSE;
  1179.       IOCTL(os_handle, PHONE_CPT_STOP);
  1180.     }
  1181.   }
  1182.  
  1183.   PWaitAndSignal mutex(readMutex);
  1184.  
  1185.   if (!readStopped) {
  1186.     IOCTL(os_handle, PHONE_REC_STOP);
  1187.     readStopped = TRUE;
  1188.     OpalLineInterfaceDevice::StopReadCodec(line);
  1189.   }
  1190.  
  1191.   readCodecType = FindCodec(mediaFormat);
  1192.   if (readCodecType == P_MAX_INDEX) {
  1193.     PTRACE(1, "xJack\tUnsupported read codec requested: " << mediaFormat);
  1194.     return FALSE;
  1195.   }
  1196.  
  1197.   if (!writeStopped && readCodecType != writeCodecType) {
  1198.     PTRACE(1, "xJack\tAsymmectric codecs requested: "
  1199.               "read=" << CodecInfo[readCodecType].mediaFormat <<
  1200.               " write=" << CodecInfo[writeCodecType].mediaFormat);
  1201.     return FALSE;
  1202.   }
  1203.  
  1204.   PTRACE(2, "IXJ\tSetting read codec to "
  1205.          << CodecInfo[readCodecType].mediaFormat
  1206.          << " code=" << CodecInfo[readCodecType].mode);
  1207.  
  1208.   readFrameSize = CodecInfo[readCodecType].readFrameSize;
  1209.  
  1210.   // set frame time
  1211.   if (writeStopped)
  1212.     IOCTL2(os_handle, PHONE_FRAME, CodecInfo[readCodecType].frameTime);
  1213.  
  1214.   int stat = IOCTL2(os_handle, PHONE_REC_CODEC, CodecInfo[readCodecType].mode);
  1215.   if (stat != 0) {
  1216.     PTRACE(1, "IXJ\tSecond try on set record codec");
  1217.     stat = IOCTL2(os_handle, PHONE_REC_CODEC, CodecInfo[readCodecType].mode);
  1218.     if (stat != 0) {
  1219.       PTRACE(1, "IXJ\tFailed second try on set record codec");
  1220.       return FALSE;
  1221.     }
  1222.   }
  1223.  
  1224.   // PHONE_REC_DEPTH does not set return value
  1225.   IOCTL2(os_handle, PHONE_REC_DEPTH, 1);
  1226.  
  1227.   // PHONE_REC_START does not set return value
  1228.   stat = IOCTL(os_handle, PHONE_REC_START);
  1229.   if (stat != 0) {
  1230.     return FALSE;
  1231.   }
  1232.  
  1233.   readStopped = FALSE;
  1234.  
  1235.   return TRUE;
  1236. }
  1237.  
  1238. BOOL OpalIxJDevice::SetWriteFormat(unsigned line, const OpalMediaFormat & mediaFormat)
  1239. {
  1240.   {
  1241.     PWaitAndSignal mutex(toneMutex);
  1242.     if (tonePlaying) {
  1243.       tonePlaying = FALSE;
  1244.       IOCTL(os_handle, PHONE_CPT_STOP);
  1245.     }
  1246.   }
  1247.  
  1248.   PWaitAndSignal mutex(readMutex);
  1249.  
  1250.   if (!writeStopped) {
  1251.     IOCTL(os_handle, PHONE_PLAY_STOP);
  1252.     writeStopped = TRUE;
  1253.     OpalLineInterfaceDevice::StopWriteCodec(line);
  1254.   }
  1255.  
  1256.  
  1257.   writeCodecType = FindCodec(mediaFormat);
  1258.   if (writeCodecType == P_MAX_INDEX) {
  1259.     PTRACE(1, "xJack\tUnsupported write codec requested: " << mediaFormat);
  1260.     return FALSE;
  1261.   }
  1262.  
  1263.   if (!readStopped && writeCodecType != readCodecType) {
  1264.     PTRACE(1, "xJack\tAsymmectric codecs requested: "
  1265.               "read=" << CodecInfo[readCodecType].mediaFormat <<
  1266.               " write=" << CodecInfo[writeCodecType].mediaFormat);
  1267.     return FALSE;
  1268.   }
  1269.  
  1270.   PTRACE(2, "IXJ\tSetting write codec to "
  1271.          << CodecInfo[writeCodecType].mediaFormat
  1272.          << " code=" << CodecInfo[writeCodecType].mode);
  1273.  
  1274.   writeFrameSize = CodecInfo[writeCodecType].writeFrameSize;
  1275.  
  1276.   // set frame time
  1277.   if (readStopped)
  1278.     IOCTL2(os_handle, PHONE_FRAME, CodecInfo[writeCodecType].frameTime);
  1279.  
  1280.   int stat = IOCTL2(os_handle, PHONE_PLAY_CODEC, CodecInfo[writeCodecType].mode);
  1281.   if (stat != 0) {
  1282.     PTRACE(1, "IXJ\tSecond try on set play codec");
  1283.     stat = IOCTL2(os_handle, PHONE_PLAY_CODEC, CodecInfo[writeCodecType].mode);
  1284.     if (stat != 0)
  1285.       return FALSE;
  1286.   }
  1287.  
  1288.   // PHONE_PLAY_DEPTH does not set return value
  1289.   IOCTL2(os_handle, PHONE_PLAY_DEPTH, 1);
  1290.  
  1291.   // start the codec
  1292.   stat = IOCTL(os_handle, PHONE_PLAY_START);
  1293.   if (stat != 0) {
  1294.     PTRACE(1, "IXJ\tSecond try on start play codec");
  1295.     stat = IOCTL(os_handle, PHONE_PLAY_START);
  1296.     if (stat != 0)
  1297.       return FALSE;
  1298.   }
  1299.  
  1300.   // wait for codec to become writable. If it doesn't happen after 100ms, give error
  1301.   fd_set wfds;
  1302.   struct timeval ts;
  1303.  
  1304.   for (;;) {
  1305.  
  1306.     FD_ZERO(&wfds);
  1307.     FD_SET(os_handle, &wfds);
  1308.     ts.tv_sec = 0;
  1309.     ts.tv_usec = 100*1000;
  1310.  
  1311.     stat = ::select(os_handle+1, NULL, &wfds, NULL, &ts);
  1312.  
  1313.     if (stat > 0)
  1314.       break;
  1315.     else if (stat == 0) {
  1316.       PTRACE(1, "IXJ\tWrite timeout on startup");
  1317.       return FALSE;
  1318.     } 
  1319.  
  1320.     if (errno != EINTR) {
  1321.       PTRACE(1, "IXJ\tWrite error on startup");
  1322.       return FALSE;
  1323.     }
  1324.   }
  1325.  
  1326.   writeStopped = FALSE;
  1327.  
  1328.   return TRUE;
  1329. }
  1330.  
  1331.  
  1332. OpalMediaFormat OpalIxJDevice::GetReadFormat(unsigned)
  1333. {
  1334.   if (readCodecType == P_MAX_INDEX)
  1335.     return "";
  1336.   return CodecInfo[readCodecType].mediaFormat;
  1337. }
  1338.  
  1339.  
  1340. OpalMediaFormat OpalIxJDevice::GetWriteFormat(unsigned)
  1341. {
  1342.   if (writeCodecType == P_MAX_INDEX)
  1343.     return "";
  1344.   return CodecInfo[writeCodecType].mediaFormat;
  1345. }
  1346.  
  1347.  
  1348. BOOL OpalIxJDevice::SetRawCodec(unsigned line)
  1349. {
  1350.   if (inRawMode)
  1351.     return FALSE;
  1352.  
  1353.   PTRACE(2, "IXJ\tSetting raw codec mode");
  1354.  
  1355.   // save the current volumes
  1356.   savedPlayVol    = userPlayVol;
  1357.   savedRecVol     = userRecVol;
  1358.   savedAEC        = aecLevel;
  1359.  
  1360.   if (!SetReadFormat (line, CodecInfo[0].mediaFormat) ||
  1361.       !SetWriteFormat(line, CodecInfo[0].mediaFormat)) {
  1362.     PTRACE(1, "IXJ\t Failed to set raw codec");
  1363.     StopReadCodec(line);
  1364.     StopWriteCodec(line);
  1365.     return FALSE;
  1366.   }
  1367.  
  1368.   // set the new (maximum) volumes
  1369.   SetAEC         (line, AECOff);
  1370.   SetRecordVolume(line, 0x100);
  1371.   SetPlayVolume  (line, 0x100);
  1372.  
  1373.   // stop values from changing
  1374.   inRawMode = TRUE;
  1375.  
  1376.   return TRUE;
  1377. }
  1378.  
  1379.  
  1380. BOOL OpalIxJDevice::StopReadCodec(unsigned line)
  1381. {
  1382.   PTRACE(3, "xJack\tStopping read codec");
  1383.  
  1384.   PWaitAndSignal mutex(readMutex);
  1385.  
  1386.   if (!readStopped) {
  1387.     IOCTL(os_handle, PHONE_REC_STOP);
  1388.     readStopped = TRUE;
  1389.   }
  1390.  
  1391.   return OpalLineInterfaceDevice::StopReadCodec(line);
  1392. }
  1393.  
  1394.  
  1395. BOOL OpalIxJDevice::StopWriteCodec(unsigned line)
  1396. {
  1397.   PTRACE(3, "xJack\tStopping write codec");
  1398.  
  1399.   PWaitAndSignal mutex(readMutex);
  1400.  
  1401.   if (!writeStopped) {
  1402.     IOCTL(os_handle, PHONE_PLAY_STOP);
  1403.     writeStopped = TRUE;
  1404.   }
  1405.  
  1406.   return OpalLineInterfaceDevice::StopWriteCodec(line);
  1407. }
  1408.  
  1409.  
  1410. BOOL OpalIxJDevice::StopRawCodec(unsigned line)
  1411. {
  1412.   if (!inRawMode)
  1413.     return FALSE;
  1414.  
  1415.   StopReadCodec(line);
  1416.   StopWriteCodec(line);
  1417.  
  1418.   // allow values to change again
  1419.   inRawMode = FALSE;
  1420.  
  1421.   SetPlayVolume  (line, savedPlayVol);
  1422.   SetRecordVolume(line, savedRecVol);
  1423.   SetAEC         (line, savedAEC);
  1424.  
  1425.   OpalLineInterfaceDevice::StopReadCodec(line);
  1426.   OpalLineInterfaceDevice::StopWriteCodec(line);
  1427.   return TRUE;
  1428. }
  1429.  
  1430.  
  1431. PINDEX OpalIxJDevice::GetReadFrameSize(unsigned)
  1432. {
  1433.   return readFrameSize;
  1434. }
  1435.  
  1436. BOOL OpalIxJDevice::SetReadFrameSize(unsigned, PINDEX)
  1437. {
  1438.   return FALSE;
  1439. }
  1440.  
  1441. static void G728_Pack(const unsigned short * unpacked, BYTE * packed)
  1442. {
  1443.   packed[0] =                                ((unpacked[0] & 0x3fc) >> 2);
  1444.   packed[1] = ((unpacked[0] & 0x003) << 6) | ((unpacked[1] & 0x3f0) >> 4);
  1445.   packed[2] = ((unpacked[1] & 0x00f) << 4) | ((unpacked[2] & 0x3c0) >> 6);
  1446.   packed[3] = ((unpacked[2] & 0x03f) << 2) | ((unpacked[3] & 0x300) >> 8);
  1447.   packed[4] =  (unpacked[3] & 0x0ff);
  1448. }
  1449.  
  1450. static const PINDEX G723count[4] = { 24, 20, 4, 1 };
  1451.  
  1452.  
  1453. BOOL OpalIxJDevice::ReadFrame(unsigned, void * buffer, PINDEX & count)
  1454. {
  1455.   PWaitAndSignal rmutex(readMutex);
  1456.  
  1457.   count = 0;
  1458.  
  1459.   if (readStopped) {
  1460.       PTRACE(1, "IXJ\tRead stopped, so ReadFrame returns false");    
  1461.       return FALSE;
  1462.   }
  1463.  
  1464.   if (writeStopped) {
  1465.     PThread::Current()->Sleep(30);
  1466.     memset(buffer, 0, readFrameSize);
  1467.     switch (CodecInfo[readCodecType].mode) {
  1468.       case G723_63:
  1469.       case G723_53:
  1470.         *((DWORD *)buffer) = 0x02;
  1471.         count = 4;
  1472.         break;
  1473.       case G729B:
  1474.         *((WORD *)buffer) = 0;
  1475.         count = 2;
  1476.         break;
  1477.       default:
  1478.         memset(buffer, 0, readFrameSize);
  1479.         count = readFrameSize;
  1480.         break;
  1481.     }
  1482.     return TRUE;
  1483.   }
  1484.  
  1485.   WORD temp_frame_buffer[48];   // 30ms = 12 frames = 48 vectors = 48 WORDS for unpacked vectors
  1486.   void * readBuf;
  1487.   int    readLen;
  1488.   switch (CodecInfo[readCodecType].mode) {
  1489.     case G728 :
  1490.       readBuf = temp_frame_buffer;
  1491.       readLen = sizeof(temp_frame_buffer);
  1492.       break;
  1493.     case G729B :
  1494.       readBuf = temp_frame_buffer;
  1495.       readLen = 12;
  1496.       break;
  1497.     default :
  1498.       readBuf = buffer;
  1499.       readLen = readFrameSize;
  1500.   }
  1501.  
  1502.   for (;;) {
  1503.     fd_set rfds;
  1504.     FD_ZERO(&rfds);
  1505.     FD_SET(os_handle, &rfds);
  1506.     struct timeval ts;
  1507.     ts.tv_sec = 30;
  1508.     ts.tv_usec = 0;
  1509. #if PTRACING
  1510.     PTime then;
  1511. #endif
  1512.     int stat = ::select(os_handle+1, &rfds, NULL, NULL, &ts);
  1513.     if (stat == 0) {
  1514.       PTRACE(1, "IXJ\tRead timeout:" << (PTime() - then));
  1515.       return FALSE;
  1516.     }
  1517.     
  1518.     if (stat > 0) {
  1519.       stat = ::read(os_handle, readBuf, readLen);
  1520.       if (stat == (int)readLen)
  1521.         break;
  1522.     }
  1523.  
  1524.     if ((stat >= 0) || (errno != EINTR)) {
  1525.       PTRACE(1, "IXJ\tRead error = " << errno);
  1526.       return FALSE;
  1527.     }
  1528.  
  1529.     PTRACE(1, "IXJ\tRead EINTR");
  1530.   }
  1531.  
  1532.   switch (CodecInfo[readCodecType].mode) {
  1533.     case G723_63:
  1534.     case G723_53:
  1535.       count = G723count[(*(BYTE *)readBuf)&3];
  1536.       break;
  1537.  
  1538.     case G728 :
  1539.       // for G728, pack four x 4 vectors
  1540.       PINDEX i;
  1541.       for (i = 0; i < 12; i++)
  1542.         G728_Pack(temp_frame_buffer+i*4, ((BYTE *)buffer)+i*5);
  1543.       count = readFrameSize;
  1544.       break;
  1545.  
  1546.     case G729B :
  1547.       switch (temp_frame_buffer[0]) {
  1548.         case 0 : // Silence
  1549.           memset(buffer, 0, 10);
  1550.           count = 10;
  1551.           break;
  1552.         case 1 : // Signal
  1553.           memcpy(buffer, &temp_frame_buffer[1], 10);
  1554.           count = 10;
  1555.           break;
  1556.         case 2 : // VAD
  1557.           memcpy(buffer, &temp_frame_buffer[1], 2);
  1558.           count = 2;
  1559.           break;
  1560.         default : // error
  1561.           PTRACE(1, "IXJ\tIllegal value from codec in G729");
  1562.           return FALSE;
  1563.       }
  1564.       break;
  1565.  
  1566.     default :
  1567.       count = readFrameSize;
  1568.   }
  1569.  
  1570.   return TRUE;
  1571. }
  1572.  
  1573. PINDEX OpalIxJDevice::GetWriteFrameSize(unsigned)
  1574. {
  1575.   return writeFrameSize;
  1576. }
  1577.  
  1578. BOOL OpalIxJDevice::SetWriteFrameSize(unsigned, PINDEX)
  1579. {
  1580.   return FALSE;
  1581. }
  1582.  
  1583. static void G728_Unpack(const BYTE * packed, unsigned short * unpacked)
  1584. {
  1585.   unpacked[0] = ( packed[0]         << 2) | ((packed[1] & 0xc0) >> 6);
  1586.   unpacked[1] = ((packed[1] & 0x3f) << 4) | ((packed[2] & 0xf0) >> 4);
  1587.   unpacked[2] = ((packed[2] & 0x0f) << 6) | ((packed[3] & 0xfc) >> 2);
  1588.   unpacked[3] = ((packed[3] & 0x03) << 8) |   packed[4];
  1589. }
  1590.  
  1591. BOOL OpalIxJDevice::WriteFrame(unsigned, const void * buffer, PINDEX count, PINDEX & written)
  1592. {
  1593.   PWaitAndSignal rmutex(readMutex);
  1594.  
  1595.   written = 0;
  1596.  
  1597.   if (writeStopped) 
  1598.     return FALSE;
  1599.  
  1600.   if (readStopped) {
  1601.     PThread::Current()->Sleep(30);
  1602.     written = writeFrameSize;
  1603.     return TRUE;
  1604.   }
  1605.  
  1606.   WORD temp_frame_buffer[48];
  1607.   const void * writeBuf;
  1608.   int writeLen;
  1609.  
  1610.   switch (CodecInfo[writeCodecType].mode) {
  1611.     case G723_63:
  1612.     case G723_53:
  1613.       writeBuf = buffer;
  1614.       writeLen = 24;
  1615.       written = G723count[(*(BYTE *)buffer)&3];
  1616.       break;
  1617.  
  1618.     case G728 :
  1619.       writeBuf = temp_frame_buffer;
  1620.       writeLen = sizeof(temp_frame_buffer);
  1621.  
  1622.       // for G728, unpack twelve x 4 vectors
  1623.       PINDEX i;
  1624.       for (i = 0; i < 12; i++) 
  1625.         G728_Unpack(((const BYTE *)buffer)+i*5, temp_frame_buffer+i*4);
  1626.       written = 60;
  1627.       break;
  1628.  
  1629.     case G729B :
  1630.       writeBuf = temp_frame_buffer;
  1631.       writeLen = 12;
  1632.  
  1633.       if (count == 2) {
  1634.         temp_frame_buffer[0] = 2;
  1635.         temp_frame_buffer[1] = *(const WORD *)buffer;
  1636.         memset(&temp_frame_buffer[2], 0, 8);
  1637.         written = 2;
  1638.       }
  1639.       else {
  1640.         if (memcmp(buffer, "\0\0\0\0\0\0\0\0\0", 10) != 0)
  1641.           temp_frame_buffer[0] = 1;
  1642.         else
  1643.           temp_frame_buffer[0] = 0;
  1644.         memcpy(&temp_frame_buffer[1], buffer, 10);
  1645.         written = 10;
  1646.       }
  1647.       break;
  1648.  
  1649.     default :
  1650.       writeBuf = buffer;
  1651.       writeLen = writeFrameSize;
  1652.       written = writeFrameSize;
  1653.   }
  1654.  
  1655.   if (count < written) {
  1656.     osError = EINVAL;
  1657.     PTRACE(1, "xJack\tWrite of too small a buffer : " << count << " vs " << written);
  1658.     return FALSE;
  1659.   }
  1660.  
  1661.   for (;;) {
  1662.  
  1663.     fd_set wfds;
  1664.     FD_ZERO(&wfds);
  1665.     FD_SET(os_handle, &wfds);
  1666.     struct timeval ts;
  1667.     ts.tv_sec = 5;
  1668.     ts.tv_usec = 0;
  1669.     int stat = ::select(os_handle+1, NULL, &wfds, NULL, &ts);
  1670.  
  1671.     if (stat == 0) {
  1672.       PTRACE(1, "IXJ\tWrite timeout");
  1673.       return FALSE;
  1674.     }
  1675.  
  1676.     if (stat > 0) {
  1677.       stat = ::write(os_handle, writeBuf, writeLen);
  1678.       if (stat == (int)writeLen)
  1679.         break;
  1680.     }
  1681.  
  1682.     if ((stat >= 0) || (errno != EINTR)) {
  1683.       PTRACE(1, "IXJ\tWrite error = " << errno);
  1684.       return FALSE;
  1685.     }
  1686.  
  1687.     PTRACE(1, "IXJ\tWrite EINTR");
  1688.   }
  1689.  
  1690. //  PTRACE(4, "IXJ\tWrote " << writeLen << " bytes to codec");
  1691.  
  1692.   return TRUE;
  1693. }
  1694.  
  1695.  
  1696. unsigned OpalIxJDevice::GetAverageSignalLevel(unsigned, BOOL playback)
  1697. {
  1698.   return IOCTL(os_handle, playback ? PHONE_PLAY_LEVEL : PHONE_REC_LEVEL);
  1699. }
  1700.  
  1701.  
  1702. BOOL OpalIxJDevice::EnableAudio(unsigned line, BOOL enable)
  1703. {
  1704.   if (line >= GetLineCount())
  1705.     return FALSE;
  1706.  
  1707.   int port = PORT_SPEAKER;
  1708.  
  1709.   if (enable) {
  1710.     if (enabledAudioLine != line) {
  1711.       if (enabledAudioLine != UINT_MAX && exclusiveAudioMode) {
  1712.         PTRACE(3, "xJack\tEnableAudio on port when already enabled other port.");
  1713.         return FALSE;
  1714.       }
  1715.       enabledAudioLine = line;
  1716.     }
  1717.     port = (line == POTSLine) ? PORT_POTS : PORT_PSTN;
  1718.   }
  1719.   else
  1720.     enabledAudioLine = UINT_MAX;
  1721.  
  1722.   return ConvertOSError(IOCTL2(os_handle, IXJCTL_PORT, port));
  1723. }
  1724.  
  1725.  
  1726. BOOL OpalIxJDevice::IsAudioEnabled(unsigned line)
  1727. {
  1728.   return enabledAudioLine == line;
  1729. }
  1730.  
  1731.  
  1732. static unsigned ConvertVolume(unsigned volume, unsigned max)
  1733. {
  1734.   // Use four tier logarithmic scale
  1735.   unsigned zone1 = max/64;
  1736.   if (volume < 25)
  1737.     return volume*zone1/25;
  1738.  
  1739.   unsigned zone2 = max/16;
  1740.   if (volume < 50)
  1741.     return (volume-25)*(zone2-zone1)/25 + zone1;
  1742.  
  1743.   unsigned zone3 = max/4;
  1744.   if (volume < 75)
  1745.     return (volume-50)*(zone3-zone2)/25 + zone2;
  1746.  
  1747.   if (volume < 100)
  1748.     return (volume-75)*(max-zone3)/25 + zone3;
  1749.  
  1750.   return max;
  1751. }  
  1752.  
  1753.  
  1754. BOOL OpalIxJDevice::SetRecordVolume(unsigned, unsigned volume)
  1755. {
  1756.   PWaitAndSignal mutex1(readMutex);
  1757.   userRecVol = volume;
  1758.   if ((aecLevel == AECAGC) || inRawMode)
  1759.     return TRUE;
  1760.  
  1761.   // Need to figure out values for each card type here.
  1762.   unsigned dspRecMax = 0x200;
  1763.   return IOCTL2(os_handle, IXJCTL_REC_VOLUME, ConvertVolume(volume, dspRecMax));
  1764. }
  1765.  
  1766. BOOL OpalIxJDevice::GetRecordVolume(unsigned, unsigned & volume)
  1767. {
  1768.   volume = userRecVol;
  1769.   return TRUE;
  1770. }
  1771.  
  1772. BOOL OpalIxJDevice::SetPlayVolume(unsigned, unsigned volume)
  1773. {
  1774.   PWaitAndSignal mutex1(readMutex);
  1775.   userPlayVol = volume;
  1776.   if (inRawMode)
  1777.     return TRUE;
  1778.  
  1779.   // Need to figure out values for each card type here.
  1780.   unsigned dspPlayMax = 0x100;
  1781.   return IOCTL2(os_handle, IXJCTL_PLAY_VOLUME, ConvertVolume(volume, dspPlayMax));
  1782. }
  1783.  
  1784. BOOL OpalIxJDevice::GetPlayVolume(unsigned, unsigned & volume)
  1785. {
  1786.   volume = userPlayVol;
  1787.   return TRUE;
  1788. }
  1789.  
  1790. OpalLineInterfaceDevice::AECLevels OpalIxJDevice::GetAEC(unsigned)
  1791. {
  1792.   return aecLevel;
  1793. }
  1794.  
  1795.  
  1796. BOOL OpalIxJDevice::SetAEC(unsigned line, AECLevels level)
  1797. {
  1798.   aecLevel = level;
  1799.  
  1800.   if (inRawMode)
  1801.     return TRUE;
  1802.  
  1803.   // IXJCTL_AEC_START does not set return code
  1804.   IOCTL2(os_handle, IXJCTL_AEC_START, aecLevel);
  1805.  
  1806.   // if coming out of AGC mode, then set record volume just in case
  1807.   if (aecLevel == AECAGC)
  1808.     SetRecordVolume(line, userRecVol);
  1809.  
  1810.   return TRUE;
  1811. }
  1812.  
  1813.  
  1814. unsigned OpalIxJDevice::GetWinkDuration(unsigned)
  1815. {
  1816.   if (!IsOpen())
  1817.     return 0;
  1818.  
  1819.   return IOCTL2(os_handle, IXJCTL_WINK_DURATION, 0);
  1820. }
  1821.  
  1822.  
  1823. BOOL OpalIxJDevice::SetWinkDuration(unsigned, unsigned winkDuration)
  1824. {
  1825.   if (!IsOpen())
  1826.     return FALSE;  
  1827.  
  1828.   return IOCTL2(os_handle, IXJCTL_WINK_DURATION, winkDuration);
  1829. }
  1830.  
  1831.  
  1832. BOOL OpalIxJDevice::GetVAD(unsigned)
  1833. {
  1834.   return FALSE;
  1835. }
  1836.  
  1837.  
  1838. BOOL OpalIxJDevice::SetVAD(unsigned, BOOL)
  1839. {
  1840.   return FALSE;
  1841. }
  1842.  
  1843.  
  1844. BOOL OpalIxJDevice::GetCallerID(unsigned line, PString & callerId, BOOL /*full*/)
  1845. {
  1846. #if TELEPHONY_VERSION < 3000
  1847.   return FALSE;
  1848. #else
  1849.  
  1850.   if (line != PSTNLine)
  1851.     return FALSE;
  1852.  
  1853.   // string is "number <TAB> time <TAB> name"
  1854.  
  1855.   PWaitAndSignal m(exceptionMutex);
  1856.   ExceptionInfo * info = GetException();
  1857.  
  1858.   if (info->hasCid) {
  1859.     PHONE_CID cid = info->cid;
  1860.     callerId  = PString(cid.number, cid.numlen) + '\t';
  1861.     callerId += PString(cid.hour, 3) + ':' + PString(cid.min, 3) + ' ' + PString(cid.month, 3) + '/' + PString(cid.day, 3) + '\t';
  1862.     callerId += PString(cid.name, cid.namelen);
  1863.     info->hasCid = FALSE;
  1864.     return TRUE;
  1865.   }
  1866.  
  1867.   return FALSE;
  1868. #endif
  1869. }
  1870.  
  1871. #if TELEPHONY_VERSION >= 3000
  1872.  
  1873. static BOOL IsPhoneDigits(const PString & str)
  1874. {
  1875.   PINDEX i;
  1876.   for (i = 0; i < str.GetLength(); i++) 
  1877.     if (!isdigit(str[i]) && str[i] != '*' && str[i] != '#')
  1878.       return FALSE;
  1879.   return TRUE;
  1880. }
  1881.  
  1882. static void FormatCallerIdString(const PString & idString, PHONE_CID & callerIdInfo)
  1883. {
  1884.   memset(&callerIdInfo, 0, sizeof(callerIdInfo));
  1885.  
  1886.   if (idString.IsEmpty())
  1887.     return;
  1888.  
  1889.   PString name, number;
  1890.   PTime theTime;
  1891.  
  1892. // string is "number <TAB> time <TAB> name"
  1893.  
  1894.   PStringArray fields = idString.Tokenise('\t', TRUE);
  1895.   int len = fields.GetSize();
  1896.  
  1897.   // if the name is specified, then use it
  1898.   if (len > 2)
  1899.     name = fields[2];
  1900.  
  1901.   // if the time is specified, then use it
  1902.   if (len > 1 && !fields[1].IsEmpty())
  1903.     theTime = PTime(fields[1]);
  1904.  
  1905.   // if the number is specified, then only use it if it is legal
  1906.   // otherwise put it into the name field
  1907.   if (len > 0) {
  1908.     if (IsPhoneDigits(fields[0]))
  1909.       number = fields[0];
  1910.     else if (name.IsEmpty())
  1911.       name = fields[0];
  1912.   }
  1913.  
  1914.   // truncate name and number fields
  1915.   if (name.GetLength() > (PINDEX)sizeof(callerIdInfo.name))
  1916.     name = name.Left(sizeof(callerIdInfo.name));
  1917.   if (number.GetLength() > (PINDEX)sizeof(callerIdInfo.number))
  1918.     number = number.Left(sizeof(callerIdInfo.number));
  1919.  
  1920.   sprintf(callerIdInfo.month, "%02i", theTime.GetMonth());
  1921.   sprintf(callerIdInfo.day,   "%02i", theTime.GetDay());
  1922.   sprintf(callerIdInfo.hour,  "%02i", theTime.GetHour());
  1923.   sprintf(callerIdInfo.min,   "%02i", theTime.GetMinute());
  1924.   strncpy(callerIdInfo.name,    (const char *)name,   sizeof(callerIdInfo.name)-1);
  1925.   callerIdInfo.namelen = name.GetLength();
  1926.   strncpy(callerIdInfo.number,  (const char *)number, sizeof(callerIdInfo.number)-1);
  1927.   callerIdInfo.numlen = number.GetLength();
  1928. }
  1929. #endif
  1930.  
  1931. BOOL OpalIxJDevice::SetCallerID(unsigned line, const PString & idString)
  1932. {
  1933. #if TELEPHONY_VERSION < 3000
  1934.   return FALSE;
  1935. #else
  1936.   if (line != POTSLine)
  1937.     return FALSE;
  1938.  
  1939.   FormatCallerIdString(idString, callerIdInfo);
  1940. #endif
  1941.  
  1942.   return TRUE;
  1943. }
  1944.  
  1945. BOOL OpalIxJDevice::SendCallerIDOnCallWaiting(unsigned line, const PString & idString)
  1946. {
  1947. #if TELEPHONY_VERSION < 3000
  1948.   return FALSE;
  1949. #else
  1950.   if (line != POTSLine)
  1951.     return FALSE;
  1952.  
  1953.   PHONE_CID callerInfo;
  1954.   FormatCallerIdString(idString, callerInfo);
  1955.   IOCTLP(os_handle, IXJCTL_CIDCW, &callerInfo);
  1956.   return TRUE;
  1957. #endif
  1958. }
  1959.  
  1960.  
  1961. BOOL OpalIxJDevice::SendVisualMessageWaitingIndicator(unsigned line, BOOL on)
  1962. {
  1963. #if TELEPHONY_VERSION < 3000
  1964.   return FALSE;
  1965. #else
  1966.   if (line != POTSLine)
  1967.     return FALSE;
  1968.  
  1969.   IOCTL2(os_handle, IXJCTL_VMWI, on);
  1970.  
  1971.   return TRUE;
  1972. #endif
  1973. }
  1974.  
  1975.  
  1976. BOOL OpalIxJDevice::PlayDTMF(unsigned, const char * tones, DWORD onTime, DWORD offTime)
  1977. {
  1978.   PWaitAndSignal mutex(toneMutex);
  1979.  
  1980.   if (tonePlaying)
  1981.     return FALSE;
  1982.  
  1983.   // not really needed, as we have the tone mutex locked
  1984.   tonePlaying = TRUE;
  1985.  
  1986.   IOCTL2(os_handle, PHONE_SET_TONE_ON_TIME,  onTime  * 4);
  1987.   IOCTL2(os_handle, PHONE_SET_TONE_OFF_TIME, offTime * 4);
  1988.  
  1989.   while (*tones != '\0') {
  1990.  
  1991.     char tone = toupper(*tones++);
  1992.  
  1993.     int code = -1;
  1994.     if ('1' <= tone && tone <= '9')
  1995.       code = tone - '0';
  1996.  
  1997.     else if (tone == '*')
  1998.       code = 10;
  1999.  
  2000.     else if (tone == '0')
  2001.       code = 11;
  2002.  
  2003.     else if (tone == '#')
  2004.       code = 12;
  2005.     
  2006.     else if ('A' <= tone && tone <= 'D')
  2007.       code = tone - 'A' + 28;
  2008.  
  2009.     else if ('E' <= tone && tone <= ('E' + 11))
  2010.       code = (tone - 'E') + 13;
  2011.  
  2012.     PTRACE(4, "IXJ\tPlaying tone " << tone);
  2013.  
  2014.     IOCTL2(os_handle, PHONE_PLAY_TONE, code);
  2015.  
  2016.     PThread::Current()->Sleep(onTime + offTime);
  2017.  
  2018.     long countDown = 200;  // a tone longer than 2 seconds? I don't think so...
  2019.     while ((countDown > 0) && IOCTL(os_handle, PHONE_GET_TONE_STATE) != 0) {
  2020.       PThread::Current()->Sleep(10);
  2021.       countDown--;
  2022.     }
  2023.     if (countDown == 0)
  2024.       cerr << "Timeout whilst waiting for DTMF tone to end" << endl;
  2025.   }
  2026.  
  2027.   // "Realize the truth....There is no tone."
  2028.   tonePlaying = FALSE;
  2029.  
  2030.   return TRUE;
  2031. }
  2032.  
  2033.  
  2034. char OpalIxJDevice::ReadDTMF(unsigned)
  2035. {
  2036.   PWaitAndSignal m(exceptionMutex);
  2037.   ExceptionInfo * info = GetException();
  2038.  
  2039.   int p = info->dtmfOut;
  2040.  
  2041.   if (info->dtmfIn == p)
  2042.     return '\0';
  2043.  
  2044.   char ch = info->dtmf[p];
  2045.   p = (p + 1) % 16;
  2046.   info->dtmfOut = p;
  2047.  
  2048.   return ch;
  2049. }
  2050.  
  2051.  
  2052. BOOL OpalIxJDevice::GetRemoveDTMF(unsigned)
  2053. {
  2054.   return removeDTMF;
  2055. }
  2056.  
  2057.  
  2058. BOOL OpalIxJDevice::SetRemoveDTMF(unsigned, BOOL state)
  2059. {
  2060.   removeDTMF = state;
  2061.   return IOCTL2(os_handle, PHONE_DTMF_OOB, state);
  2062. }
  2063.  
  2064.  
  2065. unsigned OpalIxJDevice::IsToneDetected(unsigned)
  2066. {
  2067.   PWaitAndSignal m(exceptionMutex);
  2068.   ExceptionInfo * info = GetException();
  2069.  
  2070.   int tones = NoTone;
  2071.  
  2072.   if (info->cadence[0] != 0) {
  2073.     info->cadence[0] = 0;
  2074.     tones |= DialTone;
  2075.   }
  2076.  
  2077.   if (info->cadence[1] != 0) {
  2078.     info->cadence[1] = 0;
  2079.     tones |= RingTone;
  2080.   }
  2081.  
  2082.   if (info->cadence[2] != 0) {
  2083.     info->cadence[2] = 0;
  2084.     tones |= BusyTone;
  2085.   }
  2086.  
  2087.   if (info->cadence[3] != 0) {
  2088.     info->cadence[3] = 0;
  2089.     tones |= CNGTone;
  2090.   }
  2091.  
  2092.   return tones;
  2093. }
  2094.  
  2095.  
  2096. BOOL OpalIxJDevice::SetToneFilterParameters(unsigned /*line*/,
  2097.                                             CallProgressTones tone,
  2098.                                             unsigned   lowFrequency,
  2099.                                             unsigned   highFrequency,
  2100.                                             PINDEX     numCadences,
  2101.                                             const unsigned * onTimes,
  2102.                                             const unsigned * offTimes)
  2103. {
  2104.   int toneIndex;
  2105.   switch (tone) {
  2106.     case DialTone :
  2107.       toneIndex = 0;
  2108.       break;
  2109.     case RingTone :
  2110.       toneIndex = 1;
  2111.       break;
  2112.     case BusyTone :
  2113.       toneIndex = 2;
  2114.       break;
  2115.     case CNGTone :
  2116.       toneIndex = 3;
  2117.       break;
  2118.     default :
  2119.       PTRACE(1, "xJack\tCannot set filter for tone: " << tone);
  2120.       return FALSE;
  2121.   }
  2122.  
  2123. #ifdef IXJCTL_SET_FILTER
  2124.   int filterCode = -1;
  2125.   int minMatch = 0, maxMatch = 0;
  2126.  
  2127.   if (lowFrequency == highFrequency) {
  2128.     static struct {
  2129.       IXJ_FILTER_FREQ code;
  2130.       unsigned        hertz;
  2131.     } const FreqToIXJFreq[] = {
  2132.       { f350,   350 }, { f300,   300 }, { f330,   330 }, { f340,   340 },
  2133.       { f392,   392 }, { f400,   400 }, { f420,   420 }, { f425,   425 },
  2134.       { f435,   435 }, { f440,   440 }, { f445,   445 }, { f450,   450 },
  2135.       { f452,   452 }, { f475,   475 }, { f480,   480 }, { f494,   494 },
  2136.       { f500,   500 }, { f520,   520 }, { f523,   523 }, { f525,   525 },
  2137.       { f587,   587 }, { f590,   590 }, { f600,   600 }, { f620,   620 },
  2138.       { f660,   660 }, { f700,   700 }, { f740,   740 }, { f750,   750 },
  2139.       { f770,   770 }, { f800,   800 }, { f816,   816 }, { f850,   850 },
  2140.       { f900,   900 }, { f942,   942 }, { f950,   950 }, { f975,   975 },
  2141.       { f1000, 1000 }, { f1020, 1020 }, { f1050, 1050 }, { f1100, 1100 },
  2142.       { f1140, 1140 }, { f1200, 1200 }, { f1209, 1209 }, { f1330, 1330 },
  2143.       { f1336, 1336 }, { f1380, 1380 }, { f1400, 1400 }, { f1477, 1477 },
  2144.       { f1600, 1600 }, { f1800, 1800 }, { f1860, 1860 }
  2145.     };
  2146.  
  2147.     PINDEX i;
  2148.     for (i = 0; i < PARRAYSIZE(FreqToIXJFreq); i++) {
  2149.       if (lowFrequency == FreqToIXJFreq[i].hertz) { 
  2150.         filterCode = FreqToIXJFreq[i].code;
  2151.         minMatch = maxMatch = FreqToIXJFreq[i].hertz;
  2152.         break;
  2153.       }
  2154.     }
  2155.  
  2156.   } else {
  2157.     static struct {
  2158.       IXJ_FILTER_FREQ code;
  2159.       unsigned        minHertz;
  2160.       unsigned        maxHertz;
  2161.     } const FreqToIXJFreq2[] = {
  2162.       { f20_50,       20,   50 }, { f133_200,    133,  200 }, { f300_640,    300,  640 },
  2163.       { f300_500,    300,  500 }, { f300_425,    300,  425 }, { f350_400,    350,  400 },
  2164.       { f350_440,    350,  440 }, { f350_450,    350,  450 }, { f380_420,    380,  420 },
  2165.       { f400_425,    400,  425 }, { f400_440,    400,  440 }, { f400_450,    400,  450 },
  2166.       { f425_450,    425,  450 }, { f425_475,    425,  475 }, { f440_450,    440,  450 },
  2167.       { f440_480,    440,  480 }, { f480_620,    480,  620 }, { f540_660,    540,  660 }, 
  2168.       { f750_1450,   750, 1450 }, { f857_1645,   857, 1645 }, { f900_1300,   900, 1300 },
  2169.       { f935_1215,   935, 1215 }, { f941_1477,   941, 1477 }, { f950_1400,   950, 1400 },
  2170.       { f1100_1750, 1100, 1750 }, { f1633_1638, 1633, 1638 }
  2171.     };
  2172.  
  2173.     PINDEX i;
  2174.  
  2175.     // look for exact match
  2176.     for (i = 0; i < PARRAYSIZE(FreqToIXJFreq2); i++) {
  2177.       if ((lowFrequency == FreqToIXJFreq2[i].minHertz) && (highFrequency == FreqToIXJFreq2[i].maxHertz)) { 
  2178.         filterCode = FreqToIXJFreq2[i].code;
  2179.         minMatch = FreqToIXJFreq2[i].minHertz;
  2180.         maxMatch = FreqToIXJFreq2[i].maxHertz;
  2181.         break;
  2182.       }
  2183.     }
  2184.  
  2185.     // look for an approximate match
  2186.     if (filterCode == -1) {
  2187.       for (i = 0; i < PARRAYSIZE(FreqToIXJFreq2); i++) {
  2188.         if ((lowFrequency > FreqToIXJFreq2[i].minHertz) && (highFrequency < FreqToIXJFreq2[i].maxHertz)) { 
  2189.           filterCode = FreqToIXJFreq2[i].code;
  2190.           minMatch = FreqToIXJFreq2[i].minHertz;
  2191.           maxMatch = FreqToIXJFreq2[i].maxHertz;
  2192.           break;
  2193.         }
  2194.       }
  2195.     }
  2196.   }
  2197.  
  2198.   if (filterCode < 0) {
  2199.     PTRACE(1, "PQIXJ\tCould not find filter match for " << lowFrequency << ", " << highFrequency);
  2200.     return FALSE;
  2201.   }
  2202.  
  2203.   // set the filter
  2204.   IXJ_FILTER filter;
  2205.   filter.filter = toneIndex;
  2206.   filter.freq   = (IXJ_FILTER_FREQ)filterCode;
  2207.   filter.enable = 1;
  2208.   PTRACE(3, "PQIXJ\tFilter " << lowFrequency << "," << highFrequency << " matched to " << minMatch << "," << maxMatch);
  2209.   if (::ioctl(os_handle, IXJCTL_SET_FILTER, &filter) < 0)
  2210.     return FALSE;
  2211. #endif
  2212.  
  2213. #if defined(IXJCTL_FILTER_CADENCE)
  2214.   IXJ_FILTER_CADENCE cadence;
  2215.   memset(&cadence, 0, sizeof(cadence));
  2216.   cadence.enable    = 2;
  2217.   cadence.en_filter = 0;
  2218.   cadence.filter    = toneIndex;
  2219.   switch (numCadences) {
  2220.     default :
  2221.       PTRACE(1, "xJack\tToo many cadence entries for Linux driver!");
  2222.       break;
  2223.     case 3 :
  2224.       cadence.on3  = ( onTimes[2]+5)/10;
  2225.       cadence.off3 = (offTimes[2]+5)/10;
  2226.     case 2 :
  2227.       cadence.on2  = ( onTimes[1]+5)/10;
  2228.       cadence.off2 = (offTimes[1]+5)/10;
  2229.     case 1 :
  2230.       cadence.on1  = ( onTimes[0]+5)/10;
  2231.       cadence.off1 = (offTimes[0]+5)/10;
  2232.   }
  2233.  
  2234.   // set the cadence
  2235.   return ::ioctl(os_handle, IXJCTL_FILTER_CADENCE, &cadence) >= 0;
  2236. #else
  2237.   return FALSE;
  2238. #endif
  2239. }
  2240.  
  2241.  
  2242. BOOL OpalIxJDevice::PlayTone(unsigned line, CallProgressTones tone)
  2243. {
  2244.   {
  2245.     PWaitAndSignal mutex(toneMutex);
  2246.  
  2247.     if (tonePlaying) {
  2248.       tonePlaying = FALSE;
  2249.       IOCTL(os_handle, PHONE_CPT_STOP);
  2250.     }
  2251.  
  2252.     switch (tone) {
  2253.  
  2254.       case DialTone :
  2255.         tonePlaying = TRUE;
  2256.         return IOCTL(os_handle, PHONE_DIALTONE);
  2257.  
  2258.       case RingTone :
  2259.         tonePlaying = TRUE;
  2260.         return IOCTL(os_handle, PHONE_RINGBACK);
  2261.  
  2262.       case BusyTone :
  2263.         tonePlaying = TRUE;
  2264.         return IOCTL(os_handle, PHONE_BUSY);
  2265.  
  2266.       default :
  2267.         break;
  2268.     }
  2269.   }
  2270.  
  2271.   PWaitAndSignal mutex(toneMutex);
  2272.   StopTone(line);
  2273.  
  2274.   return FALSE;
  2275. }
  2276.  
  2277.  
  2278. BOOL OpalIxJDevice::IsTonePlaying(unsigned)
  2279. {
  2280. //  if (IOCTL(os_handle, PHONE_GET_TONE_STATE) != 0) 
  2281. //    return TRUE;
  2282. //  return FALSE;
  2283.  
  2284.   return tonePlaying;
  2285. }
  2286.  
  2287.  
  2288. BOOL OpalIxJDevice::StopTone(unsigned)
  2289. {
  2290.   PWaitAndSignal mutex(toneMutex);
  2291.   if (!tonePlaying) 
  2292.     return TRUE;
  2293.  
  2294.   tonePlaying = FALSE;
  2295.   return IOCTL(os_handle, PHONE_CPT_STOP);
  2296. }
  2297.  
  2298.  
  2299. BOOL OpalIxJDevice::SetCountryCode(T35CountryCodes country)
  2300. {
  2301.   OpalLineInterfaceDevice::SetCountryCode(country);
  2302.  
  2303.   // if a LineJack, the set the DAA coeffiecients
  2304.   if (!IsLineJACK()) {
  2305.     PTRACE(4, "IXJ\tRequest to set DAA country on non-LineJACK");
  2306.     return FALSE;
  2307.   }
  2308.  
  2309.   if (country == UnknownCountry) {
  2310.     PTRACE(4, "IXJ\tRequest to set DAA country to unknown country code");
  2311.   } else {
  2312.     PTRACE(4, "IXJ\tSetting DAA country code to " << (int)country);
  2313.     static int ixjCountry[NumCountryCodes] = {
  2314.       DAA_JAPAN, 0, 0, 0, DAA_GERMANY, 0, 0, 0, 0, DAA_AUSTRALIA, 0, 0, 0, 0,
  2315.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2316.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2317.       DAA_FRANCE, 0, 0, 0, 0, DAA_GERMANY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2318.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2319.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2320.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2321.       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2322.       0, 0, 0, 0, 0, DAA_UK, DAA_US, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  2323.       0
  2324.     };
  2325.     IOCTL2(os_handle, IXJCTL_DAA_COEFF_SET, ixjCountry[countryCode]);
  2326.   }
  2327.  
  2328.   return TRUE;
  2329. }
  2330.  
  2331.  
  2332. DWORD OpalIxJDevice::GetSerialNumber()
  2333. {
  2334.   return IOCTL(os_handle, IXJCTL_SERIAL);
  2335. }
  2336.  
  2337.  
  2338. PStringArray OpalIxJDevice::GetDeviceNames()
  2339. {
  2340.   PStringArray array;
  2341.  
  2342.   PINDEX i, j = 0;
  2343.   for (i = 0; i < 10; i++) {
  2344.     PString devName = psprintf("/dev/phone%i", i);
  2345.     int handle = ::open((const char *)devName, O_RDWR);
  2346.     if (handle < 0)
  2347.       continue;
  2348.     ::close(handle);
  2349.     array[j++] = devName;
  2350.   }
  2351.   return array;
  2352. }
  2353.  
  2354.  
  2355. /////////////////////////////////////////////////////////////////////////////
  2356.