Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / lid.cxx
blobd7f76fea380f157add6859264b9e928314b142b3
1 /*
2 * lid.cxx
4 * Line Interface Device
6 * Open Phone Abstraction Library
8 * Copyright (c) 1999-2000 Equivalence Pty. Ltd.
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/
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.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.103 2004/07/19 14:16:10 csoutheren
28 * Fixed problem with pragma dispayed as warning in gcc 3.5-20040704
30 * Revision 1.102 2004/06/01 05:48:03 csoutheren
31 * Changed capability table to use abstract factory routines rather than internal linked list
33 * Revision 1.101 2004/05/19 07:38:24 csoutheren
34 * Changed OpalMediaFormat handling to use abstract factory method functions
36 * Revision 1.100 2004/05/04 03:33:33 csoutheren
37 * Added guards against comparing certain kinds of Capabilities
39 * Revision 1.99 2004/04/03 08:28:07 csoutheren
40 * Remove pseudo-RTTI and replaced with real RTTI
42 * Revision 1.98 2003/08/18 23:56:01 dereksmithies
43 * Fix typos in previous commit.
45 * Revision 1.97 2003/08/18 22:13:13 dereksmithies
46 * Add Singapore Ring Cadence. Thanks to Steve.
48 * Revision 1.96 2003/06/03 10:27:42 rjongbloed
49 * Added G.729 and G,729B detection from LID.
51 * Revision 1.95 2003/04/29 08:30:29 robertj
52 * Fixed return type of get wink function.
54 * Revision 1.94 2003/04/28 01:47:52 dereks
55 * Add ability to set/get wink duration for ixj device.
57 * Revision 1.93 2003/03/05 06:26:44 robertj
58 * Added function to play a WAV file to LID, thanks Pietro Ravasio
60 * Revision 1.92 2003/02/13 23:33:36 dereks
61 * Fix reporting of tonenames.
63 * Revision 1.91 2003/01/29 23:58:17 dereks
64 * Fix typo in United Kingdom tone definition.
66 * Revision 1.90 2002/12/02 03:06:26 robertj
67 * Fixed over zealous removal of code when NO_AUDIO_CODECS set.
69 * Revision 1.89 2002/11/05 04:27:12 robertj
70 * Imported RingLine() by array from OPAL.
72 * Revision 1.88 2002/10/30 05:54:17 craigs
73 * Fixed compatibilty problems with G.723.1 6k3 and 5k3
75 * Revision 1.87 2002/08/05 10:03:48 robertj
76 * Cosmetic changes to normalise the usage of pragma interface/implementation.
78 * Revision 1.86 2002/07/01 02:56:17 dereks
79 * Add PTRACE statements to "IsToneDetected"
81 * Revision 1.85 2002/06/27 08:52:57 robertj
82 * Fixed typo and naming convention for Cisco G.723.1 annex A capability.
84 * Revision 1.84 2002/06/26 05:45:45 robertj
85 * Added capability for Cisco IOS non-standard name for G.723.1 Annex A so
86 * can now utilise SID frames with Cisco gateways.
88 * Revision 1.83 2002/06/25 08:30:13 robertj
89 * Changes to differentiate between stright G.723.1 and G.723.1 Annex A using
90 * the OLC dataType silenceSuppression field so does not send SID frames
91 * to receiver codecs that do not understand them.
93 * Revision 1.82 2002/05/09 06:26:34 robertj
94 * Added fuction to get the current audio enable state for line in device.
95 * Changed IxJ EnableAudio() semantics so is exclusive, no direct switching
96 * from PSTN to POTS and vice versa without disabling the old one first.
98 * Revision 1.81 2002/01/23 06:13:56 robertj
99 * Added filter function hooks to codec raw data channel.
101 * Revision 1.80 2002/01/23 01:58:28 robertj
102 * Added function to determine if codecs raw data channel is native format.
104 * Revision 1.79 2002/01/13 23:57:04 robertj
105 * Added mutex so can change raw data channel while reading/writing from codec.
107 * Revision 1.78 2001/12/14 04:33:53 craigs
108 * Disabled 5.3k codec due to problems with Quicknet cards
110 * Revision 1.77 2001/12/11 04:27:28 craigs
111 * Added support for 5.3kbps G723.1
113 * Revision 1.76 2001/09/21 02:52:19 robertj
114 * Implemented static object for all "known" media formats.
116 * Revision 1.75 2001/09/11 01:24:36 robertj
117 * Added conditional compilation to remove video and/or audio codecs.
119 * Revision 1.74 2001/09/10 03:06:29 robertj
120 * Major change to fix problem with error codes being corrupted in a
121 * PChannel when have simultaneous reads and writes in threads.
123 * Revision 1.73 2001/08/06 03:08:57 robertj
124 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
126 * Revision 1.72 2001/07/24 02:28:22 robertj
127 * Added setting of tone filters for a handful of countries.
129 * Revision 1.71 2001/07/20 04:06:18 robertj
130 * Removed old Cisco hack code for G.728, they now do it rigth!
132 * Revision 1.70 2001/07/19 05:54:30 robertj
133 * Updated interface to xJACK drivers to utilise cadence and filter functions
134 * for dial tone, busy tone and ringback tone detection.
136 * Revision 1.69 2001/05/30 03:56:57 robertj
137 * Fixed initial value of read deblocking offset on stopping codec.
139 * Revision 1.68 2001/05/25 07:55:26 robertj
140 * Fixed problem with trace output of tone bits, thanks Vjacheslav Andrejev.
142 * Revision 1.67 2001/05/25 02:19:53 robertj
143 * Fixed problem with codec data reblocking code not being reset when
144 * code is stopped and restarted, thanks Artis Kugevics
146 * Revision 1.66 2001/05/22 00:31:43 robertj
147 * Changed to allow optional wink detection for line disconnect
149 * Revision 1.65 2001/05/14 05:56:28 robertj
150 * Added H323 capability registration system so can add capabilities by
151 * string name instead of having to instantiate explicit classes.
153 * Revision 1.64 2001/05/11 04:43:43 robertj
154 * Added variable names for standard PCM-16 media format name.
156 * Revision 1.63 2001/04/03 23:37:48 craigs
157 * Added extra logging of country change functions
159 * Revision 1.62 2001/03/29 23:43:02 robertj
160 * Added ability to get average signal level for both receive and transmit.
161 * Changed silence detection to use G.723.1 SID frames as indicator of
162 * silence instead of using the average energy and adaptive threshold.
164 * Revision 1.61 2001/03/23 05:38:30 robertj
165 * Added PTRACE_IF to output trace if a conditional is TRUE.
167 * Revision 1.60 2001/02/09 05:36:38 craigs
168 * Added pragma implementation
170 * Revision 1.59 2001/01/28 06:29:55 yurik
171 * WinCE-port - lid.h exists in SDK so we point to right one
173 * Revision 1.58 2001/01/25 07:27:16 robertj
174 * Major changes to add more flexible OpalMediaFormat class to normalise
175 * all information about media types, especially codecs.
177 * Revision 1.57 2001/01/11 06:24:55 robertj
178 * Fixed incorrect value for CNG frame
180 * Revision 1.56 2001/01/11 05:39:44 robertj
181 * Fixed usage of G.723.1 CNG 1 byte frames.
183 * Revision 1.55 2001/01/11 03:51:14 robertj
184 * Fixed bug in WriteBlock() flush, use actual frame size for last write.
186 * Revision 1.54 2001/01/04 06:39:51 robertj
187 * Fixed bug in G.711 mode with xJACK cards if data is not a multiple of 10ms
188 * and some silence is transmitted, closes the logical channel.
190 * Revision 1.53 2000/12/17 22:08:20 craigs
191 * Changed GetCountryCodeList to return PStringList
193 * Revision 1.52 2000/12/11 01:23:32 craigs
194 * Added extra routines to allow country string manipulation
196 * Revision 1.51 2000/12/04 00:04:21 robertj
197 * Changed G.711 "silence" to be 0xff to remove clicks from Quicknet cards,
199 * Revision 1.50 2000/11/30 08:48:36 robertj
200 * Added functions to enable/disable Voice Activity Detection in LID's
202 * Revision 1.49 2000/11/30 03:12:00 robertj
203 * Fixed bug in not resetting buffer offset on buffer flush.
205 * Revision 1.48 2000/11/29 22:08:31 craigs
206 * Fixed problem with using WaitForToneDetect with 0 timeout
208 * Revision 1.47 2000/11/27 05:19:27 robertj
209 * Fixed MSVC warning
211 * Revision 1.46 2000/11/27 00:19:39 robertj
212 * Fixed bug in SetRawCodec, conditional around the wrong way
214 * Revision 1.45 2000/11/26 23:12:18 craigs
215 * Added hook flash detection API
217 * Revision 1.44 2000/11/24 10:56:12 robertj
218 * Added a raw PCM dta mode for generating/detecting standard tones.
219 * Modified the ReadFrame/WriteFrame functions to allow for variable length codecs.
221 * Revision 1.43 2000/11/20 03:15:13 craigs
222 * Changed tone detection API slightly to allow detection of multiple
223 * simultaneous tones
224 * Added fax CNG tone to tone list
226 * Revision 1.42 2000/11/03 06:25:37 robertj
227 * Added flag to IsLinePresent() to force slow test, guarenteeing correct value.
229 * Revision 1.41 2000/10/31 03:21:02 robertj
230 * Fixed bug that caused G.711 transmitter to continuously think there was silence.
232 * Revision 1.40 2000/10/16 09:45:10 robertj
233 * Fixed recently introduced bug, caused artifacts when should be silent G.723.1
235 * Revision 1.39 2000/10/13 02:24:06 robertj
236 * Moved frame reblocking code from LID channel to LID itself and added
237 * ReadBlock/WriteBlock functions to allow non integral frame sizes.
239 * Revision 1.38 2000/09/25 22:31:18 craigs
240 * Added G.723.1 frame erasure capability
242 * Revision 1.37 2000/09/23 07:20:45 robertj
243 * Fixed problem with being able to distinguish between sw and hw codecs in LID channel.
245 * Revision 1.36 2000/09/22 01:35:51 robertj
246 * Added support for handling LID's that only do symmetric codecs.
248 * Revision 1.35 2000/09/01 00:15:21 robertj
249 * Improved country code selection, can use 2 letter ISO codes or
250 * international dialling prefixes (with leading +) to select country.
252 * Revision 1.34 2000/08/31 13:14:40 craigs
253 * Added functions to LID
254 * More bulletproofing to Linux driver
256 * Revision 1.33 2000/08/30 23:24:36 robertj
257 * Renamed string version of SetCountrCode() to SetCountryCodeName() to avoid
258 * C++ masking ancestor overloaded function when overriding numeric version.
260 * Revision 1.32 2000/07/13 16:03:25 robertj
261 * Removed transmission of 1 byte repeat CNG frames in G.723.1 as it crashes other peoples stacks.
263 * Revision 1.31 2000/07/12 10:25:37 robertj
264 * Renamed all codecs so obvious whether software or hardware.
266 * Revision 1.30 2000/07/09 15:23:00 robertj
267 * Changed G.728 not to use Cisco hack. Cisco is just wrong!
268 * Fixed output of silence in G.711 so works with any sized frame.
270 * Revision 1.29 2000/07/02 14:09:49 craigs
271 * Fill uLaw and aLaw silence with 0x80 rather than 0x00
273 * Revision 1.28 2000/06/19 00:32:22 robertj
274 * Changed functionf or adding all lid capabilities to not assume it is to an endpoint.
276 * Revision 1.27 2000/06/01 07:52:30 robertj
277 * Changed some LID capability code back again so does not unneedfully break existing API.
279 * Revision 1.26 2000/05/30 10:19:28 robertj
280 * Added function to add capabilities given a LID.
281 * Improved LID capabilities so cannot create one that is not explicitly supported.
283 * Revision 1.25 2000/05/24 06:43:16 craigs
284 * Added routines to get xJack volume
285 * Fixed problem with receiving G>723.1 NULL frames
287 * Revision 1.24 2000/05/11 03:47:48 craigs
288 * Added extra debugging
290 * Revision 1.23 2000/05/10 04:05:34 robertj
291 * Changed capabilities so has a function to get name of codec, instead of relying on PrintOn.
293 * Revision 1.22 2000/05/04 12:56:43 robertj
294 * Fixed GNU warning.
296 * Revision 1.21 2000/05/04 11:52:35 robertj
297 * Added Packets Too Late statistics, requiring major rearrangement of jitter
298 * buffer code, not also changes semantics of codec Write() function slightly.
300 * Revision 1.20 2000/05/02 04:32:27 robertj
301 * Fixed copyright notice comment.
303 * Revision 1.19 2000/04/30 03:57:14 robertj
304 * Added PTRACE of read/write frame sizes required by LID.
306 * Revision 1.18 2000/04/19 02:04:30 robertj
307 * BeOS port changes.
309 * Revision 1.17 2000/04/14 17:18:07 robertj
310 * Fixed problem with error reporting from LID hardware.
312 * Revision 1.16 2000/04/10 17:45:11 robertj
313 * Added higher level "DialOut" function for PSTN lines.
314 * Added hook flash function.
316 * Revision 1.15 2000/04/05 18:04:12 robertj
317 * Changed caller ID code for better portability.
319 * Revision 1.14 2000/04/03 19:25:14 robertj
320 * Optimised G.711 codec to read/write larger chunks of data.
322 * Revision 1.13 2000/03/31 19:50:51 robertj
323 * Fixed receiver loop being able to deal with RTP packets smaller than expected.
325 * Revision 1.12 2000/03/30 19:32:35 robertj
326 * Added swab function which seems to be missing on Linux.
328 * Revision 1.11 2000/03/30 01:57:16 robertj
329 * Added hacks so G.728 works with (I think) broken cisco gateways.
331 * Revision 1.10 2000/03/29 21:01:52 robertj
332 * Changed codec to use number of frames rather than number of bytes.
333 * Added function on LID to get available codecs.
334 * Fixed codec table for G.729 codec
336 * Revision 1.9 2000/03/28 05:22:05 robertj
337 * Fixed translation of text country code to numeric code.
339 * Revision 1.8 2000/03/23 23:36:49 robertj
340 * Added more calling tone detection functionality.
342 * Revision 1.7 2000/03/21 03:06:50 robertj
343 * Changes to make RTP TX of exact numbers of frames in some codecs.
345 * Revision 1.6 2000/01/13 12:39:29 robertj
346 * Added string based country codes to LID.
348 * Revision 1.5 2000/01/13 04:03:46 robertj
349 * Added video transmission
351 * Revision 1.4 2000/01/07 10:01:26 robertj
352 * GCC/Linux compatibility
354 * Revision 1.3 2000/01/07 08:28:09 robertj
355 * Additions and changes to line interface device base class.
357 * Revision 1.2 1999/12/29 01:18:07 craigs
358 * Fixed problem with codecs other than G.711 not working after reorganisation
360 * Revision 1.1 1999/12/23 23:02:36 robertj
361 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
365 #ifdef __GNUC__
366 #pragma implementation "lid.h"
367 #endif
369 #include <ptlib.h>
371 #ifndef _WIN32_WCE
372 #include "lid.h"
373 #else
374 #include "..\include\lid.h"
375 #endif
376 #include "h245.h"
379 #define new PNEW
382 ///////////////////////////////////////////////////////////////////////////////
384 #if PTRACING
385 static const char * const CallProgressTonesNames[] = {
386 "DialTone", "RingTone", "BusyTone", "ClearTone", "CNGTone"
389 ostream & operator<<(ostream & o, OpalLineInterfaceDevice::CallProgressTones t)
391 PINDEX i = 0;
392 while ((1 << i) != t)
393 i++;
395 if (i < PARRAYSIZE(CallProgressTonesNames))
396 return o << CallProgressTonesNames[i];
397 else
398 return o << "Unknown";
401 #endif
404 OpalLineInterfaceDevice::OpalLineInterfaceDevice()
406 os_handle = -1;
407 osError = 0;
408 countryCode = UnknownCountry;
409 readDeblockingOffset = P_MAX_INDEX;
410 writeDeblockingOffset = 0;
414 BOOL OpalLineInterfaceDevice::IsOpen() const
416 return os_handle >= 0;
420 BOOL OpalLineInterfaceDevice::Close()
422 if (os_handle < 0)
423 return FALSE;
425 os_handle = -1;
426 return TRUE;
430 BOOL OpalLineInterfaceDevice::IsLineTerminal(unsigned)
432 return FALSE;
436 BOOL OpalLineInterfaceDevice::IsLinePresent(unsigned, BOOL)
438 return TRUE;
442 BOOL OpalLineInterfaceDevice::HookFlash(unsigned line, unsigned flashTime)
444 if (!IsLineOffHook(line))
445 return FALSE;
447 if (!SetLineOnHook(line))
448 return FALSE;
450 PThread::Current()->Sleep(flashTime);
452 return SetLineOffHook(line);
456 BOOL OpalLineInterfaceDevice::HasHookFlash(unsigned)
458 return FALSE;
462 BOOL OpalLineInterfaceDevice::IsLineRinging(unsigned, DWORD *)
464 return FALSE;
468 BOOL OpalLineInterfaceDevice::RingLine(unsigned, DWORD)
470 return FALSE;
474 BOOL OpalLineInterfaceDevice::RingLine(unsigned, PINDEX, unsigned *)
476 return FALSE;
480 BOOL OpalLineInterfaceDevice::IsLineDisconnected(unsigned line, BOOL)
482 return IsToneDetected(line) == BusyTone;
486 BOOL OpalLineInterfaceDevice::SetLineToLineDirect(unsigned, unsigned, BOOL)
488 return FALSE;
492 BOOL OpalLineInterfaceDevice::IsLineToLineDirect(unsigned, unsigned)
494 return FALSE;
498 OpalMediaFormat FindMediaFormat(RTP_DataFrame::PayloadTypes pt)
500 const OpalMediaFormat::List & formats = OpalMediaFormat::GetRegisteredMediaFormats();
501 for (PINDEX i = 0; i < formats.GetSize(); i++) {
502 if (formats[i].GetPayloadType() == pt)
503 return formats[i];
506 return "<<Unknown RTP payload type>>";
510 BOOL OpalLineInterfaceDevice::SetReadCodec(unsigned line,
511 RTP_DataFrame::PayloadTypes codec)
513 return SetReadFormat(line, FindMediaFormat(codec));
517 BOOL OpalLineInterfaceDevice::SetWriteCodec(unsigned line,
518 RTP_DataFrame::PayloadTypes codec)
520 return SetWriteFormat(line, FindMediaFormat(codec));
524 BOOL OpalLineInterfaceDevice::SetRawCodec(unsigned line)
526 if (!SetReadFormat(line, OpalPCM16))
527 return FALSE;
529 if (SetWriteFormat(line, OpalPCM16))
530 return TRUE;
532 StopReadCodec(line);
533 return FALSE;
537 BOOL OpalLineInterfaceDevice::StopReadCodec(unsigned)
539 readDeblockingOffset = P_MAX_INDEX;
540 return TRUE;
544 BOOL OpalLineInterfaceDevice::StopWriteCodec(unsigned)
546 writeDeblockingOffset = 0;
547 return TRUE;
551 BOOL OpalLineInterfaceDevice::StopRawCodec(unsigned line)
553 BOOL ok = StopReadCodec(line);
554 return StopWriteCodec(line) && ok;
558 BOOL OpalLineInterfaceDevice::SetReadFrameSize(unsigned, PINDEX)
560 return FALSE;
564 BOOL OpalLineInterfaceDevice::SetWriteFrameSize(unsigned, PINDEX)
566 return FALSE;
570 BOOL OpalLineInterfaceDevice::ReadBlock(unsigned line, void * buffer, PINDEX length)
572 // Are reblocking the hardware frame sizes to those expected by the RTP packets.
573 PINDEX frameSize = GetReadFrameSize(line);
575 BYTE * bufferPtr = (BYTE *)buffer;
577 PINDEX readBytes;
578 while (length > 0) {
579 if (readDeblockingOffset < frameSize) {
580 PINDEX left = frameSize - readDeblockingOffset;
581 if (left > length)
582 left = length;
583 memcpy(bufferPtr, &readDeblockingBuffer[readDeblockingOffset], left);
584 readDeblockingOffset += left;
585 bufferPtr += left;
586 length -= left;
588 else if (length < frameSize) {
589 BYTE * deblockPtr = readDeblockingBuffer.GetPointer(frameSize);
590 if (!ReadFrame(line, deblockPtr, readBytes))
591 return FALSE;
592 readDeblockingOffset = 0;
594 else {
595 if (!ReadFrame(line, bufferPtr, readBytes))
596 return FALSE;
597 bufferPtr += readBytes;
598 length -= readBytes;
602 return TRUE;
606 BOOL OpalLineInterfaceDevice::WriteBlock(unsigned line, const void * buffer, PINDEX length)
608 PINDEX frameSize = GetWriteFrameSize(line);
609 PINDEX written;
611 // If zero length then flush any remaining data
612 if (length == 0 && writeDeblockingOffset != 0) {
613 SetWriteFrameSize(line, writeDeblockingOffset);
614 BOOL ok = WriteFrame(line,
615 writeDeblockingBuffer.GetPointer(),
616 GetWriteFrameSize(line),
617 written);
618 SetWriteFrameSize(line, frameSize);
619 writeDeblockingOffset = 0;
620 return ok;
623 const BYTE * bufferPtr = (const BYTE *)buffer;
625 while (length > 0) {
626 // If have enough data and nothing in the reblocking buffer, just send it
627 // straight on to the device.
628 if (writeDeblockingOffset == 0 && length >= frameSize) {
629 if (!WriteFrame(line, bufferPtr, frameSize, written))
630 return FALSE;
631 bufferPtr += written;
632 length -= written;
634 else {
635 BYTE * savedFramePtr = writeDeblockingBuffer.GetPointer(frameSize);
637 // See if new chunk gives us enough for one frames worth
638 if ((writeDeblockingOffset + length) < frameSize) {
639 // Nope, just copy bytes into buffer and return
640 memcpy(savedFramePtr + writeDeblockingOffset, bufferPtr, length);
641 writeDeblockingOffset += length;
642 return TRUE;
645 /* Calculate bytes we want from the passed in buffer to fill a frame by
646 subtracting from full frame width the amount we have so far. This also
647 means the lastWriteCount is set to the correct amount of buffer we are
648 grabbing this time around.
650 PINDEX left = frameSize - writeDeblockingOffset;
651 memcpy(savedFramePtr + writeDeblockingOffset, bufferPtr, left);
652 writeDeblockingOffset = 0;
654 // Write the saved frame out
655 if (!WriteFrame(line, savedFramePtr, frameSize, written))
656 return FALSE;
658 bufferPtr += left;
659 length -= left;
663 return TRUE;
667 unsigned OpalLineInterfaceDevice::GetAverageSignalLevel(unsigned, BOOL)
669 return UINT_MAX;
673 BOOL OpalLineInterfaceDevice::EnableAudio(unsigned line, BOOL enabled)
675 return line < GetLineCount() && enabled;
679 BOOL OpalLineInterfaceDevice::IsAudioEnabled(unsigned line)
681 return line < GetLineCount();
685 BOOL OpalLineInterfaceDevice::SetRecordVolume(unsigned, unsigned)
687 return FALSE;
690 BOOL OpalLineInterfaceDevice::GetRecordVolume(unsigned, unsigned &)
692 return FALSE;
696 BOOL OpalLineInterfaceDevice::SetPlayVolume(unsigned, unsigned)
698 return FALSE;
701 BOOL OpalLineInterfaceDevice::GetPlayVolume(unsigned, unsigned &)
703 return FALSE;
707 OpalLineInterfaceDevice::AECLevels OpalLineInterfaceDevice::GetAEC(unsigned)
709 return AECError;
713 BOOL OpalLineInterfaceDevice::SetAEC(unsigned, AECLevels)
715 return FALSE;
718 unsigned OpalLineInterfaceDevice::GetWinkDuration(unsigned)
720 return 0;
724 BOOL OpalLineInterfaceDevice::SetWinkDuration(unsigned, unsigned)
726 return FALSE;
730 BOOL OpalLineInterfaceDevice::GetVAD(unsigned)
732 return FALSE;
736 BOOL OpalLineInterfaceDevice::SetVAD(unsigned, BOOL)
738 return FALSE;
742 BOOL OpalLineInterfaceDevice::GetCallerID(unsigned, PString & id, BOOL)
744 id = PString();
745 return FALSE;
749 BOOL OpalLineInterfaceDevice::SetCallerID(unsigned, const PString &)
751 return FALSE;
754 BOOL OpalLineInterfaceDevice::SendCallerIDOnCallWaiting(unsigned, const PString &)
756 return FALSE;
760 BOOL OpalLineInterfaceDevice::SendVisualMessageWaitingIndicator(unsigned, BOOL)
762 return FALSE;
765 BOOL OpalLineInterfaceDevice::PlayDTMF(unsigned, const char *, DWORD, DWORD)
767 return FALSE;
771 char OpalLineInterfaceDevice::ReadDTMF(unsigned)
773 return '\0';
777 BOOL OpalLineInterfaceDevice::GetRemoveDTMF(unsigned)
779 return FALSE;
783 BOOL OpalLineInterfaceDevice::SetRemoveDTMF(unsigned, BOOL)
785 return FALSE;
789 unsigned OpalLineInterfaceDevice::IsToneDetected(unsigned)
791 return NoTone;
795 unsigned OpalLineInterfaceDevice::WaitForToneDetect(unsigned line, unsigned timeout)
797 PTRACE(2, "LID\tWaitForToneDetect");
799 static const unsigned sampleRate = 25;
801 timeout = (timeout+sampleRate-1)/sampleRate;
803 unsigned retry = 0;
804 do {
805 unsigned tones = IsToneDetected(line);
806 if (tones != NoTone) {
807 PTRACE(2, "LID\tTone " << tones << " detected after " << (retry*sampleRate) << " ms");
808 return tones;
811 PThread::Current()->Sleep(sampleRate);
812 retry++;
813 } while (retry < timeout);
815 PTRACE(3, "LID\tTone detection timeout " << (retry*sampleRate) << " ms");
816 return NoTone;
820 BOOL OpalLineInterfaceDevice::WaitForTone(unsigned line,
821 CallProgressTones tone,
822 unsigned timeout)
824 PTRACE(3, "LID\tWaitFor the tone " << tone );
825 BOOL res = WaitForToneDetect(line, timeout) & tone;
826 PTRACE(3, "LID\tWaitFor the tone " << tone <<
827 " is successfull-" << (res ? "YES" : "No"));
828 return res;
832 BOOL OpalLineInterfaceDevice::SetToneFilter(unsigned line,
833 CallProgressTones tone,
834 const PString & description)
836 PString freqDesc, cadenceDesc;
837 PINDEX colon = description.Find(':');
838 if (colon == P_MAX_INDEX)
839 freqDesc = description;
840 else {
841 freqDesc = description.Left(colon);
842 cadenceDesc = description.Mid(colon+1);
845 unsigned low_freq, high_freq;
846 PINDEX dash = freqDesc.Find('-');
847 if (dash == P_MAX_INDEX)
848 low_freq = high_freq = freqDesc.AsUnsigned();
849 else {
850 low_freq = freqDesc.Left(dash).AsUnsigned();
851 high_freq = freqDesc.Mid(dash+1).AsUnsigned();
853 if (low_freq < 100 || low_freq > 3000 ||
854 high_freq < 100 || high_freq > 3000 ||
855 low_freq > high_freq) {
856 PTRACE(1, "LID\tIllegal frequency specified: " << description);
857 return FALSE;
860 PStringArray times = cadenceDesc.Tokenise("-");
861 PINDEX numCadences = (times.GetSize()+1)/2;
863 PUnsignedArray onTimes(numCadences), offTimes(numCadences);
864 for (PINDEX i = 0; i < times.GetSize(); i++) {
865 double time = atof(times[i]);
866 if (time <= 0.01 || time > 10) {
867 PTRACE(1, "LID\tIllegal cadence time specified: " << description);
868 return FALSE;
871 if ((i&1) == 0)
872 onTimes[i/2] = (unsigned)(time*1000);
873 else
874 offTimes[i/2] = (unsigned)(time*1000);
877 return SetToneFilterParameters(line, tone, low_freq, high_freq,
878 numCadences, onTimes, offTimes);
882 BOOL OpalLineInterfaceDevice::SetToneFilterParameters(unsigned /*line*/,
883 CallProgressTones /*tone*/,
884 unsigned /*lowFrequency*/,
885 unsigned /*highFrequency*/,
886 PINDEX /*numCadences*/,
887 const unsigned * /*onTimes*/,
888 const unsigned * /*offTimes*/)
890 return FALSE;
894 BOOL OpalLineInterfaceDevice::PlayTone(unsigned, CallProgressTones)
896 return FALSE;
900 BOOL OpalLineInterfaceDevice::IsTonePlaying(unsigned)
902 return FALSE;
906 BOOL OpalLineInterfaceDevice::StopTone(unsigned)
908 return FALSE;
912 BOOL OpalLineInterfaceDevice::PlayAudio(unsigned /*line*/, const PString & /*filename*/)
914 PTRACE(3, "LID\tBase Class PlayAudio method called, exiting with FALSE");
915 return FALSE;
919 BOOL OpalLineInterfaceDevice::StopAudio(unsigned /*line*/)
921 PTRACE(3, "LID\tBase Class StopAudio method called, exiting with FALSE");
922 return FALSE;
926 OpalLineInterfaceDevice::CallProgressTones
927 OpalLineInterfaceDevice::DialOut(unsigned line,
928 const PString & number,
929 BOOL requireTone)
931 PTRACE(3, "LID\tDialOut to " << number);
933 if (IsLineTerminal(line))
934 return NoTone;
936 if (!SetLineOffHook(line))
937 return NoTone;
939 // Should get dial tone within 2 seconds of going off hook
940 if (!WaitForTone(line, DialTone, 2000)) {
941 if (requireTone)
942 return DialTone;
945 // Dial the string
946 PINDEX lastPos = 0;
947 PINDEX nextPos;
948 while ((nextPos = number.FindOneOf("!@,")) != P_MAX_INDEX) {
949 PlayDTMF(line, number(lastPos, nextPos-1));
950 lastPos = nextPos+1;
951 switch (number[nextPos]) {
952 case '!' :
953 if (!HookFlash(line))
954 return NoTone;
955 break;
957 case '@' :
958 if (!WaitForTone(line, DialTone, 3000)) {
959 if (requireTone)
960 return DialTone;
962 break;
964 case ',' :
965 PThread::Current()->Sleep(2000);
966 break;
970 PlayDTMF(line, number.Mid(lastPos));
972 // Wait for busy or ring back
973 unsigned tones;
974 while ((tones = WaitForToneDetect(line, 5000)) != NoTone) {
975 if (tones & BusyTone)
976 return BusyTone;
977 else if (tones & RingTone)
978 break;
981 if (requireTone)
982 return NoTone;
984 return RingTone;
987 static struct {
988 const char * isoName;
989 unsigned dialCode;
990 OpalLineInterfaceDevice::T35CountryCodes t35Code;
991 const char * fullName;
992 const char * dialTone;
993 const char * ringTone;
994 const char * busyTone;
995 } CountryInfo[] = {
996 { "AF", 93, OpalLineInterfaceDevice::Afghanistan, "Afghanistan" },
997 { "AL", 355, OpalLineInterfaceDevice::Albania, "Albania" },
998 { "DZ", 213, OpalLineInterfaceDevice::Algeria, "Algeria" },
999 { "AS", 684, OpalLineInterfaceDevice::AmericanSamoa, "American Samoa" },
1000 { "AO", 244, OpalLineInterfaceDevice::Angola, "Angola" },
1001 { "AI", 1264, OpalLineInterfaceDevice::Anguilla, "Anguilla" },
1002 { "AG", 1268, OpalLineInterfaceDevice::AntiguaAndBarbuda, "Antigua and Barbuda" },
1003 { "AR", 54, OpalLineInterfaceDevice::Argentina, "Argentina" },
1004 { "AC", 247, OpalLineInterfaceDevice::Ascension, "Ascension Island" },
1005 { "AU", 61, OpalLineInterfaceDevice::Australia, "Australia", "425:0.1", "425:0.4-0.2-0.4-2", "425:0.375-0.375" },
1006 { "AT", 43, OpalLineInterfaceDevice::Austria, "Austria" },
1007 { "BS", 1242, OpalLineInterfaceDevice::Bahamas, "Bahamas" },
1008 { "BH", 973, OpalLineInterfaceDevice::Bahrain, "Bahrain" },
1009 { "BD", 880, OpalLineInterfaceDevice::Bangladesh, "Bangladesh" },
1010 { "BB", 1246, OpalLineInterfaceDevice::Barbados, "Barbados" },
1011 { "BE", 32, OpalLineInterfaceDevice::Belgium, "Belgium" },
1012 { "BZ", 501, OpalLineInterfaceDevice::Belize, "Belize" },
1013 { "BJ", 229, OpalLineInterfaceDevice::Benin, "Benin" },
1014 { "BM", 1441, OpalLineInterfaceDevice::Bermudas, "Bermudas" },
1015 { "BT", 975, OpalLineInterfaceDevice::Bhutan, "Bhutan" },
1016 { "BO", 591, OpalLineInterfaceDevice::Bolivia, "Bolivia" },
1017 { "BW", 267, OpalLineInterfaceDevice::Botswana, "Botswana" },
1018 { "BR", 55, OpalLineInterfaceDevice::Brazil, "Brazil" },
1019 { "xx", 0, OpalLineInterfaceDevice::BritishAntarcticTerritory, "British Antarctic Territory" },
1020 { "IO", 246, OpalLineInterfaceDevice::BritishIndianOceanTerritory, "British IndianOcean Territory" },
1021 { "VG", 1284, OpalLineInterfaceDevice::BritishVirginIslands, "British Virgin Islands" },
1022 { "BN", 673, OpalLineInterfaceDevice::BruneiDarussalam, "Brunei Darussalam" },
1023 { "BG", 359, OpalLineInterfaceDevice::Bulgaria, "Bulgaria" },
1024 { "BF", 226, OpalLineInterfaceDevice::BurkinaFaso, "Burkina Faso" },
1025 { "BI", 257, OpalLineInterfaceDevice::Burundi, "Burundi" },
1026 { "xx", 0, OpalLineInterfaceDevice::Byelorussia, "Byelorussia" },
1027 { "KH", 855, OpalLineInterfaceDevice::Cambodia, "Cambodia" },
1028 { "CM", 237, OpalLineInterfaceDevice::Cameroon, "Cameroon" },
1029 { "CA", 1, OpalLineInterfaceDevice::Canada, "Canada" },
1030 { "CV", 238, OpalLineInterfaceDevice::CapeVerde, "Cape Verde" },
1031 { "KY", 1345, OpalLineInterfaceDevice::CaymanIslands, "Cayman Islands" },
1032 { "CF", 236, OpalLineInterfaceDevice::CentralAfricanRepublic,"Central African Republic" },
1033 { "TD", 235, OpalLineInterfaceDevice::Chad, "Chad" },
1034 { "CL", 56, OpalLineInterfaceDevice::Chile, "Chile" },
1035 { "CN", 86, OpalLineInterfaceDevice::China, "China" },
1036 { "CO", 57, OpalLineInterfaceDevice::Colombia, "Colombia" },
1037 { "KM", 269, OpalLineInterfaceDevice::Comoros, "Comoros" },
1038 { "CG", 242, OpalLineInterfaceDevice::Congo, "Congo" },
1039 { "CK", 682, OpalLineInterfaceDevice::CookIslands, "Cook Islands" },
1040 { "CR", 506, OpalLineInterfaceDevice::CostaRica, "Costa Rica" },
1041 { "CI", 225, OpalLineInterfaceDevice::CotedIvoire, "Cote dIvoire" },
1042 { "CU", 53, OpalLineInterfaceDevice::Cuba, "Cuba" },
1043 { "CY", 357, OpalLineInterfaceDevice::Cyprus, "Cyprus" },
1044 { "CZ", 420, OpalLineInterfaceDevice::Czechoslovakia, "Czech Republic" },
1045 { "DK", 45, OpalLineInterfaceDevice::Denmark, "Denmark" },
1046 { "DJ", 253, OpalLineInterfaceDevice::Djibouti, "Djibouti" },
1047 { "DM", 1767, OpalLineInterfaceDevice::Dominica, "Dominica" },
1048 { "DO", 1809, OpalLineInterfaceDevice::DominicanRepublic, "Dominican Republic" },
1049 { "EC", 593, OpalLineInterfaceDevice::Ecuador, "Ecuador" },
1050 { "EG", 20, OpalLineInterfaceDevice::Egypt, "Egypt" },
1051 { "SV", 503, OpalLineInterfaceDevice::ElSalvador, "El Salvador" },
1052 { "GQ", 240, OpalLineInterfaceDevice::EquatorialGuinea, "Equatorial Guinea" },
1053 { "ET", 251, OpalLineInterfaceDevice::Ethiopia, "Ethiopia" },
1054 { "FK", 500, OpalLineInterfaceDevice::FalklandIslands, "Falkland Islands" },
1055 { "FJ", 679, OpalLineInterfaceDevice::Fiji, "Fiji" },
1056 { "FI", 358, OpalLineInterfaceDevice::Finland, "Finland" },
1057 { "FR", 33, OpalLineInterfaceDevice::France, "France" },
1058 { "PF", 689, OpalLineInterfaceDevice::FrenchPolynesia, "French Polynesia" },
1059 { "TF", 0, OpalLineInterfaceDevice::FrenchSouthernAndAntarcticLands, "French Southern and Antarctic Lands" },
1060 { "GA", 241, OpalLineInterfaceDevice::Gabon, "Gabon" },
1061 { "GM", 220, OpalLineInterfaceDevice::Gambia, "Gambia" },
1062 { "DE", 49, OpalLineInterfaceDevice::Germany, "Germany" },
1063 { "GH", 233, OpalLineInterfaceDevice::Ghana, "Ghana" },
1064 { "GI", 350, OpalLineInterfaceDevice::Gibraltar, "Gibraltar" },
1065 { "GR", 30, OpalLineInterfaceDevice::Greece, "Greece" },
1066 { "GD", 1473, OpalLineInterfaceDevice::Grenada, "Grenada" },
1067 { "GU", 1671, OpalLineInterfaceDevice::Guam, "Guam" },
1068 { "GT", 502, OpalLineInterfaceDevice::Guatemala, "Guatemala" },
1069 { "GY", 592, OpalLineInterfaceDevice::Guayana, "Guayana" },
1070 { "GG", 441, OpalLineInterfaceDevice::Guernsey, "Guernsey" },
1071 { "GN", 224, OpalLineInterfaceDevice::Guinea, "Guinea" },
1072 { "GW", 245, OpalLineInterfaceDevice::GuineaBissau, "Guinea Bissau" },
1073 { "HT", 509, OpalLineInterfaceDevice::Haiti, "Haiti" },
1074 { "HN", 504, OpalLineInterfaceDevice::Honduras, "Honduras" },
1075 { "HK", 852, OpalLineInterfaceDevice::Hongkong, "Hong Kong" },
1076 { "HU", 36, OpalLineInterfaceDevice::Hungary, "Hungary" },
1077 { "IS", 354, OpalLineInterfaceDevice::Iceland, "Iceland" },
1078 { "IN", 91, OpalLineInterfaceDevice::India, "India" },
1079 { "ID", 62, OpalLineInterfaceDevice::Indonesia, "Indonesia" },
1080 { "IR", 98, OpalLineInterfaceDevice::Iran, "Iran" },
1081 { "IQ", 964, OpalLineInterfaceDevice::Iraq, "Iraq" },
1082 { "IE", 353, OpalLineInterfaceDevice::Ireland, "Ireland" },
1083 { "IL", 972, OpalLineInterfaceDevice::Israel, "Israel" },
1084 { "IT", 39, OpalLineInterfaceDevice::Italy, "Italy" },
1085 { "JM", 1876, OpalLineInterfaceDevice::Jamaica, "Jamaica" },
1086 { "JP", 81, OpalLineInterfaceDevice::Japan, "Japan" },
1087 { "JE", 442, OpalLineInterfaceDevice::Jersey, "Jersey" },
1088 { "JO", 962, OpalLineInterfaceDevice::Jordan, "Jordan" },
1089 { "KE", 254, OpalLineInterfaceDevice::Kenya, "Kenya" },
1090 { "KI", 686, OpalLineInterfaceDevice::Kiribati, "Kiribati" },
1091 { "KR", 82, OpalLineInterfaceDevice::KoreaRepublic, "Korea, Republic of" },
1092 { "KP", 850, OpalLineInterfaceDevice::DemocraticPeoplesRepublicOfKorea, "Korea, Democratic Peoples Republic of" },
1093 { "KW", 965, OpalLineInterfaceDevice::Kuwait, "Kuwait" },
1094 { "LA", 856, OpalLineInterfaceDevice::Lao, "Lao" },
1095 { "LB", 961, OpalLineInterfaceDevice::Lebanon, "Lebanon" },
1096 { "LS", 266, OpalLineInterfaceDevice::Lesotho, "Lesotho" },
1097 { "LR", 231, OpalLineInterfaceDevice::Liberia, "Liberia" },
1098 { "LY", 218, OpalLineInterfaceDevice::Libya, "Libya" },
1099 { "LI", 423, OpalLineInterfaceDevice::Liechtenstein, "Liechtenstein" },
1100 { "LU", 352, OpalLineInterfaceDevice::Luxemborg, "Luxemborg" },
1101 { "MO", 853, OpalLineInterfaceDevice::Macao, "Macao" },
1102 { "MG", 261, OpalLineInterfaceDevice::Madagascar, "Madagascar" },
1103 { "MY", 60, OpalLineInterfaceDevice::Malaysia, "Malaysia" },
1104 { "MW", 265, OpalLineInterfaceDevice::Malawi, "Malawi" },
1105 { "MV", 960, OpalLineInterfaceDevice::Maldives, "Maldives" },
1106 { "ML", 223, OpalLineInterfaceDevice::Mali, "Mali" },
1107 { "MT", 356, OpalLineInterfaceDevice::Malta, "Malta" },
1108 { "MR", 222, OpalLineInterfaceDevice::Mauritania, "Mauritania" },
1109 { "MU", 230, OpalLineInterfaceDevice::Mauritius, "Mauritius" },
1110 { "MX", 52, OpalLineInterfaceDevice::Mexico, "Mexico" },
1111 { "MC", 377, OpalLineInterfaceDevice::Monaco, "Monaco" },
1112 { "MN", 976, OpalLineInterfaceDevice::Mongolia, "Mongolia" },
1113 { "MS", 1664, OpalLineInterfaceDevice::Montserrat, "Montserrat" },
1114 { "MA", 212, OpalLineInterfaceDevice::Morocco, "Morocco" },
1115 { "MZ", 258, OpalLineInterfaceDevice::Mozambique, "Mozambique" },
1116 { "MM", 95, OpalLineInterfaceDevice::Myanmar, "Myanmar" },
1117 { "NR", 674, OpalLineInterfaceDevice::Nauru, "Nauru" },
1118 { "NP", 977, OpalLineInterfaceDevice::Nepal, "Nepal" },
1119 { "NL", 31, OpalLineInterfaceDevice::Netherlands, "Netherlands", "425:0.1", "425:1.0-4.0", "425:0.5-0.5" },
1120 { "AN", 599, OpalLineInterfaceDevice::NetherlandsAntilles, "Netherlands Antilles" },
1121 { "NC", 687, OpalLineInterfaceDevice::NewCaledonia, "New Caledonia" },
1122 { "NZ", 64, OpalLineInterfaceDevice::NewZealand, "New Zealand" },
1123 { "NI", 505, OpalLineInterfaceDevice::Nicaragua, "Nicaragua" },
1124 { "NE", 227, OpalLineInterfaceDevice::Niger, "Niger" },
1125 { "NG", 234, OpalLineInterfaceDevice::Nigeria, "Nigeria" },
1126 { "NO", 47, OpalLineInterfaceDevice::Norway, "Norway" },
1127 { "OM", 968, OpalLineInterfaceDevice::Oman, "Oman" },
1128 { "PK", 92, OpalLineInterfaceDevice::Pakistan, "Pakistan" },
1129 { "PA", 507, OpalLineInterfaceDevice::Panama, "Panama" },
1130 { "PG", 675, OpalLineInterfaceDevice::PapuaNewGuinea, "Papua New Guinea" },
1131 { "PY", 595, OpalLineInterfaceDevice::Paraguay, "Paraguay" },
1132 { "PE", 51, OpalLineInterfaceDevice::Peru, "Peru" },
1133 { "PH", 63, OpalLineInterfaceDevice::Philippines, "Philippines" },
1134 { "PL", 48, OpalLineInterfaceDevice::Poland, "Poland" },
1135 { "PT", 351, OpalLineInterfaceDevice::Portugal, "Portugal" },
1136 { "PR", 1787, OpalLineInterfaceDevice::PuertoRico, "Puerto Rico" },
1137 { "QA", 974, OpalLineInterfaceDevice::Qatar, "Qatar" },
1138 { "RO", 40, OpalLineInterfaceDevice::Romania, "Romania" },
1139 { "RU", 7, OpalLineInterfaceDevice::USSR, "Russia" },
1140 { "RW", 250, OpalLineInterfaceDevice::Rwanda, "Rwanda" },
1141 { "xx", 0, OpalLineInterfaceDevice::SaintCroix, "Saint Croix" },
1142 { "SH", 290, OpalLineInterfaceDevice::SaintHelenaAndAscension, "Saint Helena and Ascension" },
1143 { "KN", 1869, OpalLineInterfaceDevice::SaintKittsAndNevis, "Saint Kitts and Nevis" },
1144 { "LC", 1758, OpalLineInterfaceDevice::SaintLucia, "Saint Lucia" },
1145 { "xx", 0, OpalLineInterfaceDevice::SaintThomas, "Saint Thomas" },
1146 { "VC", 1784, OpalLineInterfaceDevice::SaintVicentAndTheGrenadines, "Saint Vicent and the Grenadines" },
1147 { "SM", 378, OpalLineInterfaceDevice::SanMarino, "San Marino" },
1148 { "ST", 239, OpalLineInterfaceDevice::SaoTomeAndPrincipe, "Sao Tome and Principe" },
1149 { "SA", 966, OpalLineInterfaceDevice::SaudiArabia, "Saudi Arabia" },
1150 { "SN", 221, OpalLineInterfaceDevice::Senegal, "Senegal" },
1151 { "SC", 248, OpalLineInterfaceDevice::Seychelles, "Seychelles" },
1152 { "SL", 232, OpalLineInterfaceDevice::SierraLeone, "Sierra Leone" },
1153 { "SG", 65, OpalLineInterfaceDevice::Singapore, "Singapore", "425:0.1", "425:0.4-0.2-0.4-2", "425:0.75-0.75"},
1154 { "SB", 677, OpalLineInterfaceDevice::SolomonIslands, "Solomon Islands" },
1155 { "SO", 252, OpalLineInterfaceDevice::Somalia, "Somalia" },
1156 { "ZA", 27, OpalLineInterfaceDevice::SouthAfrica, "South Africa" },
1157 { "ES", 34, OpalLineInterfaceDevice::Spain, "Spain" },
1158 { "LK", 94, OpalLineInterfaceDevice::SriLanka, "Sri Lanka" },
1159 { "SD", 249, OpalLineInterfaceDevice::Sudan, "Sudan" },
1160 { "SR", 597, OpalLineInterfaceDevice::Suriname, "Suriname" },
1161 { "SZ", 268, OpalLineInterfaceDevice::Swaziland, "Swaziland" },
1162 { "SE", 46, OpalLineInterfaceDevice::Sweden, "Sweden" },
1163 { "CH", 41, OpalLineInterfaceDevice::Switzerland, "Switzerland" },
1164 { "SY", 963, OpalLineInterfaceDevice::Syria, "Syria" },
1165 { "TZ", 255, OpalLineInterfaceDevice::Tanzania, "Tanzania" },
1166 { "TH", 66, OpalLineInterfaceDevice::Thailand, "Thailand" },
1167 { "TG", 228, OpalLineInterfaceDevice::Togo, "Togo" },
1168 { "TO", 676, OpalLineInterfaceDevice::Tonga, "Tonga" },
1169 { "TT", 1868, OpalLineInterfaceDevice::TrinidadAndTobago, "Trinidad and Tobago" },
1170 { "TN", 216, OpalLineInterfaceDevice::Tunisia, "Tunisia" },
1171 { "TR", 90, OpalLineInterfaceDevice::Turkey, "Turkey" },
1172 { "TC", 1649, OpalLineInterfaceDevice::TurksAndCaicosIslands, "Turks and Caicos Islands" },
1173 { "TV", 688, OpalLineInterfaceDevice::Tuvalu, "Tuvalu" },
1174 { "UG", 256, OpalLineInterfaceDevice::Uganda, "Uganda" },
1175 { "UA", 380, OpalLineInterfaceDevice::Ukraine, "Ukraine" },
1176 { "AE", 971, OpalLineInterfaceDevice::UnitedArabEmirates, "United Arab Emirates" },
1177 { "GB", 44, OpalLineInterfaceDevice::UnitedKingdom, "United Kingdom", "350-440:0.1", "400-450:0.4-0.2-0.4-2", "400:0.375-0.375" },
1178 { "US", 1, OpalLineInterfaceDevice::UnitedStates, "United States", "350-440:0.1", "440-480:2.0-4.0", "480-620:0.5-0.5" },
1179 { "UY", 598, OpalLineInterfaceDevice::Uruguay, "Uruguay" },
1180 { "VU", 678, OpalLineInterfaceDevice::Vanuatu, "Vanuatu" },
1181 { "VA", 379, OpalLineInterfaceDevice::VaticanCityState, "Vatican City State" },
1182 { "VE", 58, OpalLineInterfaceDevice::Venezuela, "Venezuela" },
1183 { "VN", 84, OpalLineInterfaceDevice::VietNam, "Viet Nam" },
1184 { "WF", 681, OpalLineInterfaceDevice::WallisAndFutuna, "Wallis and Futuna" },
1185 { "WS", 685, OpalLineInterfaceDevice::WesternSamoa, "Western Samoa" },
1186 { "YE", 967, OpalLineInterfaceDevice::Yemen, "Yemen" },
1187 { "YU", 381, OpalLineInterfaceDevice::Yugoslavia, "Yugoslavia" },
1188 { "xx", 0, OpalLineInterfaceDevice::Zaire, "Zaire" },
1189 { "ZM", 260, OpalLineInterfaceDevice::Zambia, "Zambia" },
1190 { "ZW", 263, OpalLineInterfaceDevice::Zimbabwe, "Zimbabwe" }
1193 OpalLineInterfaceDevice::T35CountryCodes OpalLineInterfaceDevice::GetCountryCode(const PString & str)
1195 for (PINDEX i = 0; i < PARRAYSIZE(CountryInfo); i++)
1196 if (str *= CountryInfo[i].fullName)
1197 return CountryInfo[i].t35Code;
1199 return OpalLineInterfaceDevice::UnknownCountry;
1203 PString OpalLineInterfaceDevice::GetCountryCodeName(T35CountryCodes c)
1205 for (PINDEX i = 0; i < PARRAYSIZE(CountryInfo); i++)
1206 if (CountryInfo[i].t35Code == c)
1207 return CountryInfo[i].fullName;
1209 return "<Unknown>";
1213 PString OpalLineInterfaceDevice::GetCountryCodeName() const
1215 return GetCountryCodeName(countryCode);
1219 BOOL OpalLineInterfaceDevice::SetCountryCode(T35CountryCodes country)
1221 countryCode = country;
1223 unsigned line;
1224 for (line = 0; line < GetLineCount(); line++)
1225 SetToneFilter(line, CNGTone, "1100:0.25");
1227 for (PINDEX i = 0; i < PARRAYSIZE(CountryInfo); i++) {
1228 if (CountryInfo[i].t35Code == country) {
1229 PTRACE(2, "LID\tCountry set to " << CountryInfo[i].fullName);
1230 for (line = 0; line < GetLineCount(); line++) {
1231 if (CountryInfo[i].dialTone != NULL)
1232 SetToneFilter(line, DialTone, CountryInfo[i].dialTone);
1233 if (CountryInfo[i].ringTone != NULL)
1234 SetToneFilter(line, RingTone, CountryInfo[i].ringTone);
1235 if (CountryInfo[i].busyTone != NULL)
1236 SetToneFilter(line, BusyTone, CountryInfo[i].busyTone);
1238 return TRUE;
1242 PTRACE(2, "LID\tCountry set to " << GetCountryCodeName());
1243 return TRUE;
1247 PStringList OpalLineInterfaceDevice::GetCountryCodeNameList() const
1249 PStringList list;
1250 list.AppendString("United States");
1251 return list;
1255 static PCaselessString DeSpaced(const PString & orig)
1257 PString str = orig.Trim();
1259 PINDEX space = 0;
1260 while ((space = str.Find(' ')) != P_MAX_INDEX)
1261 str.Delete(space, 1);
1263 return str;
1267 BOOL OpalLineInterfaceDevice::SetCountryCodeName(const PString & countryName)
1269 PTRACE(4, "IXJ\tSetting country code name to " << countryName);
1270 PCaselessString spacelessAndCaseless = DeSpaced(countryName);
1271 if (spacelessAndCaseless.IsEmpty())
1272 return FALSE;
1274 if (isdigit(spacelessAndCaseless[0]))
1275 return SetCountryCode((T35CountryCodes)spacelessAndCaseless.AsUnsigned());
1277 PINDEX i;
1278 if (spacelessAndCaseless[0] == '+') {
1279 unsigned code = spacelessAndCaseless.AsUnsigned();
1280 for (i = 0; i < PARRAYSIZE(CountryInfo); i++)
1281 if (code == CountryInfo[i].dialCode)
1282 return SetCountryCode(CountryInfo[i].t35Code);
1284 else if (spacelessAndCaseless.GetLength() == 2) {
1285 for (i = 0; i < PARRAYSIZE(CountryInfo); i++)
1286 if (spacelessAndCaseless == CountryInfo[i].isoName)
1287 return SetCountryCode(CountryInfo[i].t35Code);
1289 else {
1290 for (i = 0; i < PARRAYSIZE(CountryInfo); i++)
1291 if (spacelessAndCaseless == DeSpaced(CountryInfo[i].fullName))
1292 return SetCountryCode(CountryInfo[i].t35Code);
1295 SetCountryCode(UnknownCountry);
1296 return FALSE;
1300 PString OpalLineInterfaceDevice::GetErrorText() const
1302 return PChannel::GetErrorText(PChannel::Miscellaneous, osError);
1306 void OpalLineInterfaceDevice::PrintOn(ostream & strm) const
1308 strm << GetName();
1312 /////////////////////////////////////////////////////////////////////////////
1314 static struct {
1315 const char * name;
1317 unsigned bytesPerFrame;
1318 unsigned rxFramesInPacket;
1319 unsigned txFramesInPacket;
1320 BOOL g7231annexA;
1322 H245_AudioCapability::Choices capabilitySubtype;
1324 } CodecTypeInfo[] = {
1325 // Do not alter the order of the next four entries without understanding what
1326 // H323_LIDCapability::OnReceivedPDU() does with them!
1327 #define G7231A_63_INDEX 1
1328 { OPAL_G7231A_5k3, 24, 8, 3, TRUE, H245_AudioCapability::e_g7231 },
1329 { OPAL_G7231A_6k3, 24, 8, 3, TRUE, H245_AudioCapability::e_g7231 },
1330 { OPAL_G7231_5k3, 24, 8, 3, FALSE, H245_AudioCapability::e_g7231 },
1331 { OPAL_G7231_6k3, 24, 8, 3, FALSE, H245_AudioCapability::e_g7231 },
1333 { OPAL_G729, 10, 24, 6, FALSE, H245_AudioCapability::e_g729 },
1334 { OPAL_G729A, 10, 24, 6, FALSE, H245_AudioCapability::e_g729AnnexA },
1335 { OPAL_G729B, 10, 24, 6, FALSE, H245_AudioCapability::e_g729wAnnexB },
1336 { OPAL_G729AB, 10, 24, 6, FALSE, H245_AudioCapability::e_g729AnnexAwAnnexB },
1337 { OPAL_GSM0610, 33, 7, 4, FALSE, H245_AudioCapability::e_gsmFullRate },
1338 { OPAL_G728, 5, 96, 20, FALSE, H245_AudioCapability::e_g728 },
1339 { OPAL_G711_ULAW_64K, 8, 240, 30, FALSE, H245_AudioCapability::e_g711Ulaw64k },
1340 { OPAL_G711_ALAW_64K, 8, 240, 30, FALSE, H245_AudioCapability::e_g711Alaw64k },
1343 #define DEFINE_LID_CAPABILITY(cls, capName, fmtName) \
1344 class cls : public H323_LIDCapability { \
1345 public: \
1346 cls() : H323_LIDCapability(fmtName) { } \
1347 }; \
1348 H323_REGISTER_CAPABILITY(cls, capName) \
1350 DEFINE_LID_CAPABILITY(H323_LID_G711_ALaw_Capability, OPAL_G711_ALAW_64K"{hw}", OpalG711ALaw)
1351 DEFINE_LID_CAPABILITY(H323_LID_G711_uLaw_Capability, OPAL_G711_ULAW_64K"{hw}", OpalG711uLaw)
1352 DEFINE_LID_CAPABILITY(H323_LID_G728_Capability, OPAL_G728"{hw}", OpalG728)
1353 DEFINE_LID_CAPABILITY(H323_LID_GSM0610_Capability, OPAL_GSM0610"{hw}", OpalGSM0610)
1354 DEFINE_LID_CAPABILITY(H323_LID_G729_Capability, OPAL_G729"{hw}", OpalG729)
1355 DEFINE_LID_CAPABILITY(H323_LID_G729A_Capability, OPAL_G729A"{hw}", OpalG729A)
1356 DEFINE_LID_CAPABILITY(H323_LID_G729B_Capability, OPAL_G729B"{hw}", OpalG729B)
1357 DEFINE_LID_CAPABILITY(H323_LID_G729AB_Capability, OPAL_G729AB"{hw}", OpalG729AB)
1358 DEFINE_LID_CAPABILITY(H323_LID_G7231_6k3_Capability, OPAL_G7231_6k3"{hw}", OpalG7231_6k3)
1359 DEFINE_LID_CAPABILITY(H323_LID_G7231_5k3_Capability, OPAL_G7231_5k3"{hw}", OpalG7231_5k3)
1360 DEFINE_LID_CAPABILITY(H323_LID_G7231A_6k3_Capability, OPAL_G7231A_6k3"{hw}", OpalG7231A_6k3)
1361 DEFINE_LID_CAPABILITY(H323_LID_G7231A_5k3_Capability, OPAL_G7231A_5k3"{hw}", OpalG7231A_5k3)
1363 #define G7231_CISCO OPAL_G7231A_6k3"-Cisco{hw}"
1364 H323_REGISTER_CAPABILITY(H323_CiscoG7231aLIDCapability, G7231_CISCO)
1366 /////////////////////////////////////////////////////////////////////////////
1368 OpalLineChannel::OpalLineChannel(OpalLineInterfaceDevice & dev,
1369 unsigned line,
1370 const H323AudioCodec & codec)
1371 : device(dev)
1373 lineNumber = line;
1374 reading = codec.GetDirection() == H323Codec::Encoder;
1375 OpalMediaFormat mediaFormat = OpalPCM16;
1377 if (PIsDescendant(&codec, H323_LIDCodec)) {
1378 OpalMediaFormat::List mediaFormats = device.GetMediaFormats();
1379 for (PINDEX i = 0; i < mediaFormats.GetSize(); i++) {
1380 if (mediaFormats[i] == codec.GetMediaFormat())
1381 mediaFormat = codec.GetMediaFormat();
1385 if (reading) {
1386 if (!device.SetReadFormat(lineNumber, mediaFormat))
1387 return;
1388 useDeblocking = mediaFormat.GetFrameSize() != device.GetReadFrameSize(lineNumber);
1390 else {
1391 if (!device.SetWriteFormat(lineNumber, mediaFormat))
1392 return;
1393 useDeblocking = mediaFormat.GetFrameSize() != device.GetWriteFrameSize(lineNumber);
1396 PTRACE(3, "LID\tCodec set to " << mediaFormat << ", frame size: rd="
1397 << device.GetReadFrameSize(lineNumber) << " wr="
1398 << device.GetWriteFrameSize(lineNumber) << ", "
1399 << (useDeblocking ? "needs" : "no") << " reblocking.");
1400 os_handle = 1;
1404 OpalLineChannel::~OpalLineChannel()
1406 Close();
1410 PString OpalLineChannel::GetName() const
1412 return device.GetName() + psprintf("-%u", lineNumber);
1416 BOOL OpalLineChannel::Close()
1418 if (!IsOpen())
1419 return FALSE;
1421 os_handle = -1;
1423 if (reading)
1424 return device.StopReadCodec(lineNumber);
1425 else
1426 return device.StopWriteCodec(lineNumber);
1430 BOOL OpalLineChannel::Read(void * buffer, PINDEX length)
1432 lastReadCount = 0;
1434 if (!reading)
1435 return SetErrorValues(Miscellaneous, EINVAL, LastReadError);
1437 if (useDeblocking) {
1438 device.SetReadFrameSize(lineNumber, length);
1439 if (device.ReadBlock(lineNumber, buffer, length)) {
1440 lastReadCount = length;
1441 return TRUE;
1444 else {
1445 if (device.ReadFrame(lineNumber, buffer, lastReadCount))
1446 return TRUE;
1449 int osError = device.GetErrorNumber();
1450 PTRACE_IF(1, osError != 0, "LID\tDevice read frame error: " << device.GetErrorText());
1452 return SetErrorValues(Miscellaneous, osError, LastReadError);
1456 BOOL OpalLineChannel::Write(const void * buffer, PINDEX length)
1458 lastWriteCount = 0;
1460 if (reading)
1461 return SetErrorValues(Miscellaneous, EINVAL, LastWriteError);
1463 if (useDeblocking) {
1464 device.SetWriteFrameSize(lineNumber, length);
1465 if (device.WriteBlock(lineNumber, buffer, length)) {
1466 lastWriteCount = length;
1467 return TRUE;
1470 else {
1471 if (device.WriteFrame(lineNumber, buffer, length, lastWriteCount))
1472 return TRUE;
1475 int osError = device.GetErrorNumber();
1476 PTRACE_IF(1, osError != 0, "LID\tDevice write frame error: " << device.GetErrorText());
1478 return SetErrorValues(Miscellaneous, osError, LastWriteError);
1482 ///////////////////////////////////////////////////////////////////////////////
1484 void H323_LIDCapability::AddAllCapabilities(const OpalLineInterfaceDevice & device,
1485 H323Capabilities & capabilities,
1486 PINDEX descriptorNum,
1487 PINDEX simultaneous)
1489 OpalMediaFormat::List codecsAvailable = device.GetMediaFormats();
1490 for (PINDEX c = 0; c < codecsAvailable.GetSize(); c++) {
1491 H323_LIDCapability * cap = new H323_LIDCapability(codecsAvailable[c]);
1492 if (cap->IsValid() && !capabilities.FindCapability(*cap))
1493 capabilities.SetCapability(descriptorNum, simultaneous, cap);
1494 else
1495 delete cap;
1496 if (codecsAvailable[c] == OpalG7231A_6k3)
1497 capabilities.SetCapability(descriptorNum, simultaneous,
1498 new H323_CiscoG7231aLIDCapability);
1503 H323_LIDCapability::H323_LIDCapability(const OpalMediaFormat & fmt)
1504 : H323AudioCapability(0, 0),
1505 mediaFormat(fmt)
1507 codecTableIndex = 0;
1509 while (IsValid()) {
1510 if (mediaFormat == CodecTypeInfo[codecTableIndex].name) {
1511 rxFramesInPacket = CodecTypeInfo[codecTableIndex].rxFramesInPacket;
1512 txFramesInPacket = CodecTypeInfo[codecTableIndex].txFramesInPacket;
1513 break;
1516 codecTableIndex++;
1521 BOOL H323_LIDCapability::IsValid() const
1523 return codecTableIndex < PARRAYSIZE(CodecTypeInfo);
1527 PObject::Comparison H323_LIDCapability::Compare(const PObject & obj) const
1529 if (!PIsDescendant(&obj, H323_LIDCapability))
1530 return LessThan;
1532 Comparison result = H323AudioCapability::Compare(obj);
1533 if (result != EqualTo)
1534 return result;
1536 PINDEX otherIndex = ((const H323_LIDCapability &)obj).codecTableIndex;
1537 if (CodecTypeInfo[codecTableIndex].g7231annexA < CodecTypeInfo[otherIndex].g7231annexA)
1538 return LessThan;
1539 if (CodecTypeInfo[codecTableIndex].g7231annexA > CodecTypeInfo[otherIndex].g7231annexA)
1540 return GreaterThan;
1541 return EqualTo;
1545 PObject * H323_LIDCapability::Clone() const
1547 return new H323_LIDCapability(*this);
1551 PString H323_LIDCapability::GetFormatName() const
1553 return mediaFormat + "{hw}";
1557 unsigned H323_LIDCapability::GetSubType() const
1559 return CodecTypeInfo[codecTableIndex].capabilitySubtype;
1563 H323Codec * H323_LIDCapability::CreateCodec(H323Codec::Direction direction) const
1565 return new H323_LIDCodec(mediaFormat,
1566 direction,
1567 direction == H323Codec::Encoder ? txFramesInPacket : rxFramesInPacket,
1568 codecTableIndex);
1572 BOOL H323_LIDCapability::OnSendingPDU(H245_AudioCapability & pdu,
1573 unsigned packetSize) const
1575 pdu.SetTag(GetSubType());
1577 switch (pdu.GetTag()) {
1578 case H245_AudioCapability::e_gsmFullRate :
1580 H245_GSMAudioCapability & gsm = pdu;
1581 gsm.m_audioUnitSize = packetSize*33;
1582 break;
1584 case H245_AudioCapability::e_g7231 :
1586 H245_AudioCapability_g7231 & g7231 = pdu;
1587 g7231.m_maxAl_sduAudioFrames = packetSize;
1588 g7231.m_silenceSuppression = CodecTypeInfo[codecTableIndex].g7231annexA;
1589 break;
1591 default :
1593 PASN_Integer & value = pdu;
1594 value = packetSize;
1598 return TRUE;
1602 BOOL H323_LIDCapability::OnReceivedPDU(const H245_AudioCapability & pdu,
1603 unsigned & packetSize)
1605 if (pdu.GetTag() != GetSubType())
1606 return FALSE;
1608 switch (pdu.GetTag()) {
1609 case H245_AudioCapability::e_gsmFullRate :
1611 const H245_GSMAudioCapability & gsm = pdu;
1612 packetSize = gsm.m_audioUnitSize/33;
1613 break;
1615 case H245_AudioCapability::e_g7231 :
1617 const H245_AudioCapability_g7231 & g7231 = pdu;
1618 packetSize = g7231.m_maxAl_sduAudioFrames;
1620 BOOL g7231annexA = g7231.m_silenceSuppression;
1621 if (g7231annexA != CodecTypeInfo[codecTableIndex].g7231annexA) {
1622 // Move to the other G.723.1 version
1623 codecTableIndex += (g7231annexA ? -2 : 2);
1624 mediaFormat = CodecTypeInfo[codecTableIndex].name;
1626 break;
1628 default :
1630 const PASN_Integer & value = pdu;
1631 packetSize = value;
1635 return TRUE;
1639 /////////////////////////////////////////////////////////////////////////////
1641 H323_CiscoG7231aLIDCapability::H323_CiscoG7231aLIDCapability()
1642 : H323NonStandardAudioCapability(1, 1, 181, 0, 18, (const BYTE*)"G7231ar", 7)
1647 PObject * H323_CiscoG7231aLIDCapability::Clone() const
1649 return new H323_CiscoG7231aLIDCapability(*this);
1653 PString H323_CiscoG7231aLIDCapability::GetFormatName() const
1655 return G7231_CISCO;
1659 H323Codec * H323_CiscoG7231aLIDCapability::CreateCodec(H323Codec::Direction direction) const
1661 return new H323_LIDCodec(OpalG7231A_6k3, direction, 1, G7231A_63_INDEX);
1665 /////////////////////////////////////////////////////////////////////////////
1667 H323_LIDCodec::H323_LIDCodec(const char * fmt,
1668 Direction direction,
1669 unsigned numFrames,
1670 PINDEX index)
1671 : H323AudioCodec(fmt, direction)
1673 codecTableIndex = index;
1674 packetSize = CodecTypeInfo[index].bytesPerFrame;
1676 /* Special case for G.711 encoder, note this helps with optimisation of
1677 sound data but will break if remote does not send the maximum number of
1678 bytes that it said it could. It is legal for the remote end to do so
1679 though no endpoints seem to actually do that.
1681 if (packetSize == 8) {
1682 packetSize *= numFrames;
1683 samplesPerFrame *= numFrames;
1686 missedCount = 0;
1687 lastSID[0] = 2;
1688 lastFrameWasSignal = TRUE;
1690 PTRACE(3, "LID\tCreated codec: pt=" << mediaFormat.GetPayloadType()
1691 << ", bytes=" << packetSize << ", samples=" << mediaFormat.GetFrameTime());
1695 BOOL H323_LIDCodec::Read(BYTE * buffer, unsigned & length, RTP_DataFrame &)
1697 PWaitAndSignal mutex(rawChannelMutex);
1699 // This reads to an H323_IxJChannel class
1700 PINDEX count;
1701 if (!ReadRaw(buffer, packetSize, count))
1702 return FALSE;
1704 // In the case of G.723.1 remember the last SID frame we sent and send
1705 // it again if the hardware sends us a CNG frame.
1706 if (mediaFormat.GetPayloadType() == RTP_DataFrame::G7231) {
1707 switch (count) {
1708 case 1 : // CNG frame
1709 memcpy(buffer, lastSID, 4);
1710 count = 4;
1711 lastFrameWasSignal = FALSE;
1712 break;
1713 case 4 :
1714 if ((*buffer&3) == 2)
1715 memcpy(lastSID, buffer, 4);
1716 lastFrameWasSignal = FALSE;
1717 break;
1718 default :
1719 lastFrameWasSignal = TRUE;
1723 length = DetectSilence() ? 0 : count;
1724 return TRUE;
1728 BOOL H323_LIDCodec::Write(const BYTE * buffer,
1729 unsigned length,
1730 const RTP_DataFrame & /*frame*/,
1731 unsigned & written)
1733 // This writes to an H323_IxJChannel class
1734 if (length > packetSize)
1735 length = packetSize;
1737 // Check for writing silence
1738 PBYTEArray silenceBuffer;
1739 if (length != 0)
1740 missedCount = 0;
1741 else {
1742 switch (mediaFormat.GetPayloadType()) {
1743 case RTP_DataFrame::G7231 :
1744 if (missedCount++ < 4) {
1745 static const BYTE g723_erasure_frame[24] = { 0xff, 0xff, 0xff, 0xff };
1746 buffer = g723_erasure_frame;
1747 length = 24;
1749 else {
1750 static const BYTE g723_cng_frame[4] = { 3 };
1751 buffer = g723_cng_frame;
1752 length = 1;
1754 break;
1756 case RTP_DataFrame::PCMU :
1757 case RTP_DataFrame::PCMA :
1758 buffer = silenceBuffer.GetPointer(packetSize);
1759 memset((void *)buffer, 0xff, packetSize);
1760 length = packetSize;
1761 break;
1763 case RTP_DataFrame::G729 :
1764 if (mediaFormat.Find('B') != P_MAX_INDEX) {
1765 static const BYTE g729_sid_frame[2] = { 1 };
1766 buffer = g729_sid_frame;
1767 length = 2;
1768 break;
1770 // Else fall into default case
1772 default :
1773 buffer = silenceBuffer.GetPointer(packetSize); // Fills with zeros
1774 length = packetSize;
1775 break;
1779 PWaitAndSignal mutex(rawChannelMutex);
1781 if (!rawDataChannel->Write(buffer, length))
1782 return FALSE;
1784 written = rawDataChannel->GetLastWriteCount();
1785 return TRUE;
1789 BOOL H323_LIDCodec::IsRawDataChannelNative() const
1791 return TRUE;
1795 BOOL H323_LIDCodec::DetectSilence()
1797 // Can never have silence if NoSilenceDetection
1798 if (silenceDetectMode == NoSilenceDetection)
1799 return FALSE;
1801 if (!CodecTypeInfo[codecTableIndex].g7231annexA)
1802 return H323AudioCodec::DetectSilence();
1804 // Utilise the codecs own silence detection algorithm
1806 // If no change ie still talking or still silent, resent frame counter
1807 if (inTalkBurst == lastFrameWasSignal)
1808 framesReceived = 0;
1809 else {
1810 framesReceived++;
1811 // If have had enough consecutive frames talking/silent, swap modes.
1812 if (framesReceived >= (inTalkBurst ? silenceDeadbandFrames : signalDeadbandFrames)) {
1813 inTalkBurst = !inTalkBurst;
1814 PTRACE(4, "Codec\tSilence detection transition: "
1815 << (inTalkBurst ? "Talk" : "Silent"));
1819 return !inTalkBurst;
1823 unsigned H323_LIDCodec::GetAverageSignalLevel()
1825 PWaitAndSignal mutex(rawChannelMutex);
1827 return ((OpalLineChannel*)rawDataChannel)->GetDevice().GetAverageSignalLevel(0, direction == Decoder);
1831 /////////////////////////////////////////////////////////////////////////////