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.86 2007/04/03 13:04:23 rjongbloed
26 * Added driverName to PVideoDevice::OpenArgs (so can select YUVFile)
27 * Added new statics to create correct video input/output device object
28 * given a PVideoDevice::OpenArgs structure.
29 * Fixed incorrect initialisation of default video input device.
30 * Fixed last calls video size changing the default value.
32 * Revision 2.85 2007/04/03 07:59:14 rjongbloed
33 * Warning: API change to PCSS callbacks:
34 * changed return on OnShowIncoming to BOOL, now agrees with
35 * documentation and allows UI to abort calls early.
36 * added BOOL to AcceptIncomingConnection indicating the
37 * supplied token is invalid.
38 * removed redundent OnGetDestination() function, was never required.
40 * Revision 2.84 2007/04/03 05:27:30 rjongbloed
41 * Cleaned up somewhat confusing usage of the OnAnswerCall() virtual
42 * function. The name is innaccurate and exists as a legacy from the
43 * OpenH323 days. it now only indicates how alerting is done
44 * (with/without media) and does not actually answer the call.
46 * Revision 2.83 2007/03/29 08:32:22 csoutheren
47 * Pause before dialing when using two endpoint mode
49 * Revision 2.82 2007/03/29 05:24:00 csoutheren
50 * Add support for T.38
52 * Revision 2.81 2007/03/01 05:07:32 csoutheren
53 * Only include video code when video enabled
55 * Revision 2.80 2006/11/01 00:46:40 csoutheren
56 * Implement video output file device
58 * Revision 2.79 2006/10/31 04:41:47 csoutheren
59 * Add support for new methods needed for vidfiledevices
61 * Revision 2.78 2006/10/28 00:39:42 rjongbloed
62 * Added argument to set country on LID
64 * Revision 2.77 2006/10/22 12:09:57 rjongbloed
65 * Fixed minor error in user output string.
67 * Revision 2.76 2006/10/15 06:12:48 rjongbloed
68 * Fixed correct local A-Party endpoint type depending on compiler flags and command line arguments.
69 * Fixed being able to select IVR via wildcard (routing table order) on source endpoint type.
70 * Fixed correctly trimming spaces from POTS device name.
72 * Revision 2.75 2006/10/10 07:18:18 csoutheren
73 * Allow compilation with and without various options
75 * Revision 2.74 2006/10/05 07:11:49 csoutheren
76 * Add --disable-lid option
78 * Revision 2.73 2006/10/02 13:30:51 rjongbloed
81 * Revision 2.72 2006/08/29 01:37:11 csoutheren
82 * Change secure URLs to use h323s and tcps to be inline with sips
84 * Revision 2.71 2006/08/21 05:30:48 csoutheren
85 * Add support for sh323
87 * Revision 2.70 2006/08/01 12:46:32 rjongbloed
88 * Added build solution for plug ins
89 * Removed now redundent code due to plug ins addition
91 * Revision 2.69 2006/07/24 14:03:39 csoutheren
92 * Merged in audio and video plugins from CVS branch PluginBranch
94 * Revision 2.68 2006/07/21 00:38:31 csoutheren
95 * Applied 1483215 - Opal simpleOPAL deadlock patch & DTMF support
98 * Revision 2.67 2006/07/03 03:28:44 dereksmithies
99 * Fix arg handling on disableui, and look for args to srcep, not srcEp
101 * Revision 2.66 2006/06/26 02:03:07 csoutheren
102 * Fixed problem when no TTS code installed
104 * Revision 2.65 2006/06/05 05:26:39 csoutheren
105 * Added ability to test outgoing SIP INFO messages
107 * Revision 2.64 2006/04/30 14:42:00 dereksmithies
108 * Fix compile Sleep statement so it compiles on unix.
110 * Revision 2.63 2006/04/30 14:36:54 csoutheren
111 * backports from PLuginBranch
113 * Revision 2.62 2006/04/30 14:34:42 csoutheren
114 * Backport of IVR updates from PluginBranch
116 * Revision 2.60.2.4 2006/04/30 14:28:25 csoutheren
117 * Added disableui and srcep options
119 * Revision 2.60.2.3 2006/04/30 13:50:29 csoutheren
120 * Add ability to set TextToSpeech algorithm
121 * Revision 2.60.2.2 2006/04/10 08:54:11 csoutheren
122 * Fix problem when H323 disabled
124 * Revision 2.60.2.1 2006/03/20 02:25:26 csoutheren
125 * Backports from CVS head
127 * Revision 2.61 2006/03/07 11:24:15 csoutheren
128 * Add --disable-grq flag
130 * Revision 2.60 2006/01/23 22:56:57 csoutheren
131 * Added 2 second pause before dialling outgoing SIP calls from command line args when
134 * Revision 2.59 2005/12/11 19:14:21 dsandras
135 * Added support for setting a different user name and authentication user name
136 * as required by some providers like digisip.
138 * Revision 2.58 2005/11/07 02:27:48 dereksmithies
139 * Get the answer call Y/N mechanism to work correctly.
141 * Revision 2.57 2005/09/06 04:58:42 dereksmithies
142 * Add console input options. This is an initial release, and some "refinement"
145 * Revision 2.56 2005/08/20 09:03:10 rjongbloed
146 * Some cosmetic fixes in output messages
148 * Revision 2.55 2005/08/13 09:16:18 rjongbloed
149 * Added no-Xt-video to "usage" output
151 * Revision 2.54 2005/08/04 08:47:38 rjongbloed
152 * Some cosmetic changes, and print out the codecs that are available
154 * Revision 2.53 2005/07/30 07:42:15 csoutheren
155 * Added IAX2 functions
157 * Revision 2.52 2005/07/24 07:56:35 rjongbloed
158 * Removed -l parameter, as it always listens.
160 * Revision 2.51 2005/07/11 01:57:31 csoutheren
161 * Fixed error message
163 * Revision 2.50 2005/06/23 06:14:02 csoutheren
164 * Fixed rtp-tos argument parsing. Thanks to Paul Nader
166 * Revision 2.49 2005/06/09 04:51:58 dereksmithies
169 * Revision 2.48 2005/06/09 04:45:57 dereksmithies
170 * Correctly close the incoming connection if the user rejects the incoming call.
171 * Thanks to Robert Jongbloed for some helpful advice.
173 * Revision 2.47 2005/03/11 18:12:09 dsandras
174 * 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.
176 * Revision 2.46 2005/02/19 22:46:19 dsandras
177 * Temporarily removed support for SetDomain.
179 * Revision 2.45 2004/11/29 08:20:04 csoutheren
180 * Added support for setting SIP authentication domain
182 * Revision 2.44 2004/08/18 07:14:00 csoutheren
183 * Called ancestor OnClearedCall
185 * Revision 2.43 2004/08/14 07:56:30 rjongbloed
186 * Major revision to utilise the PSafeCollection classes for the connections and calls.
188 * Revision 2.42 2004/04/26 07:06:07 rjongbloed
189 * Removed some ancient pieces of code and used new API's for them.
191 * Revision 2.41 2004/04/26 06:33:18 rjongbloed
192 * Added ability to specify more than one defualt listener for an endpoint,
193 * required by SIP which listens on both UDP and TCP.
195 * Revision 2.40 2004/04/25 09:32:48 rjongbloed
196 * Fixed correct usage of HAS_IXJ
198 * Revision 2.39 2004/03/29 10:53:23 rjongbloed
199 * Fixed missing mutex unlock which would invariably cause a deadlock.
201 * Revision 2.38 2004/03/22 10:20:34 rjongbloed
202 * Changed to use UseGatekeeper() function so can select by gk-id as well as host.
204 * Revision 2.37 2004/03/14 11:32:20 rjongbloed
205 * Changes to better support SIP proxies.
207 * Revision 2.36 2004/03/14 08:34:09 csoutheren
208 * Added ability to set User-Agent string
210 * Revision 2.35 2004/03/14 06:15:36 rjongbloed
211 * Must set ports before stun as stun code uses those port numbers.
213 * Revision 2.34 2004/03/13 06:32:17 rjongbloed
214 * Fixes for removal of SIP and H.323 subsystems.
215 * More registration work.
217 * Revision 2.33 2004/03/11 06:54:27 csoutheren
218 * Added ability to disable SIP or H.323 stacks
220 * Revision 2.32 2004/03/09 12:09:56 rjongbloed
221 * More work on SIP register.
223 * Revision 2.31 2004/02/24 11:37:01 rjongbloed
224 * More work on NAT support, manual external address translation and STUN
226 * Revision 2.30 2004/02/21 02:41:10 rjongbloed
227 * Tidied up the translate address to utilise more of the library infrastructure.
228 * Changed cmd line args port-base/port-max to portbase/portmax, same as OhPhone.
230 * Revision 2.29 2004/02/17 11:00:06 csoutheren
231 * Added --translate, --port-base and --port-max options
233 * Revision 2.28 2004/02/03 12:22:28 rjongbloed
236 * Revision 2.27 2004/01/18 15:36:07 rjongbloed
239 * Revision 2.26 2003/04/09 01:38:27 robertj
240 * Changed default to not send/receive video and added options to turn it on.
242 * Revision 2.25 2003/03/26 03:51:46 robertj
243 * Fixed failure to compile if not statically linked.
245 * Revision 2.24 2003/03/24 07:18:29 robertj
246 * Added registration system for LIDs so can work with various LID types by
247 * name instead of class instance.
249 * Revision 2.23 2003/03/19 02:30:45 robertj
250 * Added removal of IVR stuff if EXPAT is not installed on system.
252 * Revision 2.22 2003/03/17 08:12:08 robertj
253 * Added protocol name to media stream open output.
255 * Revision 2.21 2003/03/07 08:18:47 robertj
256 * Fixed naming convention of PC sound system in routing table.
258 * Revision 2.20 2003/03/07 05:56:47 robertj
259 * Changed so a # from whatever source routes to IVR.
261 * Revision 2.19 2003/03/06 03:57:47 robertj
262 * IVR support (work in progress) requiring large changes everywhere.
264 * Revision 2.18 2002/11/11 06:52:01 robertj
265 * Added correct flag for including static global variables.
267 * Revision 2.17 2002/11/10 11:33:17 robertj
268 * Updated to OpenH323 v1.10.3
270 * Revision 2.16 2002/09/06 02:46:00 robertj
271 * Added routing table system to route calls by regular expressions.
272 * Added ability to set gatekeeper access token OID and password.
274 * Revision 2.15 2002/07/01 09:05:54 robertj
275 * Changed TCp/UDP port allocation to use new thread safe functions.
277 * Revision 2.14 2002/04/12 14:02:41 robertj
278 * Separated interface option for SIP and H.323.
280 * Revision 2.13 2002/03/27 05:34:55 robertj
281 * Removed redundent busy forward field.
282 * Added ability to set tcp and udp port bases.
284 * Revision 2.12 2002/03/27 04:36:46 robertj
285 * Changed to add all possible xJack cards to pots endpoint.
287 * Revision 2.11 2002/03/27 04:16:20 robertj
288 * Restructured default router for sample to allow more options.
290 * Revision 2.10 2002/02/13 08:17:31 robertj
291 * Changed routing algorithm to route call to H323/SIP if contains an '@'
293 * Revision 2.9 2002/02/11 09:45:35 robertj
294 * Moved version file to library root directoy
296 * Revision 2.8 2002/02/06 13:29:03 rogerh
297 * H245 tunnelling is controlled by 'T' and not by 'h'
299 * Revision 2.7 2002/02/01 04:53:01 robertj
300 * Added (very primitive!) SIP support.
302 * Revision 2.6 2002/01/22 05:34:58 robertj
303 * Revamp of user input API triggered by RFC2833 support
305 * Revision 2.5 2001/08/21 11:18:55 robertj
306 * Added conditional compile for xJack code.
308 * Revision 2.4 2001/08/17 08:35:41 robertj
309 * Changed OnEstablished() to OnEstablishedCall() to be consistent.
310 * Moved call end reasons enum from OpalConnection to global.
311 * Used LID management in lid EP.
312 * More implementation.
314 * Revision 2.3 2001/08/01 06:19:00 robertj
315 * Added flags for disabling H.323 or Quicknet endpoints.
317 * Revision 2.2 2001/08/01 05:48:30 robertj
318 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
319 * Fixed loading of transcoders from static library.
321 * Revision 2.1 2001/07/30 07:22:25 robertj
322 * Abstracted listener management from H.323 to OpalEndPoint class.
324 * Revision 2.0 2001/07/27 15:48:24 robertj
325 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
327 * Revision 1.12 2001/07/13 08:44:16 robertj
328 * Fixed incorrect inclusion of hardware codec capabilities.
330 * Revision 1.11 2001/05/17 07:11:29 robertj
331 * Added more call end types for common transport failure modes.
333 * Revision 1.10 2001/05/14 05:56:26 robertj
334 * Added H323 capability registration system so can add capabilities by
335 * string name instead of having to instantiate explicit classes.
337 * Revision 1.9 2001/03/21 04:52:40 robertj
338 * Added H.235 security to gatekeepers, thanks Fürbass Franz!
340 * Revision 1.8 2001/03/20 23:42:55 robertj
341 * Used the new PTrace::Initialise function for starting trace code.
343 * Revision 1.7 2000/10/16 08:49:31 robertj
344 * Added single function to add all UserInput capability types.
346 * Revision 1.6 2000/07/31 14:08:09 robertj
347 * Added fast start and H.245 tunneling flags to the H323Connection constructor so can
348 * disabled these features in easier manner to overriding virtuals.
350 * Revision 1.5 2000/06/20 02:38:27 robertj
351 * Changed H323TransportAddress to default to IP.
353 * Revision 1.4 2000/06/07 05:47:55 robertj
354 * Added call forwarding.
356 * Revision 1.3 2000/05/23 11:32:27 robertj
357 * Rewrite of capability table to combine 2 structures into one and move functionality into that class
358 * allowing some normalisation of usage across several applications.
359 * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
360 * to be done depending on the remote client application.
362 * Revision 1.2 2000/05/11 10:00:02 robertj
363 * Fixed setting and resetting of current call token variable.
365 * Revision 1.1 2000/05/11 04:05:57 robertj
366 * Simple sample program.
372 #include <opal/buildopts.h>
375 #include <iax2/iax2.h>
383 #include <h323/h323.h>
384 #include <h323/gkclient.h>
387 #include <t38/t38proto.h>
389 #include <opal/transcoders.h>
390 #include <lids/lidep.h>
391 #include <ptclib/pstun.h>
392 #include <ptlib/config.h>
395 #include "../../version.h"
401 PCREATE_PROCESS(SimpleOpalProcess
);
403 ///////////////////////////////////////////////////////////////
405 SimpleOpalProcess::SimpleOpalProcess()
406 : PProcess("Open Phone Abstraction Library", "SimpleOPAL",
407 MAJOR_VERSION
, MINOR_VERSION
, BUILD_TYPE
, BUILD_NUMBER
)
412 void SimpleOpalProcess::Main()
415 << " Version " << GetVersion(TRUE
)
416 << " by " << GetManufacturer()
417 << " on " << GetOSClass() << ' ' << GetOSName()
418 << " (" << GetOSVersion() << '-' << GetOSHardware() << ")\n\n";
420 // Get and parse all of the command line arguments.
421 PArgList
& args
= GetArguments();
458 "R-require-gatekeeper."
474 "T-h245tunneldisable."
487 "-rx-video." "-no-rx-video."
488 "-tx-video." "-no-tx-video."
504 if (args
.HasOption('h') || (!args
.HasOption('l') && args
.GetCount() == 0)) {
505 cout
<< "Usage : " << GetName() << " [options] -l\n"
506 " : " << GetName() << " [options] [alias@]hostname (no gatekeeper)\n"
507 " : " << GetName() << " [options] alias[@hostname] (with gatekeeper)\n"
509 " -l --listen : Listen for incoming calls.\n"
510 " -d --dial-peer spec : Set dial peer for routing calls (see below)\n"
511 " --no-std-dial-peer : Do not include the standard dial peers\n"
512 " -a --auto-answer : Automatically answer incoming calls.\n"
513 " -u --user name : Set local alias name(s) (defaults to login name).\n"
514 " -p --password pwd : Set password for user (gk or SIP authorisation).\n"
515 " -D --disable media : Disable the specified codec (may be used multiple times)\n"
516 " -P --prefer media : Prefer the specified codec (may be used multiple times)\n"
517 " --srcep ep : Set the source endpoint to use for making calls\n"
518 " --disableui : disable the user interface\n"
521 " -j --jitter [min-]max : Set minimum (optional) and maximum jitter buffer (in milliseconds).\n"
522 " -e --silence : Disable transmitter silence detection.\n"
525 " --rx-video : Start receiving video immediately.\n"
526 " --tx-video : Start transmitting video immediately.\n"
527 " --no-rx-video : Don't start receiving video immediately.\n"
528 " --no-tx-video : Don't start transmitting video immediately.\n"
529 " --grabber dev : Set the video grabber device.\n"
530 " --grabdriver dev : Set the video grabber driver (if device name is ambiguous).\n"
531 " --grabchannel num : Set the video grabber device channel.\n"
532 " --display dev : Set the video display device.\n"
533 " --displaydriver dev : Set the video display driver (if device name is ambiguous).\n"
538 " -I --no-sip : Disable SIP protocol.\n"
539 " -r --register-sip host : Register with SIP server.\n"
540 " --sip-proxy url : SIP proxy information, may be just a host name\n"
541 " : or full URL eg sip:user:pwd@host\n"
542 " --sip-listen iface : Interface/port(s) to listen for SIP requests\n"
543 " : '*' is all interfaces, (default udp$:*:5060)\n"
544 " --sip-user-agent name: SIP UserAgent name to use.\n"
545 " --sip-ui type : Set type of user indications to use for SIP. Can be one of 'rfc2833', 'info-tone', 'info-string'.\n"
546 " --use-long-mime : Use long MIME headers on outgoing SIP messages\n"
547 " --sip-domain str : set authentication domain/realm\n"
553 " -H --no-h323 : Disable H.323 protocol.\n"
554 " -g --gatekeeper host : Specify gatekeeper host.\n"
555 " -G --gk-id name : Specify gatekeeper identifier.\n"
556 " -n --no-gatekeeper : Disable gatekeeper discovery.\n"
557 " -R --require-gatekeeper : Exit if gatekeeper discovery fails.\n"
558 " --gk-token str : Set gatekeeper security token OID.\n"
559 " -b --bandwidth bps : Limit bandwidth usage to bps bits/second.\n"
560 " -f --fast-disable : Disable fast start.\n"
561 " -T --h245tunneldisable : Disable H245 tunnelling.\n"
562 " --h323-listen iface : Interface/port(s) to listen for H.323 requests\n"
564 " --h323s-listen iface : Interface/port(s) to listen for secure H.323 requests\n"
566 " : '*' is all interfaces, (default tcp$:*:1720)\n"
567 " --disable-grq : Do not send GRQ when registering with GK\n"
569 " --no-h323s : Do not creat secure H.323 endpoint\n"
575 "Line Interface options:\n"
576 " -L --no-lid : Do not use line interface device.\n"
577 " --lid device : Select line interface device (eg Quicknet:013A17C2, default *:*).\n"
578 " --country code : Select country to use for LID (eg \"US\", \"au\" or \"+61\").\n"
581 "Sound card options:\n"
582 " -S --no-sound : Do not use sound input/output device.\n"
583 " -s --sound device : Select sound input/output device.\n"
584 " --sound-in device : Select sound input device.\n"
585 " --sound-out device : Select sound output device.\n"
589 " -V --no-ivr : Disable IVR.\n"
590 " -x --vxml file : Set vxml file to use for IVR.\n"
591 " --tts engine : Set the text to speech engine\n"
595 " --translate ip : Set external IP address if masqueraded\n"
596 " --portbase n : Set TCP/UDP/RTP port base\n"
597 " --portmax n : Set TCP/UDP/RTP port max\n"
598 " --tcp-base n : Set TCP port base (default 0)\n"
599 " --tcp-max n : Set TCP port max (default base+99)\n"
600 " --udp-base n : Set UDP port base (default 6000)\n"
601 " --udp-max n : Set UDP port max (default base+199)\n"
602 " --rtp-base n : Set RTP port base (default 5000)\n"
603 " --rtp-max n : Set RTP port max (default base+199)\n"
604 " --rtp-tos n : Set RTP packet IP TOS bits to n\n"
605 " --stun server : Set STUN server\n"
609 " -t --trace : Enable trace, use multiple times for more detail.\n"
610 " -o --output : File for trace output, default is stderr.\n"
613 " -X --no-iax2 : Remove support for iax2\n"
615 " -h --help : This help message.\n"
618 "Dial peer specification:\n"
619 " General form is pattern=destination where pattern is a regular expression\n"
620 " matching the incoming calls destination address and will translate it to\n"
621 " the outgoing destination address for making an outgoing call. For example,\n"
622 " picking up a PhoneJACK handset and dialling 2, 6 would result in an address\n"
623 " of \"pots:26\" which would then be matched against, say, a spec of\n"
624 " pots:26=h323:10.0.1.1, resulting in a call from the pots handset to\n"
625 " 10.0.1.1 using the H.323 protocol.\n"
627 " As the pattern field is a regular expression, you could have used in the\n"
628 " above .*:26=h323:10.0.1.1 to achieve the same result with the addition that\n"
629 " an incoming call from a SIP client would also be routed to the H.323 client.\n"
631 " Note that the pattern has an implicit ^ and $ at the beginning and end of\n"
632 " the regular expression. So it must match the entire address.\n"
634 " If the specification is of the form @filename, then the file is read with\n"
635 " each line consisting of a pattern=destination dial peer specification. Lines\n"
636 " without and equal sign or beginning with '#' are ignored.\n"
638 " The standard dial peers that will be included are:\n"
639 " If SIP is enabled but H.323 & IAX2 are disabled:\n"
640 " pots:.*\\*.*\\*.* = sip:<dn2ip>\n"
641 " pots:.* = sip:<da>\n"
642 " pc:.* = sip:<da>\n"
644 " If SIP & IAX2 are not enabled and H.323 is enabled:\n"
645 " pots:.*\\*.*\\*.* = h323:<dn2ip>\n"
646 " pots:.* = h323:<da>\n"
647 " pc:.* = h323:<da>\n"
649 " If POTS is enabled:\n"
650 " h323:.* = pots:<da>\n"
651 " sip:.* = pots:<da>\n"
652 " iax2:.* = pots:<da>\n"
654 " If POTS is not enabled and the PC sound system is enabled:\n"
655 " iax2:.* = pc:<da>\n"
656 " h323:.* = pc:<da>\n"
657 " sip:. * = pc:<da>\n"
660 " If IVR is enabled then a # from any protocol will route it it, ie:\n"
665 " If IAX2 is enabled then you can make a iax2 call with a command like:\n"
666 " simpleopal -IHn iax2:guest@misery.digium.com/s\n"
673 PTrace::Initialise(args
.GetOptionCount('t'),
674 args
.HasOption('o') ? (const char *)args
.GetOptionString('o') : NULL
,
675 PTrace::Timestamp
|PTrace::Thread
|PTrace::FileAndLine
);
678 // Create the Opal Manager and initialise it
679 opal
= new MyManager
;
681 if (opal
->Initialise(args
))
684 cout
<< "Exiting " << GetName() << endl
;
690 ///////////////////////////////////////////////////////////////
692 MyManager::MyManager()
719 pauseBeforeDialing
= FALSE
;
723 MyManager::~MyManager()
726 // Must do this before we destroy the manager or a crash will result
728 potsEP
->RemoveAllLines();
733 BOOL
MyManager::Initialise(PArgList
& args
)
736 OpalMediaFormat
fmt(OpalT38
);
737 if (!fmt
.IsValid()) {
738 cerr
<< "cannot find t.38" << endl
;
743 OpalMediaFormat::SetRegisteredMediaFormat(fmt
);
747 OpalMediaFormat
fmt("H.261-CIF");
749 fmt
.SetOptionInteger(OpalVideoFormat::EncodingQualityOption
, 16);
750 fmt
.SetOptionBoolean(OpalVideoFormat::AdaptivePacketDelayOption
, TRUE
);
751 OpalMediaFormat::SetRegisteredMediaFormat(fmt
);
754 // Set the various global options
755 if (args
.HasOption("rx-video"))
756 autoStartReceiveVideo
= TRUE
;
757 if (args
.HasOption("no-rx-video"))
758 autoStartReceiveVideo
= FALSE
;
759 if (args
.HasOption("tx-video"))
760 autoStartTransmitVideo
= TRUE
;
761 if (args
.HasOption("no-tx-video"))
762 autoStartTransmitVideo
= FALSE
;
764 if (args
.HasOption("grabber")) {
765 PVideoDevice::OpenArgs video
= GetVideoInputDevice();
766 video
.deviceName
= args
.GetOptionString("grabber");
767 video
.driverName
= args
.GetOptionString("grabdriver");
768 video
.channelNumber
= args
.GetOptionString("grabchannel").AsInteger();
769 if (!SetVideoInputDevice(video
)) {
770 cerr
<< "Unknown grabber device " << video
.deviceName
<< endl
771 << "options are:" << setfill(',') << PVideoInputDevice::GetDriversDeviceNames("") << endl
;
776 if (args
.HasOption("display")) {
777 PVideoDevice::OpenArgs video
= GetVideoOutputDevice();
778 video
.deviceName
= args
.GetOptionString("display");
779 video
.driverName
= args
.GetOptionString("displaydriver");
780 if (!SetVideoOutputDevice(video
)) {
781 cerr
<< "Unknown display device " << video
.deviceName
<< endl
782 << "options are:" << setfill(',') << PVideoOutputDevice::GetDriversDeviceNames("") << endl
;
788 if (args
.HasOption('j')) {
791 PStringArray delays
= args
.GetOptionString('j').Tokenise(",-");
792 if (delays
.GetSize() < 2) {
793 maxJitter
= delays
[0].AsUnsigned();
794 minJitter
= PMIN(GetMinAudioJitterDelay(), maxJitter
);
797 minJitter
= delays
[0].AsUnsigned();
798 maxJitter
= delays
[1].AsUnsigned();
800 if (minJitter
>= 20 && minJitter
<= maxJitter
&& maxJitter
<= 1000)
801 SetAudioJitterDelay(minJitter
, maxJitter
);
803 cerr
<< "Jitter should be between 20 and 1000 milliseconds." << endl
;
808 silenceDetectParams
.m_mode
= args
.HasOption('e') ? OpalSilenceDetector::NoSilenceDetection
809 : OpalSilenceDetector::AdaptiveSilenceDetection
;
811 if (args
.HasOption('D'))
812 SetMediaFormatMask(args
.GetOptionString('D').Lines());
813 if (args
.HasOption('P'))
814 SetMediaFormatOrder(args
.GetOptionString('P').Lines());
816 cout
<< "Jitter buffer: " << GetMinAudioJitterDelay() << '-' << GetMaxAudioJitterDelay() << " ms\n";
818 if (args
.HasOption("translate")) {
819 SetTranslationAddress(args
.GetOptionString("translate"));
820 cout
<< "External address set to " << GetTranslationAddress() << '\n';
823 if (args
.HasOption("portbase")) {
824 unsigned portbase
= args
.GetOptionString("portbase").AsUnsigned();
825 unsigned portmax
= args
.GetOptionString("portmax").AsUnsigned();
826 SetTCPPorts (portbase
, portmax
);
827 SetUDPPorts (portbase
, portmax
);
828 SetRtpIpPorts(portbase
, portmax
);
830 if (args
.HasOption("tcp-base"))
831 SetTCPPorts(args
.GetOptionString("tcp-base").AsUnsigned(),
832 args
.GetOptionString("tcp-max").AsUnsigned());
834 if (args
.HasOption("udp-base"))
835 SetUDPPorts(args
.GetOptionString("udp-base").AsUnsigned(),
836 args
.GetOptionString("udp-max").AsUnsigned());
838 if (args
.HasOption("rtp-base"))
839 SetRtpIpPorts(args
.GetOptionString("rtp-base").AsUnsigned(),
840 args
.GetOptionString("rtp-max").AsUnsigned());
843 if (args
.HasOption("rtp-tos")) {
844 unsigned tos
= args
.GetOptionString("rtp-tos").AsUnsigned();
846 cerr
<< "IP Type Of Service bits must be 0 to 255." << endl
;
849 SetRtpIpTypeofService(tos
);
852 cout
<< "TCP ports: " << GetTCPPortBase() << '-' << GetTCPPortMax() << "\n"
853 "UDP ports: " << GetUDPPortBase() << '-' << GetUDPPortMax() << "\n"
854 "RTP ports: " << GetRtpIpPortBase() << '-' << GetRtpIpPortMax() << "\n"
855 "RTP IP TOS: 0x" << hex
<< (unsigned)GetRtpIpTypeofService() << dec
<< "\n"
856 "STUN server: " << flush
;
858 if (args
.HasOption("stun"))
859 SetSTUNServer(args
.GetOptionString("stun"));
862 cout
<< stun
->GetServer() << " replies " << stun
->GetNatTypeName();
867 OpalMediaFormatList allMediaFormats
;
869 ///////////////////////////////////////
870 // Open the LID if parameter provided, create LID based endpoint
872 if (!args
.HasOption('L')) {
873 PStringArray devices
= args
.GetOptionString("lid").Lines();
874 if (devices
.IsEmpty() || devices
[0] == "*" || devices
[0] == "*:*")
875 devices
= OpalLineInterfaceDevice::GetAllDevices();
876 for (PINDEX d
= 0; d
< devices
.GetSize(); d
++) {
877 PINDEX colon
= devices
[d
].Find(':');
878 OpalLineInterfaceDevice
* lid
= OpalLineInterfaceDevice::Create(devices
[d
].Left(colon
));
879 if (lid
->Open(devices
[d
].Mid(colon
+1).Trim())) {
880 if (args
.HasOption("country")) {
881 PString country
= args
.GetOptionString("country");
882 if (!lid
->SetCountryCodeName(country
))
883 cerr
<< "Could not set LID to country name \"" << country
<< '"' << endl
;
886 // Create LID protocol handler, automatically adds to manager
888 potsEP
= new OpalPOTSEndPoint(*this);
889 if (potsEP
->AddDevice(lid
)) {
890 cout
<< "Line interface device \"" << devices
[d
] << "\" added." << endl
;
891 allMediaFormats
+= potsEP
->GetMediaFormats();
895 cerr
<< "Could not open device \"" << devices
[d
] << '"' << endl
;
902 ///////////////////////////////////////
903 // Create PC Sound System handler
905 if (!args
.HasOption('S')) {
906 pcssEP
= new MyPCSSEndPoint(*this);
908 pcssEP
->autoAnswer
= args
.HasOption('a');
909 cout
<< "Auto answer is " << (pcssEP
->autoAnswer
? "on" : "off") << "\n";
911 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Recorder
))
913 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Player
))
915 if (!pcssEP
->SetSoundDevice(args
, "sound-in", PSoundChannel::Recorder
))
917 if (!pcssEP
->SetSoundDevice(args
, "sound-out", PSoundChannel::Player
))
920 allMediaFormats
+= pcssEP
->GetMediaFormats();
922 cout
<< "Sound output device: \"" << pcssEP
->GetSoundChannelPlayDevice() << "\"\n"
923 "Sound input device: \"" << pcssEP
->GetSoundChannelRecordDevice() << "\"\n"
925 "Video output device: \"" << GetVideoOutputDevice().deviceName
<< "\"\n"
926 "Video input device: \"" << GetVideoInputDevice().deviceName
<< '"'
933 ///////////////////////////////////////
934 // Create H.323 protocol handler
935 if (!args
.HasOption("no-h323")) {
936 h323EP
= new H323EndPoint(*this);
937 if (!InitialiseH323EP(args
, "h323-listen", h323EP
))
940 if (!args
.HasOption("no-h323s")) {
941 h323sEP
= new H323SecureEndPoint(*this);
942 if (!InitialiseH323EP(args
, "h323s-listen", h323sEP
))
951 ///////////////////////////////////////
952 // Create IAX2 protocol handler
954 if (!args
.HasOption("no-iax2")) {
955 iax2EP
= new IAX2EndPoint(*this);
957 if (args
.HasOption('p'))
958 iax2EP
->SetPassword(args
.GetOptionString('p'));
960 if (args
.HasOption('u')) {
961 PStringArray aliases
= args
.GetOptionString('u').Lines();
962 iax2EP
->SetLocalUserName(aliases
[0]);
969 ///////////////////////////////////////
970 // Create SIP protocol handler
972 if (!args
.HasOption("no-sip")) {
973 sipEP
= new SIPEndPoint(*this);
975 if (args
.HasOption("sip-user-agent"))
976 sipEP
->SetUserAgent(args
.GetOptionString("sip-user-agent"));
978 PString str
= args
.GetOptionString("sip-ui");
979 if (str
*= "rfc2833")
980 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsSeparateRFC2833
);
981 else if (str
*= "info-tone")
982 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsTone
);
983 else if (str
*= "info-string")
984 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsString
);
986 if (args
.HasOption("sip-proxy"))
987 sipEP
->SetProxy(args
.GetOptionString("sip-proxy"));
990 sipEP
->SetMIMEForm(args
.HasOption("use-long-mime"));
992 // Get local username, multiple uses of -u indicates additional aliases
993 if (args
.HasOption('u')) {
994 PStringArray aliases
= args
.GetOptionString('u').Lines();
995 sipEP
->SetDefaultLocalPartyName(aliases
[0]);
998 sipEP
->SetRetryTimeouts(10000, 30000);
1000 // Start the listener thread for incoming calls.
1001 PStringArray listeners
= args
.GetOptionString("sip-listen").Lines();
1002 if (!sipEP
->StartListeners(listeners
)) {
1003 cerr
<< "Could not open any SIP listener from "
1004 << setfill(',') << listeners
<< endl
;
1008 if (args
.HasOption('r')) {
1009 PString registrar
= args
.GetOptionString('r');
1010 cout
<< "Using SIP registrar " << registrar
<< " ... " << flush
;
1011 if (sipEP
->Register(registrar
, args
.GetOptionString('u'), args
.GetOptionString('u'), args
.GetOptionString('p'), args
.GetOptionString("sip-domain")))
1016 pauseBeforeDialing
= TRUE
;
1024 ///////////////////////////////////////
1025 // Create IVR protocol handler
1027 if (!args
.HasOption('V')) {
1028 ivrEP
= new OpalIVREndPoint(*this);
1029 if (args
.HasOption('x'))
1030 ivrEP
->SetDefaultVXML(args
.GetOptionString('x'));
1032 allMediaFormats
+= ivrEP
->GetMediaFormats();
1034 PString ttsEngine
= args
.GetOptionString("tts");
1035 if (ttsEngine
.IsEmpty() && PFactory
<PTextToSpeech
>::GetKeyList().size() > 0)
1036 ttsEngine
= PFactory
<PTextToSpeech
>::GetKeyList()[0];
1037 if (!ttsEngine
.IsEmpty())
1038 ivrEP
->SetDefaultTextToSpeech(ttsEngine
);
1043 ///////////////////////////////////////
1044 // Create T38 protocol handler
1046 faxEP
= new OpalFaxEndPoint(*this);
1047 t38EP
= new OpalT38EndPoint(*this);
1051 ///////////////////////////////////////
1052 // Set the dial peers
1054 if (args
.HasOption('d')) {
1055 if (!SetRouteTable(args
.GetOptionString('d').Lines())) {
1056 cerr
<< "No legal entries in dial peer!" << endl
;
1061 if (!args
.HasOption("no-std-dial-peer")) {
1063 // Need to make sure wildcard on source ep type is first or it won't be
1064 // selected in preference to the specific entries below
1066 AddRouteEntry(".*:# = ivr:"); // A hash from anywhere goes to IVR
1070 if (sipEP
!= NULL
) {
1071 AddRouteEntry("pots:.*\\*.*\\*.* = sip:<dn2ip>");
1072 AddRouteEntry("pots:.* = sip:<da>");
1073 AddRouteEntry("pc:.* = sip:<da>");
1078 if (h323EP
!= NULL
) {
1079 AddRouteEntry("pots:.*\\*.*\\*.* = h323:<dn2ip>");
1080 AddRouteEntry("pots:.* = h323:<da>");
1081 AddRouteEntry("pc:.* = h323:<da>");
1083 if (h323sEP
!= NULL
) {
1084 AddRouteEntry("pots:.*\\*.*\\*.* = h323s:<dn2ip>");
1085 AddRouteEntry("pots:.* = h323s:<da>");
1086 AddRouteEntry("pc:.* = h323s:<da>");
1093 if (potsEP
!= NULL
) {
1095 AddRouteEntry("h323:.* = pots:<da>");
1097 if (h323sEP
!= NULL
)
1098 AddRouteEntry("h323s:.* = pots:<da>");
1102 AddRouteEntry("sip:.* = pots:<da>");
1107 if (pcssEP
!= NULL
) {
1109 AddRouteEntry("h323:.* = pc:<da>");
1111 if (h323sEP
!= NULL
)
1112 AddRouteEntry("h323s:.* = pc:<da>");
1116 AddRouteEntry("sip:.* = pc:<da>");
1122 if (pcssEP
!= NULL
) {
1123 AddRouteEntry("iax2:.* = pc:<da>");
1124 AddRouteEntry("pc:.* = iax2:<da>");
1128 srcEP
= args
.GetOptionString("srcep", pcssEP
!= NULL
? "pc:*"
1130 : potsEP
!= NULL
? "pots:*"
1133 : ivrEP
!= NULL
? "ivr:#"
1136 : sipEP
!= NULL
? "sip:localhost"
1139 : h323EP
!= NULL
? "sip:localhost"
1143 cout
<< "Local endpoint type: " << srcEP
<< "\n"
1144 "Codecs removed: " << setfill(',') << GetMediaFormatMask() << "\n"
1145 "Codec order: " << GetMediaFormatOrder() << "\n"
1146 "Available codecs: " << OpalTranscoder::GetPossibleFormats(allMediaFormats
) << setfill(' ') << endl
;
1153 BOOL
MyManager::InitialiseH323EP(PArgList
& args
, const PString
& listenOption
, H323EndPoint
* h323EP
)
1155 h323EP
->DisableFastStart(args
.HasOption('f'));
1156 h323EP
->DisableH245Tunneling(args
.HasOption('T'));
1157 h323EP
->SetSendGRQ(!args
.HasOption("disable-grq"));
1160 // Get local username, multiple uses of -u indicates additional aliases
1161 if (args
.HasOption('u')) {
1162 PStringArray aliases
= args
.GetOptionString('u').Lines();
1163 h323EP
->SetLocalUserName(aliases
[0]);
1164 for (PINDEX i
= 1; i
< aliases
.GetSize(); i
++)
1165 h323EP
->AddAliasName(aliases
[i
]);
1168 if (args
.HasOption('b')) {
1169 unsigned initialBandwidth
= args
.GetOptionString('b').AsUnsigned()*100;
1170 if (initialBandwidth
== 0) {
1171 cerr
<< "Illegal bandwidth specified." << endl
;
1174 h323EP
->SetInitialBandwidth(initialBandwidth
);
1177 h323EP
->SetGkAccessTokenOID(args
.GetOptionString("gk-token"));
1179 PString prefix
= h323EP
->GetPrefixName();
1181 cout
<< prefix
<< " Local username: " << h323EP
->GetLocalUserName() << "\n"
1182 << prefix
<< " FastConnect is " << (h323EP
->IsFastStartDisabled() ? "off" : "on") << "\n"
1183 << prefix
<< " H245Tunnelling is " << (h323EP
->IsH245TunnelingDisabled() ? "off" : "on") << "\n"
1184 << prefix
<< " gk Token OID is " << h323EP
->GetGkAccessTokenOID() << endl
;
1187 // Start the listener thread for incoming calls.
1188 PStringArray listeners
= args
.GetOptionString(listenOption
).Lines();
1189 if (!h323EP
->StartListeners(listeners
)) {
1190 cerr
<< "Could not open any " << prefix
<< " listener from "
1191 << setfill(',') << listeners
<< endl
;
1194 cout
<< prefix
<< " listeners: " << setfill(',') << h323EP
->GetListeners() << setfill(' ') << endl
;
1197 if (args
.HasOption('p'))
1198 h323EP
->SetGatekeeperPassword(args
.GetOptionString('p'));
1200 // Establish link with gatekeeper if required.
1201 if (!args
.HasOption('n')) {
1202 PString gkHost
= args
.GetOptionString('g');
1203 PString gkIdentifer
= args
.GetOptionString('G');
1204 PString gkInterface
= args
.GetOptionString("h323-listen");
1205 cout
<< "Gatekeeper: " << flush
;
1206 if (h323EP
->UseGatekeeper(gkHost
, gkIdentifer
, gkInterface
))
1207 cout
<< *h323EP
->GetGatekeeper() << endl
;
1209 cout
<< "none." << endl
;
1210 cerr
<< "Could not register with gatekeeper";
1212 cerr
<< " id \"" << gkIdentifer
<< '"';
1214 cerr
<< " at \"" << gkHost
<< '"';
1216 cerr
<< " on interface \"" << gkInterface
<< '"';
1217 if (h323EP
->GetGatekeeper() != NULL
) {
1218 switch (h323EP
->GetGatekeeper()->GetRegistrationFailReason()) {
1219 case H323Gatekeeper::InvalidListener
:
1220 cerr
<< " - Invalid listener";
1222 case H323Gatekeeper::DuplicateAlias
:
1223 cerr
<< " - Duplicate alias";
1225 case H323Gatekeeper::SecurityDenied
:
1226 cerr
<< " - Security denied";
1228 case H323Gatekeeper::TransportError
:
1229 cerr
<< " - Transport error";
1232 cerr
<< " - Error code " << h323EP
->GetGatekeeper()->GetRegistrationFailReason();
1235 cerr
<< '.' << endl
;
1236 if (args
.HasOption("require-gatekeeper"))
1246 void MyManager::NewSpeedDial(const PString
& ostr
)
1249 PINDEX idx
= str
.Find(' ');
1250 if (str
.IsEmpty() || (idx
== P_MAX_INDEX
)) {
1251 cout
<< "Must specify speedial number and string" << endl
;
1255 PString key
= str
.Left(idx
).Trim();
1256 PString data
= str
.Mid(idx
).Trim();
1258 PConfig
config("Speeddial");
1259 config
.SetString(key
, data
);
1261 cout
<< "Speedial " << key
<< " set to " << data
<< endl
;
1265 void MyManager::Main(PArgList
& args
)
1267 OpalConnection::StringOptions stringOptions
;
1269 // See if making a call or just listening.
1270 switch (args
.GetCount()) {
1272 cout
<< "Waiting for incoming calls\n";
1276 if (pauseBeforeDialing
) {
1277 cout
<< "Pausing to allow registration to occur..." << flush
;
1278 PThread::Sleep(2000);
1279 cout
<< "done" << endl
;
1282 cout
<< "Initiating call to \"" << args
[0] << "\"\n";
1283 SetUpCall(srcEP
, args
[0], currentCallToken
, 0, 0, &stringOptions
);
1287 if (pauseBeforeDialing
) {
1288 cout
<< "Pausing to allow registration to occur..." << flush
;
1289 PThread::Sleep(2000);
1290 cout
<< "done" << endl
;
1292 cout
<< "Initiating call from \"" << args
[0] << "\"to \"" << args
[1] << "\"\n";
1293 SetUpCall(args
[0], args
[1], currentCallToken
);
1297 if (args
.HasOption("disableui")) {
1298 while (FindCallWithLock(currentCallToken
) != NULL
)
1299 PThread::Sleep(1000);
1302 cout
<< "Press ? for help." << endl
;
1307 " 0-9 : send user indication message\n"
1308 " *,# : send user indication message\n"
1309 " M : send text message to remote user\n"
1310 " C : connect to remote host\n"
1311 " S : Display statistics\n"
1312 " H : Hang up phone\n"
1313 " L : List speed dials\n"
1314 " D : Create new speed dial\n"
1315 " {} : Increase/reduce record volume\n"
1316 " [] : Increase/reduce playback volume\n"
1317 " V : Display current volumes\n";
1319 PConsoleChannel
console(PConsoleChannel::StandardInput
);
1321 // display the prompt
1322 cout
<< "Command ? " << flush
;
1325 // terminate the menu loop if console finished
1326 char ch
= (char)console
.peek();
1327 if (console
.eof()) {
1328 cout
<< "\nConsole gone - menu disabled" << endl
;
1333 PTRACE(3, "console in audio test is " << ch
);
1334 switch (tolower(ch
)) {
1344 if (pcssEP
!= NULL
&& !pcssEP
->incomingConnectionToken
) {
1345 if (!pcssEP
->AcceptIncomingConnection(pcssEP
->incomingConnectionToken
))
1346 cout
<< "Could not answer connection " << pcssEP
->incomingConnectionToken
<< endl
;
1348 console
.ignore(INT_MAX
, '\n');
1352 if (pcssEP
!= NULL
&& !pcssEP
->incomingConnectionToken
) {
1353 PSafePtr
<OpalConnection
> connection
= pcssEP
->GetConnectionWithLock(pcssEP
->incomingConnectionToken
);
1354 if (connection
!= NULL
) {
1355 cout
<< "Clearing connection " << *connection
<< endl
;
1356 connection
->Release(OpalConnection::EndedByAnswerDenied
);
1359 console
.ignore(INT_MAX
, '\n');
1370 NewSpeedDial(str
.Trim());
1375 HangupCurrentCall();
1379 if (!currentCallToken
.IsEmpty())
1380 cout
<< "Cannot make call whilst call in progress\n";
1384 StartCall(str
.Trim());
1389 cout
<< " current call token is \"" << currentCallToken
<< "\" " << endl
;
1393 if (currentCallToken
.IsEmpty())
1394 cout
<< "Cannot send a message while no call in progress\n";
1398 SendMessageToRemoteNode(str
);
1403 if (ch
>= '0' || ch
<= '9' || ch
== '*' || ch
== '#') {
1404 if (currentCallToken
.IsEmpty())
1405 cout
<< "Cannot send a digit while no call in progress\n";
1413 if (!currentCallToken
.IsEmpty())
1414 HangupCurrentCall();
1417 cout
<< "Console finished " << endl
;
1420 void MyManager::HangupCurrentCall()
1422 PSafePtr
<OpalCall
> call
= FindCallWithLock(currentCallToken
);
1424 cout
<< "Clearing call " << *call
<< endl
;
1426 currentCallToken
= PString();
1429 cout
<< "Not in a call!\n";
1432 void MyManager::SendMessageToRemoteNode(const PString
& ostr
)
1434 PString str
= ostr
.Trim();
1435 if (str
.IsEmpty()) {
1436 cout
<< "Must supply a message to send!\n";
1440 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1441 PStringList res
= endpoints
[i
].GetAllConnections();
1442 if (res
.GetSize() == 0)
1445 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1446 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1448 conn
->SendUserInputString(str
);
1449 cout
<< "Send \"" << str
<< "\" to " << res
[j
] << endl
;
1456 void MyManager::SendTone(const char tone
)
1458 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1459 PStringList res
= endpoints
[i
].GetAllConnections();
1460 if (res
.GetSize() == 0)
1463 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1464 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1466 conn
->SendUserInputTone(tone
, 0);
1467 cout
<< "Send \"" << tone
<< "\" to " << res
[j
] << endl
;
1474 void MyManager::StartCall(const PString
& ostr
)
1476 PString str
= ostr
.Trim();
1477 if (str
.IsEmpty()) {
1478 cout
<< "Must supply hostname to connect to!\n";
1482 // check for speed dials, and match wild cards as we go
1483 PString key
, prefix
;
1484 if ((str
.GetLength() > 1) && (str
[str
.GetLength()-1] == '#')) {
1486 key
= str
.Left(str
.GetLength()-1).Trim();
1488 PConfig
config("Speeddial");
1490 for (p
= key
.GetLength(); p
> 0; p
--) {
1492 PString newKey
= key
.Left(p
);
1496 // look for wild cards
1497 str
= config
.GetString(newKey
+ '*').Trim();
1501 // look for digit matches
1502 for (q
= p
; q
< key
.GetLength(); q
++)
1504 str
= config
.GetString(newKey
).Trim();
1508 if (str
.IsEmpty()) {
1509 cout
<< "Speed dial \"" << key
<< "\" not defined";
1515 SetUpCall(srcEP
, str
, currentCallToken
);
1520 void MyManager::ListSpeedDials()
1522 PConfig
config("Speeddial");
1523 PStringList keys
= config
.GetKeys();
1524 if (keys
.GetSize() == 0) {
1525 cout
<< "No speed dials defined" << endl
;
1530 for (i
= 0; i
< keys
.GetSize(); i
++)
1531 cout
<< keys
[i
] << ": " << config
.GetString(keys
[i
]) << endl
;
1534 void MyManager::OnEstablishedCall(OpalCall
& call
)
1536 currentCallToken
= call
.GetToken();
1537 cout
<< "In call with " << call
.GetPartyB() << " using " << call
.GetPartyA() << endl
;
1540 void MyManager::OnClearedCall(OpalCall
& call
)
1542 if (currentCallToken
== call
.GetToken())
1543 currentCallToken
= PString();
1545 PString remoteName
= '"' + call
.GetPartyB() + '"';
1546 switch (call
.GetCallEndReason()) {
1547 case OpalConnection::EndedByRemoteUser
:
1548 cout
<< remoteName
<< " has cleared the call";
1550 case OpalConnection::EndedByCallerAbort
:
1551 cout
<< remoteName
<< " has stopped calling";
1553 case OpalConnection::EndedByRefusal
:
1554 cout
<< remoteName
<< " did not accept your call";
1556 case OpalConnection::EndedByNoAnswer
:
1557 cout
<< remoteName
<< " did not answer your call";
1559 case OpalConnection::EndedByTransportFail
:
1560 cout
<< "Call with " << remoteName
<< " ended abnormally";
1562 case OpalConnection::EndedByCapabilityExchange
:
1563 cout
<< "Could not find common codec with " << remoteName
;
1565 case OpalConnection::EndedByNoAccept
:
1566 cout
<< "Did not accept incoming call from " << remoteName
;
1568 case OpalConnection::EndedByAnswerDenied
:
1569 cout
<< "Refused incoming call from " << remoteName
;
1571 case OpalConnection::EndedByNoUser
:
1572 cout
<< "Gatekeeper or registrar could not find user " << remoteName
;
1574 case OpalConnection::EndedByNoBandwidth
:
1575 cout
<< "Call to " << remoteName
<< " aborted, insufficient bandwidth.";
1577 case OpalConnection::EndedByUnreachable
:
1578 cout
<< remoteName
<< " could not be reached.";
1580 case OpalConnection::EndedByNoEndPoint
:
1581 cout
<< "No phone running for " << remoteName
;
1583 case OpalConnection::EndedByHostOffline
:
1584 cout
<< remoteName
<< " is not online.";
1586 case OpalConnection::EndedByConnectFail
:
1587 cout
<< "Transport error calling " << remoteName
;
1590 cout
<< "Call with " << remoteName
<< " completed";
1593 cout
<< ", on " << now
.AsString("w h:mma") << ". Duration "
1594 << setprecision(0) << setw(5) << (now
- call
.GetStartTime())
1597 OpalManager::OnClearedCall(call
);
1601 BOOL
MyManager::OnOpenMediaStream(OpalConnection
& connection
,
1602 OpalMediaStream
& stream
)
1604 if (!OpalManager::OnOpenMediaStream(connection
, stream
))
1609 PCaselessString prefix
= connection
.GetEndPoint().GetPrefixName();
1610 if (prefix
== "pc" || prefix
== "pots")
1611 cout
<< (stream
.IsSink() ? "playing " : "grabbing ") << stream
.GetMediaFormat();
1612 else if (prefix
== "ivr")
1613 cout
<< (stream
.IsSink() ? "streaming " : "recording ") << stream
.GetMediaFormat();
1615 cout
<< (stream
.IsSink() ? "sending " : "receiving ") << stream
.GetMediaFormat()
1616 << (stream
.IsSink() ? " to " : " from ")<< prefix
;
1625 void MyManager::OnUserInputString(OpalConnection
& connection
, const PString
& value
)
1627 cout
<< "User input received: \"" << value
<< '"' << endl
;
1628 OpalManager::OnUserInputString(connection
, value
);
1632 ///////////////////////////////////////////////////////////////
1634 MyPCSSEndPoint::MyPCSSEndPoint(MyManager
& mgr
)
1635 : OpalPCSSEndPoint(mgr
)
1640 BOOL
MyPCSSEndPoint::OnShowIncoming(const OpalPCSSConnection
& connection
)
1642 incomingConnectionToken
= connection
.GetToken();
1645 AcceptIncomingConnection(incomingConnectionToken
);
1648 cout
<< "\nCall on " << now
.AsString("w h:mma")
1649 << " from " << connection
.GetRemotePartyName()
1650 << ", answer (Y/N)? " << flush
;
1657 BOOL
MyPCSSEndPoint::OnShowOutgoing(const OpalPCSSConnection
& connection
)
1660 cout
<< connection
.GetRemotePartyName() << " is ringing on "
1661 << now
.AsString("w h:mma") << " ..." << endl
;
1666 BOOL
MyPCSSEndPoint::SetSoundDevice(PArgList
& args
,
1667 const char * optionName
,
1668 PSoundChannel::Directions dir
)
1670 if (!args
.HasOption(optionName
))
1673 PString dev
= args
.GetOptionString(optionName
);
1675 if (dir
== PSoundChannel::Player
) {
1676 if (SetSoundChannelPlayDevice(dev
))
1680 if (SetSoundChannelRecordDevice(dev
))
1684 cerr
<< "Device for " << optionName
<< " (\"" << dev
<< "\") must be one of:\n";
1686 PStringArray names
= PSoundChannel::GetDeviceNames(dir
);
1687 for (PINDEX i
= 0; i
< names
.GetSize(); i
++)
1688 cerr
<< " \"" << names
[i
] << "\"\n";
1694 // End of File ///////////////////////////////////////////////////////////////