4 * A simple H.323 "net telephone" application.
6 * Copyright (c) 2000 Equivalence Pty. Ltd.
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15 * the License for the specific language governing rights and limitations
18 * The Original Code is Portable Windows Library.
20 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
22 * Contributor(s): ______________________________________.
25 * Revision 2.87 2007/04/10 05:15:54 rjongbloed
26 * Fixed issue with use of static C string variables in DLL environment,
27 * must use functional interface for correct initialisation.
29 * Revision 2.86 2007/04/03 13:04:23 rjongbloed
30 * Added driverName to PVideoDevice::OpenArgs (so can select YUVFile)
31 * Added new statics to create correct video input/output device object
32 * given a PVideoDevice::OpenArgs structure.
33 * Fixed incorrect initialisation of default video input device.
34 * Fixed last calls video size changing the default value.
36 * Revision 2.85 2007/04/03 07:59:14 rjongbloed
37 * Warning: API change to PCSS callbacks:
38 * changed return on OnShowIncoming to BOOL, now agrees with
39 * documentation and allows UI to abort calls early.
40 * added BOOL to AcceptIncomingConnection indicating the
41 * supplied token is invalid.
42 * removed redundent OnGetDestination() function, was never required.
44 * Revision 2.84 2007/04/03 05:27:30 rjongbloed
45 * Cleaned up somewhat confusing usage of the OnAnswerCall() virtual
46 * function. The name is innaccurate and exists as a legacy from the
47 * OpenH323 days. it now only indicates how alerting is done
48 * (with/without media) and does not actually answer the call.
50 * Revision 2.83 2007/03/29 08:32:22 csoutheren
51 * Pause before dialing when using two endpoint mode
53 * Revision 2.82 2007/03/29 05:24:00 csoutheren
54 * Add support for T.38
56 * Revision 2.81 2007/03/01 05:07:32 csoutheren
57 * Only include video code when video enabled
59 * Revision 2.80 2006/11/01 00:46:40 csoutheren
60 * Implement video output file device
62 * Revision 2.79 2006/10/31 04:41:47 csoutheren
63 * Add support for new methods needed for vidfiledevices
65 * Revision 2.78 2006/10/28 00:39:42 rjongbloed
66 * Added argument to set country on LID
68 * Revision 2.77 2006/10/22 12:09:57 rjongbloed
69 * Fixed minor error in user output string.
71 * Revision 2.76 2006/10/15 06:12:48 rjongbloed
72 * Fixed correct local A-Party endpoint type depending on compiler flags and command line arguments.
73 * Fixed being able to select IVR via wildcard (routing table order) on source endpoint type.
74 * Fixed correctly trimming spaces from POTS device name.
76 * Revision 2.75 2006/10/10 07:18:18 csoutheren
77 * Allow compilation with and without various options
79 * Revision 2.74 2006/10/05 07:11:49 csoutheren
80 * Add --disable-lid option
82 * Revision 2.73 2006/10/02 13:30:51 rjongbloed
85 * Revision 2.72 2006/08/29 01:37:11 csoutheren
86 * Change secure URLs to use h323s and tcps to be inline with sips
88 * Revision 2.71 2006/08/21 05:30:48 csoutheren
89 * Add support for sh323
91 * Revision 2.70 2006/08/01 12:46:32 rjongbloed
92 * Added build solution for plug ins
93 * Removed now redundent code due to plug ins addition
95 * Revision 2.69 2006/07/24 14:03:39 csoutheren
96 * Merged in audio and video plugins from CVS branch PluginBranch
98 * Revision 2.68 2006/07/21 00:38:31 csoutheren
99 * Applied 1483215 - Opal simpleOPAL deadlock patch & DTMF support
102 * Revision 2.67 2006/07/03 03:28:44 dereksmithies
103 * Fix arg handling on disableui, and look for args to srcep, not srcEp
105 * Revision 2.66 2006/06/26 02:03:07 csoutheren
106 * Fixed problem when no TTS code installed
108 * Revision 2.65 2006/06/05 05:26:39 csoutheren
109 * Added ability to test outgoing SIP INFO messages
111 * Revision 2.64 2006/04/30 14:42:00 dereksmithies
112 * Fix compile Sleep statement so it compiles on unix.
114 * Revision 2.63 2006/04/30 14:36:54 csoutheren
115 * backports from PLuginBranch
117 * Revision 2.62 2006/04/30 14:34:42 csoutheren
118 * Backport of IVR updates from PluginBranch
120 * Revision 2.60.2.4 2006/04/30 14:28:25 csoutheren
121 * Added disableui and srcep options
123 * Revision 2.60.2.3 2006/04/30 13:50:29 csoutheren
124 * Add ability to set TextToSpeech algorithm
125 * Revision 2.60.2.2 2006/04/10 08:54:11 csoutheren
126 * Fix problem when H323 disabled
128 * Revision 2.60.2.1 2006/03/20 02:25:26 csoutheren
129 * Backports from CVS head
131 * Revision 2.61 2006/03/07 11:24:15 csoutheren
132 * Add --disable-grq flag
134 * Revision 2.60 2006/01/23 22:56:57 csoutheren
135 * Added 2 second pause before dialling outgoing SIP calls from command line args when
138 * Revision 2.59 2005/12/11 19:14:21 dsandras
139 * Added support for setting a different user name and authentication user name
140 * as required by some providers like digisip.
142 * Revision 2.58 2005/11/07 02:27:48 dereksmithies
143 * Get the answer call Y/N mechanism to work correctly.
145 * Revision 2.57 2005/09/06 04:58:42 dereksmithies
146 * Add console input options. This is an initial release, and some "refinement"
149 * Revision 2.56 2005/08/20 09:03:10 rjongbloed
150 * Some cosmetic fixes in output messages
152 * Revision 2.55 2005/08/13 09:16:18 rjongbloed
153 * Added no-Xt-video to "usage" output
155 * Revision 2.54 2005/08/04 08:47:38 rjongbloed
156 * Some cosmetic changes, and print out the codecs that are available
158 * Revision 2.53 2005/07/30 07:42:15 csoutheren
159 * Added IAX2 functions
161 * Revision 2.52 2005/07/24 07:56:35 rjongbloed
162 * Removed -l parameter, as it always listens.
164 * Revision 2.51 2005/07/11 01:57:31 csoutheren
165 * Fixed error message
167 * Revision 2.50 2005/06/23 06:14:02 csoutheren
168 * Fixed rtp-tos argument parsing. Thanks to Paul Nader
170 * Revision 2.49 2005/06/09 04:51:58 dereksmithies
173 * Revision 2.48 2005/06/09 04:45:57 dereksmithies
174 * Correctly close the incoming connection if the user rejects the incoming call.
175 * Thanks to Robert Jongbloed for some helpful advice.
177 * Revision 2.47 2005/03/11 18:12:09 dsandras
178 * Added support to specify the realm when registering. That way softphones already know what authentication information to use when required. The realm/domain can also be used in the From field.
180 * Revision 2.46 2005/02/19 22:46:19 dsandras
181 * Temporarily removed support for SetDomain.
183 * Revision 2.45 2004/11/29 08:20:04 csoutheren
184 * Added support for setting SIP authentication domain
186 * Revision 2.44 2004/08/18 07:14:00 csoutheren
187 * Called ancestor OnClearedCall
189 * Revision 2.43 2004/08/14 07:56:30 rjongbloed
190 * Major revision to utilise the PSafeCollection classes for the connections and calls.
192 * Revision 2.42 2004/04/26 07:06:07 rjongbloed
193 * Removed some ancient pieces of code and used new API's for them.
195 * Revision 2.41 2004/04/26 06:33:18 rjongbloed
196 * Added ability to specify more than one defualt listener for an endpoint,
197 * required by SIP which listens on both UDP and TCP.
199 * Revision 2.40 2004/04/25 09:32:48 rjongbloed
200 * Fixed correct usage of HAS_IXJ
202 * Revision 2.39 2004/03/29 10:53:23 rjongbloed
203 * Fixed missing mutex unlock which would invariably cause a deadlock.
205 * Revision 2.38 2004/03/22 10:20:34 rjongbloed
206 * Changed to use UseGatekeeper() function so can select by gk-id as well as host.
208 * Revision 2.37 2004/03/14 11:32:20 rjongbloed
209 * Changes to better support SIP proxies.
211 * Revision 2.36 2004/03/14 08:34:09 csoutheren
212 * Added ability to set User-Agent string
214 * Revision 2.35 2004/03/14 06:15:36 rjongbloed
215 * Must set ports before stun as stun code uses those port numbers.
217 * Revision 2.34 2004/03/13 06:32:17 rjongbloed
218 * Fixes for removal of SIP and H.323 subsystems.
219 * More registration work.
221 * Revision 2.33 2004/03/11 06:54:27 csoutheren
222 * Added ability to disable SIP or H.323 stacks
224 * Revision 2.32 2004/03/09 12:09:56 rjongbloed
225 * More work on SIP register.
227 * Revision 2.31 2004/02/24 11:37:01 rjongbloed
228 * More work on NAT support, manual external address translation and STUN
230 * Revision 2.30 2004/02/21 02:41:10 rjongbloed
231 * Tidied up the translate address to utilise more of the library infrastructure.
232 * Changed cmd line args port-base/port-max to portbase/portmax, same as OhPhone.
234 * Revision 2.29 2004/02/17 11:00:06 csoutheren
235 * Added --translate, --port-base and --port-max options
237 * Revision 2.28 2004/02/03 12:22:28 rjongbloed
240 * Revision 2.27 2004/01/18 15:36:07 rjongbloed
243 * Revision 2.26 2003/04/09 01:38:27 robertj
244 * Changed default to not send/receive video and added options to turn it on.
246 * Revision 2.25 2003/03/26 03:51:46 robertj
247 * Fixed failure to compile if not statically linked.
249 * Revision 2.24 2003/03/24 07:18:29 robertj
250 * Added registration system for LIDs so can work with various LID types by
251 * name instead of class instance.
253 * Revision 2.23 2003/03/19 02:30:45 robertj
254 * Added removal of IVR stuff if EXPAT is not installed on system.
256 * Revision 2.22 2003/03/17 08:12:08 robertj
257 * Added protocol name to media stream open output.
259 * Revision 2.21 2003/03/07 08:18:47 robertj
260 * Fixed naming convention of PC sound system in routing table.
262 * Revision 2.20 2003/03/07 05:56:47 robertj
263 * Changed so a # from whatever source routes to IVR.
265 * Revision 2.19 2003/03/06 03:57:47 robertj
266 * IVR support (work in progress) requiring large changes everywhere.
268 * Revision 2.18 2002/11/11 06:52:01 robertj
269 * Added correct flag for including static global variables.
271 * Revision 2.17 2002/11/10 11:33:17 robertj
272 * Updated to OpenH323 v1.10.3
274 * Revision 2.16 2002/09/06 02:46:00 robertj
275 * Added routing table system to route calls by regular expressions.
276 * Added ability to set gatekeeper access token OID and password.
278 * Revision 2.15 2002/07/01 09:05:54 robertj
279 * Changed TCp/UDP port allocation to use new thread safe functions.
281 * Revision 2.14 2002/04/12 14:02:41 robertj
282 * Separated interface option for SIP and H.323.
284 * Revision 2.13 2002/03/27 05:34:55 robertj
285 * Removed redundent busy forward field.
286 * Added ability to set tcp and udp port bases.
288 * Revision 2.12 2002/03/27 04:36:46 robertj
289 * Changed to add all possible xJack cards to pots endpoint.
291 * Revision 2.11 2002/03/27 04:16:20 robertj
292 * Restructured default router for sample to allow more options.
294 * Revision 2.10 2002/02/13 08:17:31 robertj
295 * Changed routing algorithm to route call to H323/SIP if contains an '@'
297 * Revision 2.9 2002/02/11 09:45:35 robertj
298 * Moved version file to library root directoy
300 * Revision 2.8 2002/02/06 13:29:03 rogerh
301 * H245 tunnelling is controlled by 'T' and not by 'h'
303 * Revision 2.7 2002/02/01 04:53:01 robertj
304 * Added (very primitive!) SIP support.
306 * Revision 2.6 2002/01/22 05:34:58 robertj
307 * Revamp of user input API triggered by RFC2833 support
309 * Revision 2.5 2001/08/21 11:18:55 robertj
310 * Added conditional compile for xJack code.
312 * Revision 2.4 2001/08/17 08:35:41 robertj
313 * Changed OnEstablished() to OnEstablishedCall() to be consistent.
314 * Moved call end reasons enum from OpalConnection to global.
315 * Used LID management in lid EP.
316 * More implementation.
318 * Revision 2.3 2001/08/01 06:19:00 robertj
319 * Added flags for disabling H.323 or Quicknet endpoints.
321 * Revision 2.2 2001/08/01 05:48:30 robertj
322 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
323 * Fixed loading of transcoders from static library.
325 * Revision 2.1 2001/07/30 07:22:25 robertj
326 * Abstracted listener management from H.323 to OpalEndPoint class.
328 * Revision 2.0 2001/07/27 15:48:24 robertj
329 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
331 * Revision 1.12 2001/07/13 08:44:16 robertj
332 * Fixed incorrect inclusion of hardware codec capabilities.
334 * Revision 1.11 2001/05/17 07:11:29 robertj
335 * Added more call end types for common transport failure modes.
337 * Revision 1.10 2001/05/14 05:56:26 robertj
338 * Added H323 capability registration system so can add capabilities by
339 * string name instead of having to instantiate explicit classes.
341 * Revision 1.9 2001/03/21 04:52:40 robertj
342 * Added H.235 security to gatekeepers, thanks Fürbass Franz!
344 * Revision 1.8 2001/03/20 23:42:55 robertj
345 * Used the new PTrace::Initialise function for starting trace code.
347 * Revision 1.7 2000/10/16 08:49:31 robertj
348 * Added single function to add all UserInput capability types.
350 * Revision 1.6 2000/07/31 14:08:09 robertj
351 * Added fast start and H.245 tunneling flags to the H323Connection constructor so can
352 * disabled these features in easier manner to overriding virtuals.
354 * Revision 1.5 2000/06/20 02:38:27 robertj
355 * Changed H323TransportAddress to default to IP.
357 * Revision 1.4 2000/06/07 05:47:55 robertj
358 * Added call forwarding.
360 * Revision 1.3 2000/05/23 11:32:27 robertj
361 * Rewrite of capability table to combine 2 structures into one and move functionality into that class
362 * allowing some normalisation of usage across several applications.
363 * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
364 * to be done depending on the remote client application.
366 * Revision 1.2 2000/05/11 10:00:02 robertj
367 * Fixed setting and resetting of current call token variable.
369 * Revision 1.1 2000/05/11 04:05:57 robertj
370 * Simple sample program.
376 #include <opal/buildopts.h>
379 #include <iax2/iax2.h>
387 #include <h323/h323.h>
388 #include <h323/gkclient.h>
391 #include <t38/t38proto.h>
393 #include <opal/transcoders.h>
394 #include <lids/lidep.h>
395 #include <ptclib/pstun.h>
396 #include <ptlib/config.h>
399 #include "../../version.h"
405 PCREATE_PROCESS(SimpleOpalProcess
);
407 ///////////////////////////////////////////////////////////////
409 SimpleOpalProcess::SimpleOpalProcess()
410 : PProcess("Open Phone Abstraction Library", "SimpleOPAL",
411 MAJOR_VERSION
, MINOR_VERSION
, BUILD_TYPE
, BUILD_NUMBER
)
416 void SimpleOpalProcess::Main()
419 << " Version " << GetVersion(TRUE
)
420 << " by " << GetManufacturer()
421 << " on " << GetOSClass() << ' ' << GetOSName()
422 << " (" << GetOSVersion() << '-' << GetOSHardware() << ")\n\n";
424 // Get and parse all of the command line arguments.
425 PArgList
& args
= GetArguments();
462 "R-require-gatekeeper."
478 "T-h245tunneldisable."
491 "-rx-video." "-no-rx-video."
492 "-tx-video." "-no-tx-video."
508 if (args
.HasOption('h') || (!args
.HasOption('l') && args
.GetCount() == 0)) {
509 cout
<< "Usage : " << GetName() << " [options] -l\n"
510 " : " << GetName() << " [options] [alias@]hostname (no gatekeeper)\n"
511 " : " << GetName() << " [options] alias[@hostname] (with gatekeeper)\n"
513 " -l --listen : Listen for incoming calls.\n"
514 " -d --dial-peer spec : Set dial peer for routing calls (see below)\n"
515 " --no-std-dial-peer : Do not include the standard dial peers\n"
516 " -a --auto-answer : Automatically answer incoming calls.\n"
517 " -u --user name : Set local alias name(s) (defaults to login name).\n"
518 " -p --password pwd : Set password for user (gk or SIP authorisation).\n"
519 " -D --disable media : Disable the specified codec (may be used multiple times)\n"
520 " -P --prefer media : Prefer the specified codec (may be used multiple times)\n"
521 " --srcep ep : Set the source endpoint to use for making calls\n"
522 " --disableui : disable the user interface\n"
525 " -j --jitter [min-]max : Set minimum (optional) and maximum jitter buffer (in milliseconds).\n"
526 " -e --silence : Disable transmitter silence detection.\n"
529 " --rx-video : Start receiving video immediately.\n"
530 " --tx-video : Start transmitting video immediately.\n"
531 " --no-rx-video : Don't start receiving video immediately.\n"
532 " --no-tx-video : Don't start transmitting video immediately.\n"
533 " --grabber dev : Set the video grabber device.\n"
534 " --grabdriver dev : Set the video grabber driver (if device name is ambiguous).\n"
535 " --grabchannel num : Set the video grabber device channel.\n"
536 " --display dev : Set the video display device.\n"
537 " --displaydriver dev : Set the video display driver (if device name is ambiguous).\n"
542 " -I --no-sip : Disable SIP protocol.\n"
543 " -r --register-sip host : Register with SIP server.\n"
544 " --sip-proxy url : SIP proxy information, may be just a host name\n"
545 " : or full URL eg sip:user:pwd@host\n"
546 " --sip-listen iface : Interface/port(s) to listen for SIP requests\n"
547 " : '*' is all interfaces, (default udp$:*:5060)\n"
548 " --sip-user-agent name: SIP UserAgent name to use.\n"
549 " --sip-ui type : Set type of user indications to use for SIP. Can be one of 'rfc2833', 'info-tone', 'info-string'.\n"
550 " --use-long-mime : Use long MIME headers on outgoing SIP messages\n"
551 " --sip-domain str : set authentication domain/realm\n"
557 " -H --no-h323 : Disable H.323 protocol.\n"
558 " -g --gatekeeper host : Specify gatekeeper host.\n"
559 " -G --gk-id name : Specify gatekeeper identifier.\n"
560 " -n --no-gatekeeper : Disable gatekeeper discovery.\n"
561 " -R --require-gatekeeper : Exit if gatekeeper discovery fails.\n"
562 " --gk-token str : Set gatekeeper security token OID.\n"
563 " -b --bandwidth bps : Limit bandwidth usage to bps bits/second.\n"
564 " -f --fast-disable : Disable fast start.\n"
565 " -T --h245tunneldisable : Disable H245 tunnelling.\n"
566 " --h323-listen iface : Interface/port(s) to listen for H.323 requests\n"
568 " --h323s-listen iface : Interface/port(s) to listen for secure H.323 requests\n"
570 " : '*' is all interfaces, (default tcp$:*:1720)\n"
571 " --disable-grq : Do not send GRQ when registering with GK\n"
573 " --no-h323s : Do not creat secure H.323 endpoint\n"
579 "Line Interface options:\n"
580 " -L --no-lid : Do not use line interface device.\n"
581 " --lid device : Select line interface device (eg Quicknet:013A17C2, default *:*).\n"
582 " --country code : Select country to use for LID (eg \"US\", \"au\" or \"+61\").\n"
585 "Sound card options:\n"
586 " -S --no-sound : Do not use sound input/output device.\n"
587 " -s --sound device : Select sound input/output device.\n"
588 " --sound-in device : Select sound input device.\n"
589 " --sound-out device : Select sound output device.\n"
593 " -V --no-ivr : Disable IVR.\n"
594 " -x --vxml file : Set vxml file to use for IVR.\n"
595 " --tts engine : Set the text to speech engine\n"
599 " --translate ip : Set external IP address if masqueraded\n"
600 " --portbase n : Set TCP/UDP/RTP port base\n"
601 " --portmax n : Set TCP/UDP/RTP port max\n"
602 " --tcp-base n : Set TCP port base (default 0)\n"
603 " --tcp-max n : Set TCP port max (default base+99)\n"
604 " --udp-base n : Set UDP port base (default 6000)\n"
605 " --udp-max n : Set UDP port max (default base+199)\n"
606 " --rtp-base n : Set RTP port base (default 5000)\n"
607 " --rtp-max n : Set RTP port max (default base+199)\n"
608 " --rtp-tos n : Set RTP packet IP TOS bits to n\n"
609 " --stun server : Set STUN server\n"
613 " -t --trace : Enable trace, use multiple times for more detail.\n"
614 " -o --output : File for trace output, default is stderr.\n"
617 " -X --no-iax2 : Remove support for iax2\n"
619 " -h --help : This help message.\n"
622 "Dial peer specification:\n"
623 " General form is pattern=destination where pattern is a regular expression\n"
624 " matching the incoming calls destination address and will translate it to\n"
625 " the outgoing destination address for making an outgoing call. For example,\n"
626 " picking up a PhoneJACK handset and dialling 2, 6 would result in an address\n"
627 " of \"pots:26\" which would then be matched against, say, a spec of\n"
628 " pots:26=h323:10.0.1.1, resulting in a call from the pots handset to\n"
629 " 10.0.1.1 using the H.323 protocol.\n"
631 " As the pattern field is a regular expression, you could have used in the\n"
632 " above .*:26=h323:10.0.1.1 to achieve the same result with the addition that\n"
633 " an incoming call from a SIP client would also be routed to the H.323 client.\n"
635 " Note that the pattern has an implicit ^ and $ at the beginning and end of\n"
636 " the regular expression. So it must match the entire address.\n"
638 " If the specification is of the form @filename, then the file is read with\n"
639 " each line consisting of a pattern=destination dial peer specification. Lines\n"
640 " without and equal sign or beginning with '#' are ignored.\n"
642 " The standard dial peers that will be included are:\n"
643 " If SIP is enabled but H.323 & IAX2 are disabled:\n"
644 " pots:.*\\*.*\\*.* = sip:<dn2ip>\n"
645 " pots:.* = sip:<da>\n"
646 " pc:.* = sip:<da>\n"
648 " If SIP & IAX2 are not enabled and H.323 is enabled:\n"
649 " pots:.*\\*.*\\*.* = h323:<dn2ip>\n"
650 " pots:.* = h323:<da>\n"
651 " pc:.* = h323:<da>\n"
653 " If POTS is enabled:\n"
654 " h323:.* = pots:<da>\n"
655 " sip:.* = pots:<da>\n"
656 " iax2:.* = pots:<da>\n"
658 " If POTS is not enabled and the PC sound system is enabled:\n"
659 " iax2:.* = pc:<da>\n"
660 " h323:.* = pc:<da>\n"
661 " sip:. * = pc:<da>\n"
664 " If IVR is enabled then a # from any protocol will route it it, ie:\n"
669 " If IAX2 is enabled then you can make a iax2 call with a command like:\n"
670 " simpleopal -IHn iax2:guest@misery.digium.com/s\n"
677 PTrace::Initialise(args
.GetOptionCount('t'),
678 args
.HasOption('o') ? (const char *)args
.GetOptionString('o') : NULL
,
679 PTrace::Timestamp
|PTrace::Thread
|PTrace::FileAndLine
);
682 // Create the Opal Manager and initialise it
683 opal
= new MyManager
;
685 if (opal
->Initialise(args
))
688 cout
<< "Exiting " << GetName() << endl
;
694 ///////////////////////////////////////////////////////////////
696 MyManager::MyManager()
723 pauseBeforeDialing
= FALSE
;
727 MyManager::~MyManager()
730 // Must do this before we destroy the manager or a crash will result
732 potsEP
->RemoveAllLines();
737 BOOL
MyManager::Initialise(PArgList
& args
)
740 OpalMediaFormat
fmt("H.261-CIF");
742 fmt
.SetOptionInteger(OpalVideoFormat::EncodingQualityOption(), 16);
743 fmt
.SetOptionBoolean(OpalVideoFormat::AdaptivePacketDelayOption(), TRUE
);
744 OpalMediaFormat::SetRegisteredMediaFormat(fmt
);
747 // Set the various global options
748 if (args
.HasOption("rx-video"))
749 autoStartReceiveVideo
= TRUE
;
750 if (args
.HasOption("no-rx-video"))
751 autoStartReceiveVideo
= FALSE
;
752 if (args
.HasOption("tx-video"))
753 autoStartTransmitVideo
= TRUE
;
754 if (args
.HasOption("no-tx-video"))
755 autoStartTransmitVideo
= FALSE
;
757 if (args
.HasOption("grabber")) {
758 PVideoDevice::OpenArgs video
= GetVideoInputDevice();
759 video
.deviceName
= args
.GetOptionString("grabber");
760 video
.driverName
= args
.GetOptionString("grabdriver");
761 video
.channelNumber
= args
.GetOptionString("grabchannel").AsInteger();
762 if (!SetVideoInputDevice(video
)) {
763 cerr
<< "Unknown grabber device " << video
.deviceName
<< endl
764 << "options are:" << setfill(',') << PVideoInputDevice::GetDriversDeviceNames("") << endl
;
769 if (args
.HasOption("display")) {
770 PVideoDevice::OpenArgs video
= GetVideoOutputDevice();
771 video
.deviceName
= args
.GetOptionString("display");
772 video
.driverName
= args
.GetOptionString("displaydriver");
773 if (!SetVideoOutputDevice(video
)) {
774 cerr
<< "Unknown display device " << video
.deviceName
<< endl
775 << "options are:" << setfill(',') << PVideoOutputDevice::GetDriversDeviceNames("") << endl
;
781 if (args
.HasOption('j')) {
784 PStringArray delays
= args
.GetOptionString('j').Tokenise(",-");
785 if (delays
.GetSize() < 2) {
786 maxJitter
= delays
[0].AsUnsigned();
787 minJitter
= PMIN(GetMinAudioJitterDelay(), maxJitter
);
790 minJitter
= delays
[0].AsUnsigned();
791 maxJitter
= delays
[1].AsUnsigned();
793 if (minJitter
>= 20 && minJitter
<= maxJitter
&& maxJitter
<= 1000)
794 SetAudioJitterDelay(minJitter
, maxJitter
);
796 cerr
<< "Jitter should be between 20 and 1000 milliseconds." << endl
;
801 silenceDetectParams
.m_mode
= args
.HasOption('e') ? OpalSilenceDetector::NoSilenceDetection
802 : OpalSilenceDetector::AdaptiveSilenceDetection
;
804 if (args
.HasOption('D'))
805 SetMediaFormatMask(args
.GetOptionString('D').Lines());
806 if (args
.HasOption('P'))
807 SetMediaFormatOrder(args
.GetOptionString('P').Lines());
809 cout
<< "Jitter buffer: " << GetMinAudioJitterDelay() << '-' << GetMaxAudioJitterDelay() << " ms\n";
811 if (args
.HasOption("translate")) {
812 SetTranslationAddress(args
.GetOptionString("translate"));
813 cout
<< "External address set to " << GetTranslationAddress() << '\n';
816 if (args
.HasOption("portbase")) {
817 unsigned portbase
= args
.GetOptionString("portbase").AsUnsigned();
818 unsigned portmax
= args
.GetOptionString("portmax").AsUnsigned();
819 SetTCPPorts (portbase
, portmax
);
820 SetUDPPorts (portbase
, portmax
);
821 SetRtpIpPorts(portbase
, portmax
);
823 if (args
.HasOption("tcp-base"))
824 SetTCPPorts(args
.GetOptionString("tcp-base").AsUnsigned(),
825 args
.GetOptionString("tcp-max").AsUnsigned());
827 if (args
.HasOption("udp-base"))
828 SetUDPPorts(args
.GetOptionString("udp-base").AsUnsigned(),
829 args
.GetOptionString("udp-max").AsUnsigned());
831 if (args
.HasOption("rtp-base"))
832 SetRtpIpPorts(args
.GetOptionString("rtp-base").AsUnsigned(),
833 args
.GetOptionString("rtp-max").AsUnsigned());
836 if (args
.HasOption("rtp-tos")) {
837 unsigned tos
= args
.GetOptionString("rtp-tos").AsUnsigned();
839 cerr
<< "IP Type Of Service bits must be 0 to 255." << endl
;
842 SetRtpIpTypeofService(tos
);
845 cout
<< "TCP ports: " << GetTCPPortBase() << '-' << GetTCPPortMax() << "\n"
846 "UDP ports: " << GetUDPPortBase() << '-' << GetUDPPortMax() << "\n"
847 "RTP ports: " << GetRtpIpPortBase() << '-' << GetRtpIpPortMax() << "\n"
848 "RTP IP TOS: 0x" << hex
<< (unsigned)GetRtpIpTypeofService() << dec
<< "\n"
849 "STUN server: " << flush
;
851 if (args
.HasOption("stun"))
852 SetSTUNServer(args
.GetOptionString("stun"));
855 cout
<< stun
->GetServer() << " replies " << stun
->GetNatTypeName();
860 OpalMediaFormatList allMediaFormats
;
862 ///////////////////////////////////////
863 // Open the LID if parameter provided, create LID based endpoint
865 if (!args
.HasOption('L')) {
866 PStringArray devices
= args
.GetOptionString("lid").Lines();
867 if (devices
.IsEmpty() || devices
[0] == "*" || devices
[0] == "*:*")
868 devices
= OpalLineInterfaceDevice::GetAllDevices();
869 for (PINDEX d
= 0; d
< devices
.GetSize(); d
++) {
870 PINDEX colon
= devices
[d
].Find(':');
871 OpalLineInterfaceDevice
* lid
= OpalLineInterfaceDevice::Create(devices
[d
].Left(colon
));
872 if (lid
->Open(devices
[d
].Mid(colon
+1).Trim())) {
873 if (args
.HasOption("country")) {
874 PString country
= args
.GetOptionString("country");
875 if (!lid
->SetCountryCodeName(country
))
876 cerr
<< "Could not set LID to country name \"" << country
<< '"' << endl
;
879 // Create LID protocol handler, automatically adds to manager
881 potsEP
= new OpalPOTSEndPoint(*this);
882 if (potsEP
->AddDevice(lid
)) {
883 cout
<< "Line interface device \"" << devices
[d
] << "\" added." << endl
;
884 allMediaFormats
+= potsEP
->GetMediaFormats();
888 cerr
<< "Could not open device \"" << devices
[d
] << '"' << endl
;
895 ///////////////////////////////////////
896 // Create PC Sound System handler
898 if (!args
.HasOption('S')) {
899 pcssEP
= new MyPCSSEndPoint(*this);
901 pcssEP
->autoAnswer
= args
.HasOption('a');
902 cout
<< "Auto answer is " << (pcssEP
->autoAnswer
? "on" : "off") << "\n";
904 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Recorder
))
906 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Player
))
908 if (!pcssEP
->SetSoundDevice(args
, "sound-in", PSoundChannel::Recorder
))
910 if (!pcssEP
->SetSoundDevice(args
, "sound-out", PSoundChannel::Player
))
913 allMediaFormats
+= pcssEP
->GetMediaFormats();
915 cout
<< "Sound output device: \"" << pcssEP
->GetSoundChannelPlayDevice() << "\"\n"
916 "Sound input device: \"" << pcssEP
->GetSoundChannelRecordDevice() << "\"\n"
918 "Video output device: \"" << GetVideoOutputDevice().deviceName
<< "\"\n"
919 "Video input device: \"" << GetVideoInputDevice().deviceName
<< '"'
926 ///////////////////////////////////////
927 // Create H.323 protocol handler
928 if (!args
.HasOption("no-h323")) {
929 h323EP
= new H323EndPoint(*this);
930 if (!InitialiseH323EP(args
, "h323-listen", h323EP
))
933 if (!args
.HasOption("no-h323s")) {
934 h323sEP
= new H323SecureEndPoint(*this);
935 if (!InitialiseH323EP(args
, "h323s-listen", h323sEP
))
944 ///////////////////////////////////////
945 // Create IAX2 protocol handler
947 if (!args
.HasOption("no-iax2")) {
948 iax2EP
= new IAX2EndPoint(*this);
950 if (args
.HasOption('p'))
951 iax2EP
->SetPassword(args
.GetOptionString('p'));
953 if (args
.HasOption('u')) {
954 PStringArray aliases
= args
.GetOptionString('u').Lines();
955 iax2EP
->SetLocalUserName(aliases
[0]);
962 ///////////////////////////////////////
963 // Create SIP protocol handler
965 if (!args
.HasOption("no-sip")) {
966 sipEP
= new SIPEndPoint(*this);
968 if (args
.HasOption("sip-user-agent"))
969 sipEP
->SetUserAgent(args
.GetOptionString("sip-user-agent"));
971 PString str
= args
.GetOptionString("sip-ui");
972 if (str
*= "rfc2833")
973 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsSeparateRFC2833
);
974 else if (str
*= "info-tone")
975 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsTone
);
976 else if (str
*= "info-string")
977 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsString
);
979 if (args
.HasOption("sip-proxy"))
980 sipEP
->SetProxy(args
.GetOptionString("sip-proxy"));
983 sipEP
->SetMIMEForm(args
.HasOption("use-long-mime"));
985 // Get local username, multiple uses of -u indicates additional aliases
986 if (args
.HasOption('u')) {
987 PStringArray aliases
= args
.GetOptionString('u').Lines();
988 sipEP
->SetDefaultLocalPartyName(aliases
[0]);
991 sipEP
->SetRetryTimeouts(10000, 30000);
993 // Start the listener thread for incoming calls.
994 PStringArray listeners
= args
.GetOptionString("sip-listen").Lines();
995 if (!sipEP
->StartListeners(listeners
)) {
996 cerr
<< "Could not open any SIP listener from "
997 << setfill(',') << listeners
<< endl
;
1001 if (args
.HasOption('r')) {
1002 PString registrar
= args
.GetOptionString('r');
1003 cout
<< "Using SIP registrar " << registrar
<< " ... " << flush
;
1004 if (sipEP
->Register(registrar
, args
.GetOptionString('u'), args
.GetOptionString('u'), args
.GetOptionString('p'), args
.GetOptionString("sip-domain")))
1009 pauseBeforeDialing
= TRUE
;
1017 ///////////////////////////////////////
1018 // Create IVR protocol handler
1020 if (!args
.HasOption('V')) {
1021 ivrEP
= new OpalIVREndPoint(*this);
1022 if (args
.HasOption('x'))
1023 ivrEP
->SetDefaultVXML(args
.GetOptionString('x'));
1025 allMediaFormats
+= ivrEP
->GetMediaFormats();
1027 PString ttsEngine
= args
.GetOptionString("tts");
1028 if (ttsEngine
.IsEmpty() && PFactory
<PTextToSpeech
>::GetKeyList().size() > 0)
1029 ttsEngine
= PFactory
<PTextToSpeech
>::GetKeyList()[0];
1030 if (!ttsEngine
.IsEmpty())
1031 ivrEP
->SetDefaultTextToSpeech(ttsEngine
);
1036 ///////////////////////////////////////
1037 // Create T38 protocol handler
1039 OpalMediaFormat
fmt(OpalT38
); // Force instantiation of T.38 media format
1040 faxEP
= new OpalFaxEndPoint(*this);
1041 t38EP
= new OpalT38EndPoint(*this);
1045 ///////////////////////////////////////
1046 // Set the dial peers
1048 if (args
.HasOption('d')) {
1049 if (!SetRouteTable(args
.GetOptionString('d').Lines())) {
1050 cerr
<< "No legal entries in dial peer!" << endl
;
1055 if (!args
.HasOption("no-std-dial-peer")) {
1057 // Need to make sure wildcard on source ep type is first or it won't be
1058 // selected in preference to the specific entries below
1060 AddRouteEntry(".*:# = ivr:"); // A hash from anywhere goes to IVR
1064 if (sipEP
!= NULL
) {
1065 AddRouteEntry("pots:.*\\*.*\\*.* = sip:<dn2ip>");
1066 AddRouteEntry("pots:.* = sip:<da>");
1067 AddRouteEntry("pc:.* = sip:<da>");
1072 if (h323EP
!= NULL
) {
1073 AddRouteEntry("pots:.*\\*.*\\*.* = h323:<dn2ip>");
1074 AddRouteEntry("pots:.* = h323:<da>");
1075 AddRouteEntry("pc:.* = h323:<da>");
1077 if (h323sEP
!= NULL
) {
1078 AddRouteEntry("pots:.*\\*.*\\*.* = h323s:<dn2ip>");
1079 AddRouteEntry("pots:.* = h323s:<da>");
1080 AddRouteEntry("pc:.* = h323s:<da>");
1087 if (potsEP
!= NULL
) {
1089 AddRouteEntry("h323:.* = pots:<da>");
1091 if (h323sEP
!= NULL
)
1092 AddRouteEntry("h323s:.* = pots:<da>");
1096 AddRouteEntry("sip:.* = pots:<da>");
1101 if (pcssEP
!= NULL
) {
1103 AddRouteEntry("h323:.* = pc:<da>");
1105 if (h323sEP
!= NULL
)
1106 AddRouteEntry("h323s:.* = pc:<da>");
1110 AddRouteEntry("sip:.* = pc:<da>");
1116 if (pcssEP
!= NULL
) {
1117 AddRouteEntry("iax2:.* = pc:<da>");
1118 AddRouteEntry("pc:.* = iax2:<da>");
1122 srcEP
= args
.GetOptionString("srcep", pcssEP
!= NULL
? "pc:*"
1124 : potsEP
!= NULL
? "pots:*"
1127 : ivrEP
!= NULL
? "ivr:#"
1130 : sipEP
!= NULL
? "sip:localhost"
1133 : h323EP
!= NULL
? "sip:localhost"
1137 cout
<< "Local endpoint type: " << srcEP
<< "\n"
1138 "Codecs removed: " << setfill(',') << GetMediaFormatMask() << "\n"
1139 "Codec order: " << GetMediaFormatOrder() << "\n"
1140 "Available codecs: " << OpalTranscoder::GetPossibleFormats(allMediaFormats
) << setfill(' ') << endl
;
1147 BOOL
MyManager::InitialiseH323EP(PArgList
& args
, const PString
& listenOption
, H323EndPoint
* h323EP
)
1149 h323EP
->DisableFastStart(args
.HasOption('f'));
1150 h323EP
->DisableH245Tunneling(args
.HasOption('T'));
1151 h323EP
->SetSendGRQ(!args
.HasOption("disable-grq"));
1154 // Get local username, multiple uses of -u indicates additional aliases
1155 if (args
.HasOption('u')) {
1156 PStringArray aliases
= args
.GetOptionString('u').Lines();
1157 h323EP
->SetLocalUserName(aliases
[0]);
1158 for (PINDEX i
= 1; i
< aliases
.GetSize(); i
++)
1159 h323EP
->AddAliasName(aliases
[i
]);
1162 if (args
.HasOption('b')) {
1163 unsigned initialBandwidth
= args
.GetOptionString('b').AsUnsigned()*100;
1164 if (initialBandwidth
== 0) {
1165 cerr
<< "Illegal bandwidth specified." << endl
;
1168 h323EP
->SetInitialBandwidth(initialBandwidth
);
1171 h323EP
->SetGkAccessTokenOID(args
.GetOptionString("gk-token"));
1173 PString prefix
= h323EP
->GetPrefixName();
1175 cout
<< prefix
<< " Local username: " << h323EP
->GetLocalUserName() << "\n"
1176 << prefix
<< " FastConnect is " << (h323EP
->IsFastStartDisabled() ? "off" : "on") << "\n"
1177 << prefix
<< " H245Tunnelling is " << (h323EP
->IsH245TunnelingDisabled() ? "off" : "on") << "\n"
1178 << prefix
<< " gk Token OID is " << h323EP
->GetGkAccessTokenOID() << endl
;
1181 // Start the listener thread for incoming calls.
1182 PStringArray listeners
= args
.GetOptionString(listenOption
).Lines();
1183 if (!h323EP
->StartListeners(listeners
)) {
1184 cerr
<< "Could not open any " << prefix
<< " listener from "
1185 << setfill(',') << listeners
<< endl
;
1188 cout
<< prefix
<< " listeners: " << setfill(',') << h323EP
->GetListeners() << setfill(' ') << endl
;
1191 if (args
.HasOption('p'))
1192 h323EP
->SetGatekeeperPassword(args
.GetOptionString('p'));
1194 // Establish link with gatekeeper if required.
1195 if (!args
.HasOption('n')) {
1196 PString gkHost
= args
.GetOptionString('g');
1197 PString gkIdentifer
= args
.GetOptionString('G');
1198 PString gkInterface
= args
.GetOptionString("h323-listen");
1199 cout
<< "Gatekeeper: " << flush
;
1200 if (h323EP
->UseGatekeeper(gkHost
, gkIdentifer
, gkInterface
))
1201 cout
<< *h323EP
->GetGatekeeper() << endl
;
1203 cout
<< "none." << endl
;
1204 cerr
<< "Could not register with gatekeeper";
1206 cerr
<< " id \"" << gkIdentifer
<< '"';
1208 cerr
<< " at \"" << gkHost
<< '"';
1210 cerr
<< " on interface \"" << gkInterface
<< '"';
1211 if (h323EP
->GetGatekeeper() != NULL
) {
1212 switch (h323EP
->GetGatekeeper()->GetRegistrationFailReason()) {
1213 case H323Gatekeeper::InvalidListener
:
1214 cerr
<< " - Invalid listener";
1216 case H323Gatekeeper::DuplicateAlias
:
1217 cerr
<< " - Duplicate alias";
1219 case H323Gatekeeper::SecurityDenied
:
1220 cerr
<< " - Security denied";
1222 case H323Gatekeeper::TransportError
:
1223 cerr
<< " - Transport error";
1226 cerr
<< " - Error code " << h323EP
->GetGatekeeper()->GetRegistrationFailReason();
1229 cerr
<< '.' << endl
;
1230 if (args
.HasOption("require-gatekeeper"))
1240 void MyManager::NewSpeedDial(const PString
& ostr
)
1243 PINDEX idx
= str
.Find(' ');
1244 if (str
.IsEmpty() || (idx
== P_MAX_INDEX
)) {
1245 cout
<< "Must specify speedial number and string" << endl
;
1249 PString key
= str
.Left(idx
).Trim();
1250 PString data
= str
.Mid(idx
).Trim();
1252 PConfig
config("Speeddial");
1253 config
.SetString(key
, data
);
1255 cout
<< "Speedial " << key
<< " set to " << data
<< endl
;
1259 void MyManager::Main(PArgList
& args
)
1261 OpalConnection::StringOptions stringOptions
;
1263 // See if making a call or just listening.
1264 switch (args
.GetCount()) {
1266 cout
<< "Waiting for incoming calls\n";
1270 if (pauseBeforeDialing
) {
1271 cout
<< "Pausing to allow registration to occur..." << flush
;
1272 PThread::Sleep(2000);
1273 cout
<< "done" << endl
;
1276 cout
<< "Initiating call to \"" << args
[0] << "\"\n";
1277 SetUpCall(srcEP
, args
[0], currentCallToken
, 0, 0, &stringOptions
);
1281 if (pauseBeforeDialing
) {
1282 cout
<< "Pausing to allow registration to occur..." << flush
;
1283 PThread::Sleep(2000);
1284 cout
<< "done" << endl
;
1286 cout
<< "Initiating call from \"" << args
[0] << "\"to \"" << args
[1] << "\"\n";
1287 SetUpCall(args
[0], args
[1], currentCallToken
);
1291 if (args
.HasOption("disableui")) {
1292 while (FindCallWithLock(currentCallToken
) != NULL
)
1293 PThread::Sleep(1000);
1296 cout
<< "Press ? for help." << endl
;
1301 " 0-9 : send user indication message\n"
1302 " *,# : send user indication message\n"
1303 " M : send text message to remote user\n"
1304 " C : connect to remote host\n"
1305 " S : Display statistics\n"
1306 " H : Hang up phone\n"
1307 " L : List speed dials\n"
1308 " D : Create new speed dial\n"
1309 " {} : Increase/reduce record volume\n"
1310 " [] : Increase/reduce playback volume\n"
1311 " V : Display current volumes\n";
1313 PConsoleChannel
console(PConsoleChannel::StandardInput
);
1315 // display the prompt
1316 cout
<< "Command ? " << flush
;
1319 // terminate the menu loop if console finished
1320 char ch
= (char)console
.peek();
1321 if (console
.eof()) {
1322 cout
<< "\nConsole gone - menu disabled" << endl
;
1327 PTRACE(3, "console in audio test is " << ch
);
1328 switch (tolower(ch
)) {
1338 if (pcssEP
!= NULL
&& !pcssEP
->incomingConnectionToken
) {
1339 if (!pcssEP
->AcceptIncomingConnection(pcssEP
->incomingConnectionToken
))
1340 cout
<< "Could not answer connection " << pcssEP
->incomingConnectionToken
<< endl
;
1342 console
.ignore(INT_MAX
, '\n');
1346 if (pcssEP
!= NULL
&& !pcssEP
->incomingConnectionToken
) {
1347 PSafePtr
<OpalConnection
> connection
= pcssEP
->GetConnectionWithLock(pcssEP
->incomingConnectionToken
);
1348 if (connection
!= NULL
) {
1349 cout
<< "Clearing connection " << *connection
<< endl
;
1350 connection
->Release(OpalConnection::EndedByAnswerDenied
);
1353 console
.ignore(INT_MAX
, '\n');
1364 NewSpeedDial(str
.Trim());
1369 HangupCurrentCall();
1373 if (!currentCallToken
.IsEmpty())
1374 cout
<< "Cannot make call whilst call in progress\n";
1378 StartCall(str
.Trim());
1383 cout
<< " current call token is \"" << currentCallToken
<< "\" " << endl
;
1387 if (currentCallToken
.IsEmpty())
1388 cout
<< "Cannot send a message while no call in progress\n";
1392 SendMessageToRemoteNode(str
);
1397 if (ch
>= '0' || ch
<= '9' || ch
== '*' || ch
== '#') {
1398 if (currentCallToken
.IsEmpty())
1399 cout
<< "Cannot send a digit while no call in progress\n";
1407 if (!currentCallToken
.IsEmpty())
1408 HangupCurrentCall();
1411 cout
<< "Console finished " << endl
;
1414 void MyManager::HangupCurrentCall()
1416 PSafePtr
<OpalCall
> call
= FindCallWithLock(currentCallToken
);
1418 cout
<< "Clearing call " << *call
<< endl
;
1420 currentCallToken
= PString();
1423 cout
<< "Not in a call!\n";
1426 void MyManager::SendMessageToRemoteNode(const PString
& ostr
)
1428 PString str
= ostr
.Trim();
1429 if (str
.IsEmpty()) {
1430 cout
<< "Must supply a message to send!\n";
1434 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1435 PStringList res
= endpoints
[i
].GetAllConnections();
1436 if (res
.GetSize() == 0)
1439 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1440 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1442 conn
->SendUserInputString(str
);
1443 cout
<< "Send \"" << str
<< "\" to " << res
[j
] << endl
;
1450 void MyManager::SendTone(const char tone
)
1452 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1453 PStringList res
= endpoints
[i
].GetAllConnections();
1454 if (res
.GetSize() == 0)
1457 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1458 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1460 conn
->SendUserInputTone(tone
, 0);
1461 cout
<< "Send \"" << tone
<< "\" to " << res
[j
] << endl
;
1468 void MyManager::StartCall(const PString
& ostr
)
1470 PString str
= ostr
.Trim();
1471 if (str
.IsEmpty()) {
1472 cout
<< "Must supply hostname to connect to!\n";
1476 // check for speed dials, and match wild cards as we go
1477 PString key
, prefix
;
1478 if ((str
.GetLength() > 1) && (str
[str
.GetLength()-1] == '#')) {
1480 key
= str
.Left(str
.GetLength()-1).Trim();
1482 PConfig
config("Speeddial");
1484 for (p
= key
.GetLength(); p
> 0; p
--) {
1486 PString newKey
= key
.Left(p
);
1490 // look for wild cards
1491 str
= config
.GetString(newKey
+ '*').Trim();
1495 // look for digit matches
1496 for (q
= p
; q
< key
.GetLength(); q
++)
1498 str
= config
.GetString(newKey
).Trim();
1502 if (str
.IsEmpty()) {
1503 cout
<< "Speed dial \"" << key
<< "\" not defined";
1509 SetUpCall(srcEP
, str
, currentCallToken
);
1514 void MyManager::ListSpeedDials()
1516 PConfig
config("Speeddial");
1517 PStringList keys
= config
.GetKeys();
1518 if (keys
.GetSize() == 0) {
1519 cout
<< "No speed dials defined" << endl
;
1524 for (i
= 0; i
< keys
.GetSize(); i
++)
1525 cout
<< keys
[i
] << ": " << config
.GetString(keys
[i
]) << endl
;
1528 void MyManager::OnEstablishedCall(OpalCall
& call
)
1530 currentCallToken
= call
.GetToken();
1531 cout
<< "In call with " << call
.GetPartyB() << " using " << call
.GetPartyA() << endl
;
1534 void MyManager::OnClearedCall(OpalCall
& call
)
1536 if (currentCallToken
== call
.GetToken())
1537 currentCallToken
= PString();
1539 PString remoteName
= '"' + call
.GetPartyB() + '"';
1540 switch (call
.GetCallEndReason()) {
1541 case OpalConnection::EndedByRemoteUser
:
1542 cout
<< remoteName
<< " has cleared the call";
1544 case OpalConnection::EndedByCallerAbort
:
1545 cout
<< remoteName
<< " has stopped calling";
1547 case OpalConnection::EndedByRefusal
:
1548 cout
<< remoteName
<< " did not accept your call";
1550 case OpalConnection::EndedByNoAnswer
:
1551 cout
<< remoteName
<< " did not answer your call";
1553 case OpalConnection::EndedByTransportFail
:
1554 cout
<< "Call with " << remoteName
<< " ended abnormally";
1556 case OpalConnection::EndedByCapabilityExchange
:
1557 cout
<< "Could not find common codec with " << remoteName
;
1559 case OpalConnection::EndedByNoAccept
:
1560 cout
<< "Did not accept incoming call from " << remoteName
;
1562 case OpalConnection::EndedByAnswerDenied
:
1563 cout
<< "Refused incoming call from " << remoteName
;
1565 case OpalConnection::EndedByNoUser
:
1566 cout
<< "Gatekeeper or registrar could not find user " << remoteName
;
1568 case OpalConnection::EndedByNoBandwidth
:
1569 cout
<< "Call to " << remoteName
<< " aborted, insufficient bandwidth.";
1571 case OpalConnection::EndedByUnreachable
:
1572 cout
<< remoteName
<< " could not be reached.";
1574 case OpalConnection::EndedByNoEndPoint
:
1575 cout
<< "No phone running for " << remoteName
;
1577 case OpalConnection::EndedByHostOffline
:
1578 cout
<< remoteName
<< " is not online.";
1580 case OpalConnection::EndedByConnectFail
:
1581 cout
<< "Transport error calling " << remoteName
;
1584 cout
<< "Call with " << remoteName
<< " completed";
1587 cout
<< ", on " << now
.AsString("w h:mma") << ". Duration "
1588 << setprecision(0) << setw(5) << (now
- call
.GetStartTime())
1591 OpalManager::OnClearedCall(call
);
1595 BOOL
MyManager::OnOpenMediaStream(OpalConnection
& connection
,
1596 OpalMediaStream
& stream
)
1598 if (!OpalManager::OnOpenMediaStream(connection
, stream
))
1603 PCaselessString prefix
= connection
.GetEndPoint().GetPrefixName();
1604 if (prefix
== "pc" || prefix
== "pots")
1605 cout
<< (stream
.IsSink() ? "playing " : "grabbing ") << stream
.GetMediaFormat();
1606 else if (prefix
== "ivr")
1607 cout
<< (stream
.IsSink() ? "streaming " : "recording ") << stream
.GetMediaFormat();
1609 cout
<< (stream
.IsSink() ? "sending " : "receiving ") << stream
.GetMediaFormat()
1610 << (stream
.IsSink() ? " to " : " from ")<< prefix
;
1619 void MyManager::OnUserInputString(OpalConnection
& connection
, const PString
& value
)
1621 cout
<< "User input received: \"" << value
<< '"' << endl
;
1622 OpalManager::OnUserInputString(connection
, value
);
1626 ///////////////////////////////////////////////////////////////
1628 MyPCSSEndPoint::MyPCSSEndPoint(MyManager
& mgr
)
1629 : OpalPCSSEndPoint(mgr
)
1634 BOOL
MyPCSSEndPoint::OnShowIncoming(const OpalPCSSConnection
& connection
)
1636 incomingConnectionToken
= connection
.GetToken();
1639 AcceptIncomingConnection(incomingConnectionToken
);
1642 cout
<< "\nCall on " << now
.AsString("w h:mma")
1643 << " from " << connection
.GetRemotePartyName()
1644 << ", answer (Y/N)? " << flush
;
1651 BOOL
MyPCSSEndPoint::OnShowOutgoing(const OpalPCSSConnection
& connection
)
1654 cout
<< connection
.GetRemotePartyName() << " is ringing on "
1655 << now
.AsString("w h:mma") << " ..." << endl
;
1660 BOOL
MyPCSSEndPoint::SetSoundDevice(PArgList
& args
,
1661 const char * optionName
,
1662 PSoundChannel::Directions dir
)
1664 if (!args
.HasOption(optionName
))
1667 PString dev
= args
.GetOptionString(optionName
);
1669 if (dir
== PSoundChannel::Player
) {
1670 if (SetSoundChannelPlayDevice(dev
))
1674 if (SetSoundChannelRecordDevice(dev
))
1678 cerr
<< "Device for " << optionName
<< " (\"" << dev
<< "\") must be one of:\n";
1680 PStringArray names
= PSoundChannel::GetDeviceNames(dir
);
1681 for (PINDEX i
= 0; i
< names
.GetSize(); i
++)
1682 cerr
<< " \"" << names
[i
] << "\"\n";
1688 // End of File ///////////////////////////////////////////////////////////////