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.83 2007/03/29 08:32:22 csoutheren
26 * Pause before dialing when using two endpoint mode
28 * Revision 2.82 2007/03/29 05:24:00 csoutheren
29 * Add support for T.38
31 * Revision 2.81 2007/03/01 05:07:32 csoutheren
32 * Only include video code when video enabled
34 * Revision 2.80 2006/11/01 00:46:40 csoutheren
35 * Implement video output file device
37 * Revision 2.79 2006/10/31 04:41:47 csoutheren
38 * Add support for new methods needed for vidfiledevices
40 * Revision 2.78 2006/10/28 00:39:42 rjongbloed
41 * Added argument to set country on LID
43 * Revision 2.77 2006/10/22 12:09:57 rjongbloed
44 * Fixed minor error in user output string.
46 * Revision 2.76 2006/10/15 06:12:48 rjongbloed
47 * Fixed correct local A-Party endpoint type depending on compiler flags and command line arguments.
48 * Fixed being able to select IVR via wildcard (routing table order) on source endpoint type.
49 * Fixed correctly trimming spaces from POTS device name.
51 * Revision 2.75 2006/10/10 07:18:18 csoutheren
52 * Allow compilation with and without various options
54 * Revision 2.74 2006/10/05 07:11:49 csoutheren
55 * Add --disable-lid option
57 * Revision 2.73 2006/10/02 13:30:51 rjongbloed
60 * Revision 2.72 2006/08/29 01:37:11 csoutheren
61 * Change secure URLs to use h323s and tcps to be inline with sips
63 * Revision 2.71 2006/08/21 05:30:48 csoutheren
64 * Add support for sh323
66 * Revision 2.70 2006/08/01 12:46:32 rjongbloed
67 * Added build solution for plug ins
68 * Removed now redundent code due to plug ins addition
70 * Revision 2.69 2006/07/24 14:03:39 csoutheren
71 * Merged in audio and video plugins from CVS branch PluginBranch
73 * Revision 2.68 2006/07/21 00:38:31 csoutheren
74 * Applied 1483215 - Opal simpleOPAL deadlock patch & DTMF support
77 * Revision 2.67 2006/07/03 03:28:44 dereksmithies
78 * Fix arg handling on disableui, and look for args to srcep, not srcEp
80 * Revision 2.66 2006/06/26 02:03:07 csoutheren
81 * Fixed problem when no TTS code installed
83 * Revision 2.65 2006/06/05 05:26:39 csoutheren
84 * Added ability to test outgoing SIP INFO messages
86 * Revision 2.64 2006/04/30 14:42:00 dereksmithies
87 * Fix compile Sleep statement so it compiles on unix.
89 * Revision 2.63 2006/04/30 14:36:54 csoutheren
90 * backports from PLuginBranch
92 * Revision 2.62 2006/04/30 14:34:42 csoutheren
93 * Backport of IVR updates from PluginBranch
95 * Revision 2.60.2.4 2006/04/30 14:28:25 csoutheren
96 * Added disableui and srcep options
98 * Revision 2.60.2.3 2006/04/30 13:50:29 csoutheren
99 * Add ability to set TextToSpeech algorithm
100 * Revision 2.60.2.2 2006/04/10 08:54:11 csoutheren
101 * Fix problem when H323 disabled
103 * Revision 2.60.2.1 2006/03/20 02:25:26 csoutheren
104 * Backports from CVS head
106 * Revision 2.61 2006/03/07 11:24:15 csoutheren
107 * Add --disable-grq flag
109 * Revision 2.60 2006/01/23 22:56:57 csoutheren
110 * Added 2 second pause before dialling outgoing SIP calls from command line args when
113 * Revision 2.59 2005/12/11 19:14:21 dsandras
114 * Added support for setting a different user name and authentication user name
115 * as required by some providers like digisip.
117 * Revision 2.58 2005/11/07 02:27:48 dereksmithies
118 * Get the answer call Y/N mechanism to work correctly.
120 * Revision 2.57 2005/09/06 04:58:42 dereksmithies
121 * Add console input options. This is an initial release, and some "refinement"
124 * Revision 2.56 2005/08/20 09:03:10 rjongbloed
125 * Some cosmetic fixes in output messages
127 * Revision 2.55 2005/08/13 09:16:18 rjongbloed
128 * Added no-Xt-video to "usage" output
130 * Revision 2.54 2005/08/04 08:47:38 rjongbloed
131 * Some cosmetic changes, and print out the codecs that are available
133 * Revision 2.53 2005/07/30 07:42:15 csoutheren
134 * Added IAX2 functions
136 * Revision 2.52 2005/07/24 07:56:35 rjongbloed
137 * Removed -l parameter, as it always listens.
139 * Revision 2.51 2005/07/11 01:57:31 csoutheren
140 * Fixed error message
142 * Revision 2.50 2005/06/23 06:14:02 csoutheren
143 * Fixed rtp-tos argument parsing. Thanks to Paul Nader
145 * Revision 2.49 2005/06/09 04:51:58 dereksmithies
148 * Revision 2.48 2005/06/09 04:45:57 dereksmithies
149 * Correctly close the incoming connection if the user rejects the incoming call.
150 * Thanks to Robert Jongbloed for some helpful advice.
152 * Revision 2.47 2005/03/11 18:12:09 dsandras
153 * 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.
155 * Revision 2.46 2005/02/19 22:46:19 dsandras
156 * Temporarily removed support for SetDomain.
158 * Revision 2.45 2004/11/29 08:20:04 csoutheren
159 * Added support for setting SIP authentication domain
161 * Revision 2.44 2004/08/18 07:14:00 csoutheren
162 * Called ancestor OnClearedCall
164 * Revision 2.43 2004/08/14 07:56:30 rjongbloed
165 * Major revision to utilise the PSafeCollection classes for the connections and calls.
167 * Revision 2.42 2004/04/26 07:06:07 rjongbloed
168 * Removed some ancient pieces of code and used new API's for them.
170 * Revision 2.41 2004/04/26 06:33:18 rjongbloed
171 * Added ability to specify more than one defualt listener for an endpoint,
172 * required by SIP which listens on both UDP and TCP.
174 * Revision 2.40 2004/04/25 09:32:48 rjongbloed
175 * Fixed correct usage of HAS_IXJ
177 * Revision 2.39 2004/03/29 10:53:23 rjongbloed
178 * Fixed missing mutex unlock which would invariably cause a deadlock.
180 * Revision 2.38 2004/03/22 10:20:34 rjongbloed
181 * Changed to use UseGatekeeper() function so can select by gk-id as well as host.
183 * Revision 2.37 2004/03/14 11:32:20 rjongbloed
184 * Changes to better support SIP proxies.
186 * Revision 2.36 2004/03/14 08:34:09 csoutheren
187 * Added ability to set User-Agent string
189 * Revision 2.35 2004/03/14 06:15:36 rjongbloed
190 * Must set ports before stun as stun code uses those port numbers.
192 * Revision 2.34 2004/03/13 06:32:17 rjongbloed
193 * Fixes for removal of SIP and H.323 subsystems.
194 * More registration work.
196 * Revision 2.33 2004/03/11 06:54:27 csoutheren
197 * Added ability to disable SIP or H.323 stacks
199 * Revision 2.32 2004/03/09 12:09:56 rjongbloed
200 * More work on SIP register.
202 * Revision 2.31 2004/02/24 11:37:01 rjongbloed
203 * More work on NAT support, manual external address translation and STUN
205 * Revision 2.30 2004/02/21 02:41:10 rjongbloed
206 * Tidied up the translate address to utilise more of the library infrastructure.
207 * Changed cmd line args port-base/port-max to portbase/portmax, same as OhPhone.
209 * Revision 2.29 2004/02/17 11:00:06 csoutheren
210 * Added --translate, --port-base and --port-max options
212 * Revision 2.28 2004/02/03 12:22:28 rjongbloed
215 * Revision 2.27 2004/01/18 15:36:07 rjongbloed
218 * Revision 2.26 2003/04/09 01:38:27 robertj
219 * Changed default to not send/receive video and added options to turn it on.
221 * Revision 2.25 2003/03/26 03:51:46 robertj
222 * Fixed failure to compile if not statically linked.
224 * Revision 2.24 2003/03/24 07:18:29 robertj
225 * Added registration system for LIDs so can work with various LID types by
226 * name instead of class instance.
228 * Revision 2.23 2003/03/19 02:30:45 robertj
229 * Added removal of IVR stuff if EXPAT is not installed on system.
231 * Revision 2.22 2003/03/17 08:12:08 robertj
232 * Added protocol name to media stream open output.
234 * Revision 2.21 2003/03/07 08:18:47 robertj
235 * Fixed naming convention of PC sound system in routing table.
237 * Revision 2.20 2003/03/07 05:56:47 robertj
238 * Changed so a # from whatever source routes to IVR.
240 * Revision 2.19 2003/03/06 03:57:47 robertj
241 * IVR support (work in progress) requiring large changes everywhere.
243 * Revision 2.18 2002/11/11 06:52:01 robertj
244 * Added correct flag for including static global variables.
246 * Revision 2.17 2002/11/10 11:33:17 robertj
247 * Updated to OpenH323 v1.10.3
249 * Revision 2.16 2002/09/06 02:46:00 robertj
250 * Added routing table system to route calls by regular expressions.
251 * Added ability to set gatekeeper access token OID and password.
253 * Revision 2.15 2002/07/01 09:05:54 robertj
254 * Changed TCp/UDP port allocation to use new thread safe functions.
256 * Revision 2.14 2002/04/12 14:02:41 robertj
257 * Separated interface option for SIP and H.323.
259 * Revision 2.13 2002/03/27 05:34:55 robertj
260 * Removed redundent busy forward field.
261 * Added ability to set tcp and udp port bases.
263 * Revision 2.12 2002/03/27 04:36:46 robertj
264 * Changed to add all possible xJack cards to pots endpoint.
266 * Revision 2.11 2002/03/27 04:16:20 robertj
267 * Restructured default router for sample to allow more options.
269 * Revision 2.10 2002/02/13 08:17:31 robertj
270 * Changed routing algorithm to route call to H323/SIP if contains an '@'
272 * Revision 2.9 2002/02/11 09:45:35 robertj
273 * Moved version file to library root directoy
275 * Revision 2.8 2002/02/06 13:29:03 rogerh
276 * H245 tunnelling is controlled by 'T' and not by 'h'
278 * Revision 2.7 2002/02/01 04:53:01 robertj
279 * Added (very primitive!) SIP support.
281 * Revision 2.6 2002/01/22 05:34:58 robertj
282 * Revamp of user input API triggered by RFC2833 support
284 * Revision 2.5 2001/08/21 11:18:55 robertj
285 * Added conditional compile for xJack code.
287 * Revision 2.4 2001/08/17 08:35:41 robertj
288 * Changed OnEstablished() to OnEstablishedCall() to be consistent.
289 * Moved call end reasons enum from OpalConnection to global.
290 * Used LID management in lid EP.
291 * More implementation.
293 * Revision 2.3 2001/08/01 06:19:00 robertj
294 * Added flags for disabling H.323 or Quicknet endpoints.
296 * Revision 2.2 2001/08/01 05:48:30 robertj
297 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
298 * Fixed loading of transcoders from static library.
300 * Revision 2.1 2001/07/30 07:22:25 robertj
301 * Abstracted listener management from H.323 to OpalEndPoint class.
303 * Revision 2.0 2001/07/27 15:48:24 robertj
304 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
306 * Revision 1.12 2001/07/13 08:44:16 robertj
307 * Fixed incorrect inclusion of hardware codec capabilities.
309 * Revision 1.11 2001/05/17 07:11:29 robertj
310 * Added more call end types for common transport failure modes.
312 * Revision 1.10 2001/05/14 05:56:26 robertj
313 * Added H323 capability registration system so can add capabilities by
314 * string name instead of having to instantiate explicit classes.
316 * Revision 1.9 2001/03/21 04:52:40 robertj
317 * Added H.235 security to gatekeepers, thanks Fürbass Franz!
319 * Revision 1.8 2001/03/20 23:42:55 robertj
320 * Used the new PTrace::Initialise function for starting trace code.
322 * Revision 1.7 2000/10/16 08:49:31 robertj
323 * Added single function to add all UserInput capability types.
325 * Revision 1.6 2000/07/31 14:08:09 robertj
326 * Added fast start and H.245 tunneling flags to the H323Connection constructor so can
327 * disabled these features in easier manner to overriding virtuals.
329 * Revision 1.5 2000/06/20 02:38:27 robertj
330 * Changed H323TransportAddress to default to IP.
332 * Revision 1.4 2000/06/07 05:47:55 robertj
333 * Added call forwarding.
335 * Revision 1.3 2000/05/23 11:32:27 robertj
336 * Rewrite of capability table to combine 2 structures into one and move functionality into that class
337 * allowing some normalisation of usage across several applications.
338 * Changed H323Connection so gets a copy of capabilities instead of using endponts, allows adjustments
339 * to be done depending on the remote client application.
341 * Revision 1.2 2000/05/11 10:00:02 robertj
342 * Fixed setting and resetting of current call token variable.
344 * Revision 1.1 2000/05/11 04:05:57 robertj
345 * Simple sample program.
351 #include <opal/buildopts.h>
354 #include <iax2/iax2.h>
362 #include <h323/h323.h>
363 #include <h323/gkclient.h>
366 #include <t38/t38proto.h>
368 #include <opal/transcoders.h>
369 #include <lids/lidep.h>
370 #include <ptclib/pstun.h>
371 #include <ptlib/config.h>
374 #include "../../version.h"
380 PCREATE_PROCESS(SimpleOpalProcess
);
382 ///////////////////////////////////////////////////////////////
384 SimpleOpalProcess::SimpleOpalProcess()
385 : PProcess("Open Phone Abstraction Library", "SimpleOPAL",
386 MAJOR_VERSION
, MINOR_VERSION
, BUILD_TYPE
, BUILD_NUMBER
)
391 void SimpleOpalProcess::Main()
394 << " Version " << GetVersion(TRUE
)
395 << " by " << GetManufacturer()
396 << " on " << GetOSClass() << ' ' << GetOSName()
397 << " (" << GetOSVersion() << '-' << GetOSHardware() << ")\n\n";
399 // Get and parse all of the command line arguments.
400 PArgList
& args
= GetArguments();
437 "R-require-gatekeeper."
453 "T-h245tunneldisable."
466 "-rx-video." "-no-rx-video."
467 "-tx-video." "-no-tx-video."
483 if (args
.HasOption('h') || (!args
.HasOption('l') && args
.GetCount() == 0)) {
484 cout
<< "Usage : " << GetName() << " [options] -l\n"
485 " : " << GetName() << " [options] [alias@]hostname (no gatekeeper)\n"
486 " : " << GetName() << " [options] alias[@hostname] (with gatekeeper)\n"
488 " -l --listen : Listen for incoming calls.\n"
489 " -d --dial-peer spec : Set dial peer for routing calls (see below)\n"
490 " --no-std-dial-peer : Do not include the standard dial peers\n"
491 " -a --auto-answer : Automatically answer incoming calls.\n"
492 " -u --user name : Set local alias name(s) (defaults to login name).\n"
493 " -p --password pwd : Set password for user (gk or SIP authorisation).\n"
494 " -D --disable media : Disable the specified codec (may be used multiple times)\n"
495 " -P --prefer media : Prefer the specified codec (may be used multiple times)\n"
496 " --srcep ep : Set the source endpoint to use for making calls\n"
497 " --disableui : disable the user interface\n"
500 " -j --jitter [min-]max : Set minimum (optional) and maximum jitter buffer (in milliseconds).\n"
501 " -e --silence : Disable transmitter silence detection.\n"
504 " --rx-video : Start receiving video immediately.\n"
505 " --tx-video : Start transmitting video immediately.\n"
506 " --no-rx-video : Don't start receiving video immediately.\n"
507 " --no-tx-video : Don't start transmitting video immediately.\n"
508 " --grabber dev : Set the video grabber driver.\n"
509 " --grabdevice dev : Set the video grabber device.\n"
510 " --grabchannel num : Set the video grabber device channel.\n"
511 " --display dev : Set the video display driver.\n"
512 " --displaydevice dev : Set the video display device.\n"
517 " -I --no-sip : Disable SIP protocol.\n"
518 " -r --register-sip host : Register with SIP server.\n"
519 " --sip-proxy url : SIP proxy information, may be just a host name\n"
520 " : or full URL eg sip:user:pwd@host\n"
521 " --sip-listen iface : Interface/port(s) to listen for SIP requests\n"
522 " : '*' is all interfaces, (default udp$:*:5060)\n"
523 " --sip-user-agent name: SIP UserAgent name to use.\n"
524 " --sip-ui type : Set type of user indications to use for SIP. Can be one of 'rfc2833', 'info-tone', 'info-string'.\n"
525 " --use-long-mime : Use long MIME headers on outgoing SIP messages\n"
526 " --sip-domain str : set authentication domain/realm\n"
532 " -H --no-h323 : Disable H.323 protocol.\n"
533 " -g --gatekeeper host : Specify gatekeeper host.\n"
534 " -G --gk-id name : Specify gatekeeper identifier.\n"
535 " -n --no-gatekeeper : Disable gatekeeper discovery.\n"
536 " -R --require-gatekeeper : Exit if gatekeeper discovery fails.\n"
537 " --gk-token str : Set gatekeeper security token OID.\n"
538 " -b --bandwidth bps : Limit bandwidth usage to bps bits/second.\n"
539 " -f --fast-disable : Disable fast start.\n"
540 " -T --h245tunneldisable : Disable H245 tunnelling.\n"
541 " --h323-listen iface : Interface/port(s) to listen for H.323 requests\n"
543 " --h323s-listen iface : Interface/port(s) to listen for secure H.323 requests\n"
545 " : '*' is all interfaces, (default tcp$:*:1720)\n"
546 " --disable-grq : Do not send GRQ when registering with GK\n"
548 " --no-h323s : Do not creat secure H.323 endpoint\n"
554 "Line Interface options:\n"
555 " -L --no-lid : Do not use line interface device.\n"
556 " --lid device : Select line interface device (eg Quicknet:013A17C2, default *:*).\n"
557 " --country code : Select country to use for LID (eg \"US\", \"au\" or \"+61\").\n"
560 "Sound card options:\n"
561 " -S --no-sound : Do not use sound input/output device.\n"
562 " -s --sound device : Select sound input/output device.\n"
563 " --sound-in device : Select sound input device.\n"
564 " --sound-out device : Select sound output device.\n"
568 " -V --no-ivr : Disable IVR.\n"
569 " -x --vxml file : Set vxml file to use for IVR.\n"
570 " --tts engine : Set the text to speech engine\n"
574 " --translate ip : Set external IP address if masqueraded\n"
575 " --portbase n : Set TCP/UDP/RTP port base\n"
576 " --portmax n : Set TCP/UDP/RTP port max\n"
577 " --tcp-base n : Set TCP port base (default 0)\n"
578 " --tcp-max n : Set TCP port max (default base+99)\n"
579 " --udp-base n : Set UDP port base (default 6000)\n"
580 " --udp-max n : Set UDP port max (default base+199)\n"
581 " --rtp-base n : Set RTP port base (default 5000)\n"
582 " --rtp-max n : Set RTP port max (default base+199)\n"
583 " --rtp-tos n : Set RTP packet IP TOS bits to n\n"
584 " --stun server : Set STUN server\n"
588 " -t --trace : Enable trace, use multiple times for more detail.\n"
589 " -o --output : File for trace output, default is stderr.\n"
592 " -X --no-iax2 : Remove support for iax2\n"
594 " -h --help : This help message.\n"
597 "Dial peer specification:\n"
598 " General form is pattern=destination where pattern is a regular expression\n"
599 " matching the incoming calls destination address and will translate it to\n"
600 " the outgoing destination address for making an outgoing call. For example,\n"
601 " picking up a PhoneJACK handset and dialling 2, 6 would result in an address\n"
602 " of \"pots:26\" which would then be matched against, say, a spec of\n"
603 " pots:26=h323:10.0.1.1, resulting in a call from the pots handset to\n"
604 " 10.0.1.1 using the H.323 protocol.\n"
606 " As the pattern field is a regular expression, you could have used in the\n"
607 " above .*:26=h323:10.0.1.1 to achieve the same result with the addition that\n"
608 " an incoming call from a SIP client would also be routed to the H.323 client.\n"
610 " Note that the pattern has an implicit ^ and $ at the beginning and end of\n"
611 " the regular expression. So it must match the entire address.\n"
613 " If the specification is of the form @filename, then the file is read with\n"
614 " each line consisting of a pattern=destination dial peer specification. Lines\n"
615 " without and equal sign or beginning with '#' are ignored.\n"
617 " The standard dial peers that will be included are:\n"
618 " If SIP is enabled but H.323 & IAX2 are disabled:\n"
619 " pots:.*\\*.*\\*.* = sip:<dn2ip>\n"
620 " pots:.* = sip:<da>\n"
621 " pc:.* = sip:<da>\n"
623 " If SIP & IAX2 are not enabled and H.323 is enabled:\n"
624 " pots:.*\\*.*\\*.* = h323:<dn2ip>\n"
625 " pots:.* = h323:<da>\n"
626 " pc:.* = h323:<da>\n"
628 " If POTS is enabled:\n"
629 " h323:.* = pots:<da>\n"
630 " sip:.* = pots:<da>\n"
631 " iax2:.* = pots:<da>\n"
633 " If POTS is not enabled and the PC sound system is enabled:\n"
634 " iax2:.* = pc:<da>\n"
635 " h323:.* = pc:<da>\n"
636 " sip:. * = pc:<da>\n"
639 " If IVR is enabled then a # from any protocol will route it it, ie:\n"
644 " If IAX2 is enabled then you can make a iax2 call with a command like:\n"
645 " simpleopal -IHn iax2:guest@misery.digium.com/s\n"
652 PTrace::Initialise(args
.GetOptionCount('t'),
653 args
.HasOption('o') ? (const char *)args
.GetOptionString('o') : NULL
,
654 PTrace::Timestamp
|PTrace::Thread
|PTrace::FileAndLine
);
657 // Create the Opal Manager and initialise it
658 opal
= new MyManager
;
660 if (opal
->Initialise(args
))
663 cout
<< "Exiting " << GetName() << endl
;
669 ///////////////////////////////////////////////////////////////
671 MyManager::MyManager()
698 pauseBeforeDialing
= FALSE
;
702 MyManager::~MyManager()
705 // Must do this before we destroy the manager or a crash will result
707 potsEP
->RemoveAllLines();
712 BOOL
MyManager::Initialise(PArgList
& args
)
715 OpalMediaFormat
fmt(OpalT38
);
716 if (!fmt
.IsValid()) {
717 cerr
<< "cannot find t.38" << endl
;
722 OpalMediaFormat::SetRegisteredMediaFormat(fmt
);
726 OpalMediaFormat
fmt("H.261-CIF");
728 fmt
.SetOptionInteger(OpalVideoFormat::EncodingQualityOption
, 16);
729 fmt
.SetOptionBoolean(OpalVideoFormat::AdaptivePacketDelayOption
, TRUE
);
730 OpalMediaFormat::SetRegisteredMediaFormat(fmt
);
733 // Set the various global options
734 if (args
.HasOption("rx-video"))
735 autoStartReceiveVideo
= TRUE
;
736 if (args
.HasOption("no-rx-video"))
737 autoStartReceiveVideo
= FALSE
;
738 if (args
.HasOption("tx-video"))
739 autoStartTransmitVideo
= TRUE
;
740 if (args
.HasOption("no-tx-video"))
741 autoStartTransmitVideo
= FALSE
;
743 if (args
.HasOption("grabber")) {
744 PVideoDevice::OpenArgs video
= GetVideoInputDevice();
745 video
.deviceName
= args
.GetOptionString("grabber");
746 video
.filename
= args
.GetOptionString("grabdevice");
747 video
.channelNumber
= args
.GetOptionString("grabchannel").AsInteger();
748 if (!SetVideoInputDevice(video
)) {
749 cerr
<< "Unknown grabber device " << video
.deviceName
<< endl
750 << "options are:" << setfill(',') << PVideoInputDevice::GetDriversDeviceNames("") << endl
;
755 if (args
.HasOption("display")) {
756 PVideoDevice::OpenArgs video
= GetVideoOutputDevice();
757 video
.deviceName
= args
.GetOptionString("display");
758 video
.filename
= args
.GetOptionString("displaydevice");
759 if (!SetVideoOutputDevice(video
)) {
760 cerr
<< "Unknown display device " << video
.deviceName
<< endl
761 << "options are:" << setfill(',') << PVideoOutputDevice::GetDriversDeviceNames("") << endl
;
767 if (args
.HasOption('j')) {
770 PStringArray delays
= args
.GetOptionString('j').Tokenise(",-");
771 if (delays
.GetSize() < 2) {
772 maxJitter
= delays
[0].AsUnsigned();
773 minJitter
= PMIN(GetMinAudioJitterDelay(), maxJitter
);
776 minJitter
= delays
[0].AsUnsigned();
777 maxJitter
= delays
[1].AsUnsigned();
779 if (minJitter
>= 20 && minJitter
<= maxJitter
&& maxJitter
<= 1000)
780 SetAudioJitterDelay(minJitter
, maxJitter
);
782 cerr
<< "Jitter should be between 20 and 1000 milliseconds." << endl
;
787 silenceDetectParams
.m_mode
= args
.HasOption('e') ? OpalSilenceDetector::NoSilenceDetection
788 : OpalSilenceDetector::AdaptiveSilenceDetection
;
790 if (args
.HasOption('D'))
791 SetMediaFormatMask(args
.GetOptionString('D').Lines());
792 if (args
.HasOption('P'))
793 SetMediaFormatOrder(args
.GetOptionString('P').Lines());
795 cout
<< "Jitter buffer: " << GetMinAudioJitterDelay() << '-' << GetMaxAudioJitterDelay() << " ms\n"
796 "Codecs removed: " << setfill(',') << GetMediaFormatMask() << "\n"
797 "Codec order: " << setfill(',') << GetMediaFormatOrder() << setfill(' ') << '\n';
799 if (args
.HasOption("translate")) {
800 SetTranslationAddress(args
.GetOptionString("translate"));
801 cout
<< "External address set to " << GetTranslationAddress() << '\n';
804 if (args
.HasOption("portbase")) {
805 unsigned portbase
= args
.GetOptionString("portbase").AsUnsigned();
806 unsigned portmax
= args
.GetOptionString("portmax").AsUnsigned();
807 SetTCPPorts (portbase
, portmax
);
808 SetUDPPorts (portbase
, portmax
);
809 SetRtpIpPorts(portbase
, portmax
);
811 if (args
.HasOption("tcp-base"))
812 SetTCPPorts(args
.GetOptionString("tcp-base").AsUnsigned(),
813 args
.GetOptionString("tcp-max").AsUnsigned());
815 if (args
.HasOption("udp-base"))
816 SetUDPPorts(args
.GetOptionString("udp-base").AsUnsigned(),
817 args
.GetOptionString("udp-max").AsUnsigned());
819 if (args
.HasOption("rtp-base"))
820 SetRtpIpPorts(args
.GetOptionString("rtp-base").AsUnsigned(),
821 args
.GetOptionString("rtp-max").AsUnsigned());
824 if (args
.HasOption("rtp-tos")) {
825 unsigned tos
= args
.GetOptionString("rtp-tos").AsUnsigned();
827 cerr
<< "IP Type Of Service bits must be 0 to 255." << endl
;
830 SetRtpIpTypeofService(tos
);
833 cout
<< "TCP ports: " << GetTCPPortBase() << '-' << GetTCPPortMax() << "\n"
834 "UDP ports: " << GetUDPPortBase() << '-' << GetUDPPortMax() << "\n"
835 "RTP ports: " << GetRtpIpPortBase() << '-' << GetRtpIpPortMax() << "\n"
836 "RTP IP TOS: 0x" << hex
<< (unsigned)GetRtpIpTypeofService() << dec
<< "\n"
837 "STUN server: " << flush
;
839 if (args
.HasOption("stun"))
840 SetSTUNServer(args
.GetOptionString("stun"));
843 cout
<< stun
->GetServer() << " replies " << stun
->GetNatTypeName();
849 ///////////////////////////////////////
850 // Open the LID if parameter provided, create LID based endpoint
852 if (!args
.HasOption('L')) {
853 PStringArray devices
= args
.GetOptionString("lid").Lines();
854 if (devices
.IsEmpty() || devices
[0] == "*" || devices
[0] == "*:*")
855 devices
= OpalLineInterfaceDevice::GetAllDevices();
856 for (PINDEX d
= 0; d
< devices
.GetSize(); d
++) {
857 PINDEX colon
= devices
[d
].Find(':');
858 OpalLineInterfaceDevice
* lid
= OpalLineInterfaceDevice::Create(devices
[d
].Left(colon
));
859 if (lid
->Open(devices
[d
].Mid(colon
+1).Trim())) {
860 if (args
.HasOption("country")) {
861 PString country
= args
.GetOptionString("country");
862 if (!lid
->SetCountryCodeName(country
))
863 cerr
<< "Could not set LID to country name \"" << country
<< '"' << endl
;
866 // Create LID protocol handler, automatically adds to manager
868 potsEP
= new OpalPOTSEndPoint(*this);
869 if (potsEP
->AddDevice(lid
))
870 cout
<< "Line interface device \"" << devices
[d
] << "\" added." << endl
;
873 cerr
<< "Could not open device \"" << devices
[d
] << '"' << endl
;
880 ///////////////////////////////////////
881 // Create PC Sound System handler
883 if (!args
.HasOption('S')) {
884 pcssEP
= new MyPCSSEndPoint(*this);
886 pcssEP
->autoAnswer
= args
.HasOption('a');
887 cout
<< "Auto answer is " << (pcssEP
->autoAnswer
? "on" : "off") << "\n";
889 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Recorder
))
891 if (!pcssEP
->SetSoundDevice(args
, "sound", PSoundChannel::Player
))
893 if (!pcssEP
->SetSoundDevice(args
, "sound-in", PSoundChannel::Recorder
))
895 if (!pcssEP
->SetSoundDevice(args
, "sound-out", PSoundChannel::Player
))
898 cout
<< "Sound output device: \"" << pcssEP
->GetSoundChannelPlayDevice() << "\"\n"
899 "Sound input device: \"" << pcssEP
->GetSoundChannelRecordDevice() << "\"\n"
901 "Video output device: \"" << GetVideoOutputDevice().deviceName
<< "\"\n"
902 "Video input device: \"" << GetVideoInputDevice().deviceName
<< "\"\n"
904 "Available codecs: " << setfill(',') << OpalTranscoder::GetPossibleFormats(pcssEP
->GetMediaFormats()) << setfill(' ') << endl
;
909 ///////////////////////////////////////
910 // Create H.323 protocol handler
911 if (!args
.HasOption("no-h323")) {
912 h323EP
= new H323EndPoint(*this);
913 if (!InitialiseH323EP(args
, "h323-listen", h323EP
))
916 if (!args
.HasOption("no-h323s")) {
917 h323sEP
= new H323SecureEndPoint(*this);
918 if (!InitialiseH323EP(args
, "h323s-listen", h323sEP
))
927 ///////////////////////////////////////
928 // Create IAX2 protocol handler
930 if (!args
.HasOption("no-iax2")) {
931 iax2EP
= new IAX2EndPoint(*this);
933 if (args
.HasOption('p'))
934 iax2EP
->SetPassword(args
.GetOptionString('p'));
936 if (args
.HasOption('u')) {
937 PStringArray aliases
= args
.GetOptionString('u').Lines();
938 iax2EP
->SetLocalUserName(aliases
[0]);
945 ///////////////////////////////////////
946 // Create SIP protocol handler
948 if (!args
.HasOption("no-sip")) {
949 sipEP
= new SIPEndPoint(*this);
951 if (args
.HasOption("sip-user-agent"))
952 sipEP
->SetUserAgent(args
.GetOptionString("sip-user-agent"));
954 PString str
= args
.GetOptionString("sip-ui");
955 if (str
*= "rfc2833")
956 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsSeparateRFC2833
);
957 else if (str
*= "info-tone")
958 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsTone
);
959 else if (str
*= "info-string")
960 sipEP
->SetSendUserInputMode(OpalConnection::SendUserInputAsString
);
962 if (args
.HasOption("sip-proxy"))
963 sipEP
->SetProxy(args
.GetOptionString("sip-proxy"));
966 sipEP
->SetMIMEForm(args
.HasOption("use-long-mime"));
968 // Get local username, multiple uses of -u indicates additional aliases
969 if (args
.HasOption('u')) {
970 PStringArray aliases
= args
.GetOptionString('u').Lines();
971 sipEP
->SetDefaultLocalPartyName(aliases
[0]);
974 sipEP
->SetRetryTimeouts(10000, 30000);
976 // Start the listener thread for incoming calls.
977 PStringArray listeners
= args
.GetOptionString("sip-listen").Lines();
978 if (!sipEP
->StartListeners(listeners
)) {
979 cerr
<< "Could not open any SIP listener from "
980 << setfill(',') << listeners
<< endl
;
984 if (args
.HasOption('r')) {
985 PString registrar
= args
.GetOptionString('r');
986 cout
<< "Using SIP registrar " << registrar
<< " ... " << flush
;
987 if (sipEP
->Register(registrar
, args
.GetOptionString('u'), args
.GetOptionString('u'), args
.GetOptionString('p'), args
.GetOptionString("sip-domain")))
992 pauseBeforeDialing
= TRUE
;
1000 ///////////////////////////////////////
1001 // Create IVR protocol handler
1003 if (!args
.HasOption('V')) {
1004 ivrEP
= new OpalIVREndPoint(*this);
1005 if (args
.HasOption('x'))
1006 ivrEP
->SetDefaultVXML(args
.GetOptionString('x'));
1008 PString ttsEngine
= args
.GetOptionString("tts");
1009 if (ttsEngine
.IsEmpty() && PFactory
<PTextToSpeech
>::GetKeyList().size() > 0)
1010 ttsEngine
= PFactory
<PTextToSpeech
>::GetKeyList()[0];
1011 if (!ttsEngine
.IsEmpty())
1012 ivrEP
->SetDefaultTextToSpeech(ttsEngine
);
1017 ///////////////////////////////////////
1018 // Create T38 protocol handler
1020 faxEP
= new OpalFaxEndPoint(*this);
1021 t38EP
= new OpalT38EndPoint(*this);
1025 ///////////////////////////////////////
1026 // Set the dial peers
1028 if (args
.HasOption('d')) {
1029 if (!SetRouteTable(args
.GetOptionString('d').Lines())) {
1030 cerr
<< "No legal entries in dial peer!" << endl
;
1035 if (!args
.HasOption("no-std-dial-peer")) {
1037 // Need to make sure wildcard on source ep type is first or it won't be
1038 // selected in preference to the specific entries below
1040 AddRouteEntry(".*:# = ivr:"); // A hash from anywhere goes to IVR
1044 if (sipEP
!= NULL
) {
1045 AddRouteEntry("pots:.*\\*.*\\*.* = sip:<dn2ip>");
1046 AddRouteEntry("pots:.* = sip:<da>");
1047 AddRouteEntry("pc:.* = sip:<da>");
1052 if (h323EP
!= NULL
) {
1053 AddRouteEntry("pots:.*\\*.*\\*.* = h323:<dn2ip>");
1054 AddRouteEntry("pots:.* = h323:<da>");
1055 AddRouteEntry("pc:.* = h323:<da>");
1057 if (h323sEP
!= NULL
) {
1058 AddRouteEntry("pots:.*\\*.*\\*.* = h323s:<dn2ip>");
1059 AddRouteEntry("pots:.* = h323s:<da>");
1060 AddRouteEntry("pc:.* = h323s:<da>");
1067 if (potsEP
!= NULL
) {
1069 AddRouteEntry("h323:.* = pots:<da>");
1071 if (h323sEP
!= NULL
)
1072 AddRouteEntry("h323s:.* = pots:<da>");
1076 AddRouteEntry("sip:.* = pots:<da>");
1081 if (pcssEP
!= NULL
) {
1083 AddRouteEntry("h323:.* = pc:<da>");
1085 if (h323sEP
!= NULL
)
1086 AddRouteEntry("h323s:.* = pc:<da>");
1090 AddRouteEntry("sip:.* = pc:<da>");
1096 if (pcssEP
!= NULL
) {
1097 AddRouteEntry("iax2:.* = pc:<da>");
1098 AddRouteEntry("pc:.* = iax2:<da>");
1102 srcEP
= args
.GetOptionString("srcep", pcssEP
!= NULL
? "pc:*"
1104 : potsEP
!= NULL
? "pots:*"
1107 : ivrEP
!= NULL
? "ivr:#"
1110 : sipEP
!= NULL
? "sip:localhost"
1113 : h323EP
!= NULL
? "sip:localhost"
1121 BOOL
MyManager::InitialiseH323EP(PArgList
& args
, const PString
& listenOption
, H323EndPoint
* h323EP
)
1123 h323EP
->DisableFastStart(args
.HasOption('f'));
1124 h323EP
->DisableH245Tunneling(args
.HasOption('T'));
1125 h323EP
->SetSendGRQ(!args
.HasOption("disable-grq"));
1128 // Get local username, multiple uses of -u indicates additional aliases
1129 if (args
.HasOption('u')) {
1130 PStringArray aliases
= args
.GetOptionString('u').Lines();
1131 h323EP
->SetLocalUserName(aliases
[0]);
1132 for (PINDEX i
= 1; i
< aliases
.GetSize(); i
++)
1133 h323EP
->AddAliasName(aliases
[i
]);
1136 if (args
.HasOption('b')) {
1137 unsigned initialBandwidth
= args
.GetOptionString('b').AsUnsigned()*100;
1138 if (initialBandwidth
== 0) {
1139 cerr
<< "Illegal bandwidth specified." << endl
;
1142 h323EP
->SetInitialBandwidth(initialBandwidth
);
1145 h323EP
->SetGkAccessTokenOID(args
.GetOptionString("gk-token"));
1147 PString prefix
= h323EP
->GetPrefixName();
1149 cout
<< prefix
<< " Local username: " << h323EP
->GetLocalUserName() << "\n"
1150 << prefix
<< " FastConnect is " << (h323EP
->IsFastStartDisabled() ? "off" : "on") << "\n"
1151 << prefix
<< " H245Tunnelling is " << (h323EP
->IsH245TunnelingDisabled() ? "off" : "on") << "\n"
1152 << prefix
<< " gk Token OID is " << h323EP
->GetGkAccessTokenOID() << endl
;
1155 // Start the listener thread for incoming calls.
1156 PStringArray listeners
= args
.GetOptionString(listenOption
).Lines();
1157 if (!h323EP
->StartListeners(listeners
)) {
1158 cerr
<< "Could not open any " << prefix
<< " listener from "
1159 << setfill(',') << listeners
<< endl
;
1162 cout
<< prefix
<< " listeners: " << setfill(',') << h323EP
->GetListeners() << setfill(' ') << endl
;
1165 if (args
.HasOption('p'))
1166 h323EP
->SetGatekeeperPassword(args
.GetOptionString('p'));
1168 // Establish link with gatekeeper if required.
1169 if (!args
.HasOption('n')) {
1170 PString gkHost
= args
.GetOptionString('g');
1171 PString gkIdentifer
= args
.GetOptionString('G');
1172 PString gkInterface
= args
.GetOptionString("h323-listen");
1173 cout
<< "Gatekeeper: " << flush
;
1174 if (h323EP
->UseGatekeeper(gkHost
, gkIdentifer
, gkInterface
))
1175 cout
<< *h323EP
->GetGatekeeper() << endl
;
1177 cout
<< "none." << endl
;
1178 cerr
<< "Could not register with gatekeeper";
1180 cerr
<< " id \"" << gkIdentifer
<< '"';
1182 cerr
<< " at \"" << gkHost
<< '"';
1184 cerr
<< " on interface \"" << gkInterface
<< '"';
1185 if (h323EP
->GetGatekeeper() != NULL
) {
1186 switch (h323EP
->GetGatekeeper()->GetRegistrationFailReason()) {
1187 case H323Gatekeeper::InvalidListener
:
1188 cerr
<< " - Invalid listener";
1190 case H323Gatekeeper::DuplicateAlias
:
1191 cerr
<< " - Duplicate alias";
1193 case H323Gatekeeper::SecurityDenied
:
1194 cerr
<< " - Security denied";
1196 case H323Gatekeeper::TransportError
:
1197 cerr
<< " - Transport error";
1200 cerr
<< " - Error code " << h323EP
->GetGatekeeper()->GetRegistrationFailReason();
1203 cerr
<< '.' << endl
;
1204 if (args
.HasOption("require-gatekeeper"))
1213 OpalConnection::AnswerCallResponse
1214 MyManager::OnAnswerCall(OpalConnection
& connection
,
1215 const PString
& caller
)
1217 cout
<< "incoming call from " << caller
<< endl
;
1218 cout
<< "Answer call (Y/N) " << endl
;
1219 currentCallToken
= connection
.GetCall().GetToken();
1220 return OpalConnection::AnswerCallPending
;
1223 void MyManager::AnswerCall(OpalConnection::AnswerCallResponse response
)
1226 PSafePtr
<OpalCall
> call
= FindCallWithLock(currentCallToken
);
1228 cout
<< "Could not find call for " << currentCallToken
<< " to answer" << endl
;
1232 if (response
!= OpalConnection::AnswerCallNow
) {
1233 cout
<< "Clearing call " << *call
<< endl
;
1239 if (pcssEP
!= NULL
&& !pcssEP
->incomingConnectionToken
)
1240 pcssEP
->AcceptIncomingConnection(pcssEP
->incomingConnectionToken
);
1244 void MyManager::NewSpeedDial(const PString
& ostr
)
1247 PINDEX idx
= str
.Find(' ');
1248 if (str
.IsEmpty() || (idx
== P_MAX_INDEX
)) {
1249 cout
<< "Must specify speedial number and string" << endl
;
1253 PString key
= str
.Left(idx
).Trim();
1254 PString data
= str
.Mid(idx
).Trim();
1256 PConfig
config("Speeddial");
1257 config
.SetString(key
, data
);
1259 cout
<< "Speedial " << key
<< " set to " << data
<< endl
;
1263 void MyManager::Main(PArgList
& args
)
1265 OpalConnection::StringOptions stringOptions
;
1267 // See if making a call or just listening.
1268 switch (args
.GetCount()) {
1270 cout
<< "Waiting for incoming calls\n";
1274 if (pauseBeforeDialing
) {
1275 cout
<< "Pausing to allow registration to occur..." << flush
;
1276 PThread::Sleep(2000);
1277 cout
<< "done" << endl
;
1280 cout
<< "Initiating call to \"" << args
[0] << "\"\n";
1281 SetUpCall(srcEP
, args
[0], currentCallToken
, 0, 0, &stringOptions
);
1285 if (pauseBeforeDialing
) {
1286 cout
<< "Pausing to allow registration to occur..." << flush
;
1287 PThread::Sleep(2000);
1288 cout
<< "done" << endl
;
1290 cout
<< "Initiating call from \"" << args
[0] << "\"to \"" << args
[1] << "\"\n";
1291 SetUpCall(args
[0], args
[1], currentCallToken
);
1295 if (args
.HasOption("disableui")) {
1296 while (FindCallWithLock(currentCallToken
) != NULL
)
1297 PThread::Sleep(1000);
1300 cout
<< "Press ? for help." << endl
;
1305 " 0-9 : send user indication message\n"
1306 " *,# : send user indication message\n"
1307 " M : send text message to remote user\n"
1308 " C : connect to remote host\n"
1309 " S : Display statistics\n"
1310 " H : Hang up phone\n"
1311 " L : List speed dials\n"
1312 " D : Create new speed dial\n"
1313 " {} : Increase/reduce record volume\n"
1314 " [] : Increase/reduce playback volume\n"
1315 " V : Display current volumes\n";
1317 PConsoleChannel
console(PConsoleChannel::StandardInput
);
1319 // display the prompt
1320 cout
<< "Command ? " << flush
;
1323 // terminate the menu loop if console finished
1324 char ch
= (char)console
.peek();
1325 if (console
.eof()) {
1326 cout
<< "\nConsole gone - menu disabled" << endl
;
1331 PTRACE(3, "console in audio test is " << ch
);
1332 switch (tolower(ch
)) {
1342 AnswerCall(OpalConnection::AnswerCallNow
);
1343 console
.ignore(INT_MAX
, '\n');
1347 AnswerCall(OpalConnection::AnswerCallDenied
);
1348 console
.ignore(INT_MAX
, '\n');
1359 NewSpeedDial(str
.Trim());
1364 HangupCurrentCall();
1368 if (!currentCallToken
.IsEmpty())
1369 cout
<< "Cannot make call whilst call in progress\n";
1373 StartCall(str
.Trim());
1378 cout
<< " current call token is \"" << currentCallToken
<< "\" " << endl
;
1382 if (currentCallToken
.IsEmpty())
1383 cout
<< "Cannot send a message while no call in progress\n";
1387 SendMessageToRemoteNode(str
);
1392 if (ch
>= '0' || ch
<= '9' || ch
== '*' || ch
== '#') {
1393 if (currentCallToken
.IsEmpty())
1394 cout
<< "Cannot send a digit while no call in progress\n";
1402 if (!currentCallToken
.IsEmpty())
1403 HangupCurrentCall();
1406 cout
<< "Console finished " << endl
;
1409 void MyManager::HangupCurrentCall()
1411 PSafePtr
<OpalCall
> call
= FindCallWithLock(currentCallToken
);
1413 cout
<< "Clearing call " << *call
<< endl
;
1415 currentCallToken
= PString();
1418 cout
<< "Not in a call!\n";
1421 void MyManager::SendMessageToRemoteNode(const PString
& ostr
)
1423 PString str
= ostr
.Trim();
1424 if (str
.IsEmpty()) {
1425 cout
<< "Must supply a message to send!\n";
1429 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1430 PStringList res
= endpoints
[i
].GetAllConnections();
1431 if (res
.GetSize() == 0)
1434 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1435 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1437 conn
->SendUserInputString(str
);
1438 cout
<< "Send \"" << str
<< "\" to " << res
[j
] << endl
;
1445 void MyManager::SendTone(const char tone
)
1447 for (PINDEX i
= 0; i
< endpoints
.GetSize(); i
++) {
1448 PStringList res
= endpoints
[i
].GetAllConnections();
1449 if (res
.GetSize() == 0)
1452 for(PINDEX j
= 0; j
< res
.GetSize(); j
++) {
1453 PSafePtr
< OpalConnection
> conn
= endpoints
[i
].GetConnectionWithLock (res
[j
]);
1455 conn
->SendUserInputTone(tone
, 0);
1456 cout
<< "Send \"" << tone
<< "\" to " << res
[j
] << endl
;
1463 void MyManager::StartCall(const PString
& ostr
)
1465 PString str
= ostr
.Trim();
1466 if (str
.IsEmpty()) {
1467 cout
<< "Must supply hostname to connect to!\n";
1471 // check for speed dials, and match wild cards as we go
1472 PString key
, prefix
;
1473 if ((str
.GetLength() > 1) && (str
[str
.GetLength()-1] == '#')) {
1475 key
= str
.Left(str
.GetLength()-1).Trim();
1477 PConfig
config("Speeddial");
1479 for (p
= key
.GetLength(); p
> 0; p
--) {
1481 PString newKey
= key
.Left(p
);
1485 // look for wild cards
1486 str
= config
.GetString(newKey
+ '*').Trim();
1490 // look for digit matches
1491 for (q
= p
; q
< key
.GetLength(); q
++)
1493 str
= config
.GetString(newKey
).Trim();
1497 if (str
.IsEmpty()) {
1498 cout
<< "Speed dial \"" << key
<< "\" not defined";
1504 SetUpCall(srcEP
, str
, currentCallToken
);
1509 void MyManager::ListSpeedDials()
1511 PConfig
config("Speeddial");
1512 PStringList keys
= config
.GetKeys();
1513 if (keys
.GetSize() == 0) {
1514 cout
<< "No speed dials defined" << endl
;
1519 for (i
= 0; i
< keys
.GetSize(); i
++)
1520 cout
<< keys
[i
] << ": " << config
.GetString(keys
[i
]) << endl
;
1523 void MyManager::OnEstablishedCall(OpalCall
& call
)
1525 currentCallToken
= call
.GetToken();
1526 cout
<< "In call with " << call
.GetPartyB() << " using " << call
.GetPartyA() << endl
;
1529 void MyManager::OnClearedCall(OpalCall
& call
)
1531 if (currentCallToken
== call
.GetToken())
1532 currentCallToken
= PString();
1534 PString remoteName
= '"' + call
.GetPartyB() + '"';
1535 switch (call
.GetCallEndReason()) {
1536 case OpalConnection::EndedByRemoteUser
:
1537 cout
<< remoteName
<< " has cleared the call";
1539 case OpalConnection::EndedByCallerAbort
:
1540 cout
<< remoteName
<< " has stopped calling";
1542 case OpalConnection::EndedByRefusal
:
1543 cout
<< remoteName
<< " did not accept your call";
1545 case OpalConnection::EndedByNoAnswer
:
1546 cout
<< remoteName
<< " did not answer your call";
1548 case OpalConnection::EndedByTransportFail
:
1549 cout
<< "Call with " << remoteName
<< " ended abnormally";
1551 case OpalConnection::EndedByCapabilityExchange
:
1552 cout
<< "Could not find common codec with " << remoteName
;
1554 case OpalConnection::EndedByNoAccept
:
1555 cout
<< "Did not accept incoming call from " << remoteName
;
1557 case OpalConnection::EndedByAnswerDenied
:
1558 cout
<< "Refused incoming call from " << remoteName
;
1560 case OpalConnection::EndedByNoUser
:
1561 cout
<< "Gatekeeper or registrar could not find user " << remoteName
;
1563 case OpalConnection::EndedByNoBandwidth
:
1564 cout
<< "Call to " << remoteName
<< " aborted, insufficient bandwidth.";
1566 case OpalConnection::EndedByUnreachable
:
1567 cout
<< remoteName
<< " could not be reached.";
1569 case OpalConnection::EndedByNoEndPoint
:
1570 cout
<< "No phone running for " << remoteName
;
1572 case OpalConnection::EndedByHostOffline
:
1573 cout
<< remoteName
<< " is not online.";
1575 case OpalConnection::EndedByConnectFail
:
1576 cout
<< "Transport error calling " << remoteName
;
1579 cout
<< "Call with " << remoteName
<< " completed";
1582 cout
<< ", on " << now
.AsString("w h:mma") << ". Duration "
1583 << setprecision(0) << setw(5) << (now
- call
.GetStartTime())
1586 OpalManager::OnClearedCall(call
);
1590 BOOL
MyManager::OnOpenMediaStream(OpalConnection
& connection
,
1591 OpalMediaStream
& stream
)
1593 if (!OpalManager::OnOpenMediaStream(connection
, stream
))
1598 PCaselessString prefix
= connection
.GetEndPoint().GetPrefixName();
1599 if (prefix
== "pc" || prefix
== "pots")
1600 cout
<< (stream
.IsSink() ? "playing " : "grabbing ") << stream
.GetMediaFormat();
1601 else if (prefix
== "ivr")
1602 cout
<< (stream
.IsSink() ? "streaming " : "recording ") << stream
.GetMediaFormat();
1604 cout
<< (stream
.IsSink() ? "sending " : "receiving ") << stream
.GetMediaFormat()
1605 << (stream
.IsSink() ? " to " : " from ")<< prefix
;
1614 void MyManager::OnUserInputString(OpalConnection
& connection
, const PString
& value
)
1616 cout
<< "User input received: \"" << value
<< '"' << endl
;
1617 OpalManager::OnUserInputString(connection
, value
);
1621 ///////////////////////////////////////////////////////////////
1623 MyPCSSEndPoint::MyPCSSEndPoint(MyManager
& mgr
)
1624 : OpalPCSSEndPoint(mgr
)
1629 PString
MyPCSSEndPoint::OnGetDestination(const OpalPCSSConnection
& /*connection*/)
1631 PString destination
;
1633 if (destinationAddress
.IsEmpty()) {
1634 cout
<< "Enter destination address? " << flush
;
1638 destination
= destinationAddress
;
1639 destinationAddress
= PString();
1646 void MyPCSSEndPoint::OnShowIncoming(const OpalPCSSConnection
& connection
)
1648 incomingConnectionToken
= connection
.GetToken();
1651 AcceptIncomingConnection(incomingConnectionToken
);
1654 cout
<< "\nCall on " << now
.AsString("w h:mma")
1655 << " from " << connection
.GetRemotePartyName()
1656 << ", answer (Y/N)? " << flush
;
1661 BOOL
MyPCSSEndPoint::OnShowOutgoing(const OpalPCSSConnection
& connection
)
1664 cout
<< connection
.GetRemotePartyName() << " is ringing on "
1665 << now
.AsString("w h:mma") << " ..." << endl
;
1670 BOOL
MyPCSSEndPoint::SetSoundDevice(PArgList
& args
,
1671 const char * optionName
,
1672 PSoundChannel::Directions dir
)
1674 if (!args
.HasOption(optionName
))
1677 PString dev
= args
.GetOptionString(optionName
);
1679 if (dir
== PSoundChannel::Player
) {
1680 if (SetSoundChannelPlayDevice(dev
))
1684 if (SetSoundChannelRecordDevice(dev
))
1688 cerr
<< "Device for " << optionName
<< " (\"" << dev
<< "\") must be one of:\n";
1690 PStringArray names
= PSoundChannel::GetDeviceNames(dir
);
1691 for (PINDEX i
= 0; i
< names
.GetSize(); i
++)
1692 cerr
<< " \"" << names
[i
] << "\"\n";
1698 // End of File ///////////////////////////////////////////////////////////////