Pause before dialing when using two endpoint mode
[opal/cbnco.git] / samples / simple / main.cxx
blobd2fee9f38e186955d370304a92b54d435416926d
1 /*
2 * main.cxx
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
16 * under the License.
18 * The Original Code is Portable Windows Library.
20 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
22 * Contributor(s): ______________________________________.
24 * $Log$
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
58 * Added LID plug ins
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
75 * Thanks to Mike T
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
111 * registrar used
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"
122 * help immensely.
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
146 * Fix formatting.
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
213 * Added call command
215 * Revision 2.27 2004/01/18 15:36:07 rjongbloed
216 * Added stun support
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.
349 #include <ptlib.h>
351 #include <opal/buildopts.h>
353 #if OPAL_IAX2
354 #include <iax2/iax2.h>
355 #endif
357 #if OPAL_SIP
358 #include <sip/sip.h>
359 #endif
361 #if OPAL_H323
362 #include <h323/h323.h>
363 #include <h323/gkclient.h>
364 #endif
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>
373 #include "main.h"
374 #include "../../version.h"
377 #define new PNEW
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()
393 cout << GetName()
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();
401 args.Parse(
402 "a-auto-answer."
403 "b-bandwidth:"
404 "D-disable:"
405 "d-dial-peer:"
406 "-disableui."
407 "e-silence."
408 "f-fast-disable."
409 "g-gatekeeper:"
410 "G-gk-id:"
411 "-gk-token:"
412 "-disable-grq."
413 "h-help."
414 "H-no-h323."
415 #if P_SSL
416 "-no-h323s."
417 "-h323s-listen:"
418 #endif
419 "-h323-listen:"
420 "I-no-sip."
421 "j-jitter:"
422 "l-listen."
423 #if OPAL_LID
424 "L-no-lid."
425 "-lid:"
426 "-country:"
427 #endif
428 "n-no-gatekeeper."
429 "-no-std-dial-peer."
430 #if PTRACING
431 "o-output:"
432 #endif
433 "P-prefer:"
434 "p-password:"
435 "-portbase:"
436 "-portmax:"
437 "R-require-gatekeeper."
438 "r-register-sip:"
439 "-rtp-base:"
440 "-rtp-max:"
441 "-rtp-tos:"
442 "s-sound:"
443 "S-no-sound."
444 "-sound-in:"
445 "-sound-out:"
446 "-srcep:"
447 "-sip-listen:"
448 "-sip-proxy:"
449 "-sip-domain:"
450 "-sip-user-agent:"
451 "-sip-ui:"
452 "-stun:"
453 "T-h245tunneldisable."
454 "-translate:"
455 "-tts:"
457 #if PTRACING
458 "t-trace."
459 #endif
460 "-tcp-base:"
461 "-tcp-max:"
462 "u-user:"
463 "-udp-base:"
464 "-udp-max:"
465 "-use-long-mime."
466 "-rx-video." "-no-rx-video."
467 "-tx-video." "-no-tx-video."
468 "-grabber:"
469 "-grabdevice:"
470 "-grabchannel:"
471 "-display:"
472 "-displaydevice:"
473 #if P_EXPAT
474 "V-no-ivr."
475 "x-vxml:"
476 #endif
477 #if OPAL_IAX2
478 "X-no-iax2."
479 #endif
480 , FALSE);
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"
487 "General options:\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"
498 "\n"
499 "Audio options:\n"
500 " -j --jitter [min-]max : Set minimum (optional) and maximum jitter buffer (in milliseconds).\n"
501 " -e --silence : Disable transmitter silence detection.\n"
502 "\n"
503 "Video options:\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"
513 "\n"
515 #if OPAL_SIP
516 "SIP options:\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"
527 "\n"
528 #endif
530 #if OPAL_H323
531 "H.323 options:\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"
542 #if P_SSL
543 " --h323s-listen iface : Interface/port(s) to listen for secure H.323 requests\n"
544 #endif
545 " : '*' is all interfaces, (default tcp$:*:1720)\n"
546 " --disable-grq : Do not send GRQ when registering with GK\n"
547 #if P_SSL
548 " --no-h323s : Do not creat secure H.323 endpoint\n"
549 #endif
550 #endif
552 "\n"
553 #if OPAL_LID
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"
558 "\n"
559 #endif
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"
565 "\n"
566 #if P_EXPAT
567 "IVR options:\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"
571 "\n"
572 #endif
573 "IP options:\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"
585 "\n"
586 "Debug options:\n"
587 #if PTRACING
588 " -t --trace : Enable trace, use multiple times for more detail.\n"
589 " -o --output : File for trace output, default is stderr.\n"
590 #endif
591 #if OPAL_IAX2
592 " -X --no-iax2 : Remove support for iax2\n"
593 #endif
594 " -h --help : This help message.\n"
595 "\n"
596 "\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"
605 "\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"
609 "\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"
612 "\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"
616 "\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"
622 "\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"
627 "\n"
628 " If POTS is enabled:\n"
629 " h323:.* = pots:<da>\n"
630 " sip:.* = pots:<da>\n"
631 " iax2:.* = pots:<da>\n"
632 "\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"
637 "\n"
638 #if P_EXPAT
639 " If IVR is enabled then a # from any protocol will route it it, ie:\n"
640 " .*:# = ivr:\n"
641 "\n"
642 #endif
643 #if OPAL_IAX2
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"
646 #endif
647 << endl;
648 return;
651 #if PTRACING
652 PTrace::Initialise(args.GetOptionCount('t'),
653 args.HasOption('o') ? (const char *)args.GetOptionString('o') : NULL,
654 PTrace::Timestamp|PTrace::Thread|PTrace::FileAndLine);
655 #endif
657 // Create the Opal Manager and initialise it
658 opal = new MyManager;
660 if (opal->Initialise(args))
661 opal->Main(args);
663 cout << "Exiting " << GetName() << endl;
665 delete opal;
669 ///////////////////////////////////////////////////////////////
671 MyManager::MyManager()
673 #if OPAL_LID
674 potsEP = NULL;
675 #endif
676 pcssEP = NULL;
678 #if OPAL_H323
679 h323EP = NULL;
680 #if P_SSL
681 h323sEP = NULL;
682 #endif
683 #endif
684 #if OPAL_SIP
685 sipEP = NULL;
686 #endif
687 #if OPAL_IAX2
688 iax2EP = NULL;
689 #endif
690 #if P_EXPAT
691 ivrEP = NULL;
692 #endif
693 #if OPAL_T38FAX
694 faxEP = NULL;
695 t38EP = NULL;
696 #endif
698 pauseBeforeDialing = FALSE;
702 MyManager::~MyManager()
704 #if OPAL_LID
705 // Must do this before we destroy the manager or a crash will result
706 if (potsEP != NULL)
707 potsEP->RemoveAllLines();
708 #endif
712 BOOL MyManager::Initialise(PArgList & args)
715 OpalMediaFormat fmt(OpalT38);
716 if (!fmt.IsValid()) {
717 cerr << "cannot find t.38" << endl;
718 return false;
720 else
722 OpalMediaFormat::SetRegisteredMediaFormat(fmt);
725 #if OPAL_VIDEO
726 OpalMediaFormat fmt("H.261-CIF");
727 if (fmt.IsValid()) {
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;
751 return FALSE;
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;
762 return FALSE;
765 #endif
767 if (args.HasOption('j')) {
768 unsigned minJitter;
769 unsigned maxJitter;
770 PStringArray delays = args.GetOptionString('j').Tokenise(",-");
771 if (delays.GetSize() < 2) {
772 maxJitter = delays[0].AsUnsigned();
773 minJitter = PMIN(GetMinAudioJitterDelay(), maxJitter);
775 else {
776 minJitter = delays[0].AsUnsigned();
777 maxJitter = delays[1].AsUnsigned();
779 if (minJitter >= 20 && minJitter <= maxJitter && maxJitter <= 1000)
780 SetAudioJitterDelay(minJitter, maxJitter);
781 else {
782 cerr << "Jitter should be between 20 and 1000 milliseconds." << endl;
783 return FALSE;
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);
810 } else {
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();
826 if (tos > 255) {
827 cerr << "IP Type Of Service bits must be 0 to 255." << endl;
828 return FALSE;
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"));
842 if (stun != NULL)
843 cout << stun->GetServer() << " replies " << stun->GetNatTypeName();
844 else
845 cout << "None";
846 cout << '\n';
849 ///////////////////////////////////////
850 // Open the LID if parameter provided, create LID based endpoint
851 #if OPAL_LID
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
867 if (potsEP == NULL)
868 potsEP = new OpalPOTSEndPoint(*this);
869 if (potsEP->AddDevice(lid))
870 cout << "Line interface device \"" << devices[d] << "\" added." << endl;
872 else {
873 cerr << "Could not open device \"" << devices[d] << '"' << endl;
874 delete lid;
878 #endif
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))
890 return FALSE;
891 if (!pcssEP->SetSoundDevice(args, "sound", PSoundChannel::Player))
892 return FALSE;
893 if (!pcssEP->SetSoundDevice(args, "sound-in", PSoundChannel::Recorder))
894 return FALSE;
895 if (!pcssEP->SetSoundDevice(args, "sound-out", PSoundChannel::Player))
896 return FALSE;
898 cout << "Sound output device: \"" << pcssEP->GetSoundChannelPlayDevice() << "\"\n"
899 "Sound input device: \"" << pcssEP->GetSoundChannelRecordDevice() << "\"\n"
900 #if OPAL_VIDEO
901 "Video output device: \"" << GetVideoOutputDevice().deviceName << "\"\n"
902 "Video input device: \"" << GetVideoInputDevice().deviceName << "\"\n"
903 #endif
904 "Available codecs: " << setfill(',') << OpalTranscoder::GetPossibleFormats(pcssEP->GetMediaFormats()) << setfill(' ') << endl;
907 #if OPAL_H323
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))
914 return FALSE;
915 #if P_SSL
916 if (!args.HasOption("no-h323s")) {
917 h323sEP = new H323SecureEndPoint(*this);
918 if (!InitialiseH323EP(args, "h323s-listen", h323sEP))
919 return FALSE;
921 #endif
924 #endif
926 #if OPAL_IAX2
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]);
941 #endif
943 #if OPAL_SIP
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"));
965 // set MIME format
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;
981 return FALSE;
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")))
988 cout << "done.";
989 else
990 cout << "failed!";
991 cout << endl;
992 pauseBeforeDialing = TRUE;
996 #endif
999 #if P_EXPAT
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);
1014 #endif
1016 #if OPAL_T38FAX
1017 ///////////////////////////////////////
1018 // Create T38 protocol handler
1020 faxEP = new OpalFaxEndPoint(*this);
1021 t38EP = new OpalT38EndPoint(*this);
1023 #endif
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;
1031 return FALSE;
1035 if (!args.HasOption("no-std-dial-peer")) {
1036 #if P_EXPAT
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
1039 if (ivrEP != NULL)
1040 AddRouteEntry(".*:# = ivr:"); // A hash from anywhere goes to IVR
1041 #endif
1043 #if OPAL_SIP
1044 if (sipEP != NULL) {
1045 AddRouteEntry("pots:.*\\*.*\\*.* = sip:<dn2ip>");
1046 AddRouteEntry("pots:.* = sip:<da>");
1047 AddRouteEntry("pc:.* = sip:<da>");
1049 #endif
1051 #if OPAL_H323
1052 if (h323EP != NULL) {
1053 AddRouteEntry("pots:.*\\*.*\\*.* = h323:<dn2ip>");
1054 AddRouteEntry("pots:.* = h323:<da>");
1055 AddRouteEntry("pc:.* = h323:<da>");
1056 #if P_SSL
1057 if (h323sEP != NULL) {
1058 AddRouteEntry("pots:.*\\*.*\\*.* = h323s:<dn2ip>");
1059 AddRouteEntry("pots:.* = h323s:<da>");
1060 AddRouteEntry("pc:.* = h323s:<da>");
1062 #endif
1064 #endif
1066 #if OPAL_LID
1067 if (potsEP != NULL) {
1068 #if OPAL_H323
1069 AddRouteEntry("h323:.* = pots:<da>");
1070 #if P_SSL
1071 if (h323sEP != NULL)
1072 AddRouteEntry("h323s:.* = pots:<da>");
1073 #endif
1074 #endif
1075 #if OPAL_SIP
1076 AddRouteEntry("sip:.* = pots:<da>");
1077 #endif
1079 else
1080 #endif // OPAL_LID
1081 if (pcssEP != NULL) {
1082 #if OPAL_H323
1083 AddRouteEntry("h323:.* = pc:<da>");
1084 #if P_SSL
1085 if (h323sEP != NULL)
1086 AddRouteEntry("h323s:.* = pc:<da>");
1087 #endif
1088 #endif
1089 #if OPAL_SIP
1090 AddRouteEntry("sip:.* = pc:<da>");
1091 #endif
1095 #if OPAL_IAX2
1096 if (pcssEP != NULL) {
1097 AddRouteEntry("iax2:.* = pc:<da>");
1098 AddRouteEntry("pc:.* = iax2:<da>");
1100 #endif
1102 srcEP = args.GetOptionString("srcep", pcssEP != NULL ? "pc:*"
1103 #if OPAL_LID
1104 : potsEP != NULL ? "pots:*"
1105 #endif
1106 #if P_EXPAT
1107 : ivrEP != NULL ? "ivr:#"
1108 #endif
1109 #if OPAL_SIP
1110 : sipEP != NULL ? "sip:localhost"
1111 #endif
1112 #if OPAL_H323
1113 : h323EP != NULL ? "sip:localhost"
1114 #endif
1115 : "");
1116 return TRUE;
1119 #if OPAL_H323
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;
1140 return FALSE;
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;
1160 return FALSE;
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;
1176 else {
1177 cout << "none." << endl;
1178 cerr << "Could not register with gatekeeper";
1179 if (!gkIdentifer)
1180 cerr << " id \"" << gkIdentifer << '"';
1181 if (!gkHost)
1182 cerr << " at \"" << gkHost << '"';
1183 if (!gkInterface)
1184 cerr << " on interface \"" << gkInterface << '"';
1185 if (h323EP->GetGatekeeper() != NULL) {
1186 switch (h323EP->GetGatekeeper()->GetRegistrationFailReason()) {
1187 case H323Gatekeeper::InvalidListener :
1188 cerr << " - Invalid listener";
1189 break;
1190 case H323Gatekeeper::DuplicateAlias :
1191 cerr << " - Duplicate alias";
1192 break;
1193 case H323Gatekeeper::SecurityDenied :
1194 cerr << " - Security denied";
1195 break;
1196 case H323Gatekeeper::TransportError :
1197 cerr << " - Transport error";
1198 break;
1199 default :
1200 cerr << " - Error code " << h323EP->GetGatekeeper()->GetRegistrationFailReason();
1203 cerr << '.' << endl;
1204 if (args.HasOption("require-gatekeeper"))
1205 return FALSE;
1208 return TRUE;
1211 #endif //OPAL_H323
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);
1227 if (call == NULL) {
1228 cout << "Could not find call for " << currentCallToken << " to answer" << endl;
1229 return;
1232 if (response != OpalConnection::AnswerCallNow) {
1233 cout << "Clearing call " << *call << endl;
1234 call->Clear();
1235 return;
1239 if (pcssEP != NULL && !pcssEP->incomingConnectionToken)
1240 pcssEP->AcceptIncomingConnection(pcssEP->incomingConnectionToken);
1244 void MyManager::NewSpeedDial(const PString & ostr)
1246 PString str = ostr;
1247 PINDEX idx = str.Find(' ');
1248 if (str.IsEmpty() || (idx == P_MAX_INDEX)) {
1249 cout << "Must specify speedial number and string" << endl;
1250 return;
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()) {
1269 case 0 :
1270 cout << "Waiting for incoming calls\n";
1271 break;
1273 case 1 :
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);
1282 break;
1284 default :
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);
1292 break;
1295 if (args.HasOption("disableui")) {
1296 while (FindCallWithLock(currentCallToken) != NULL)
1297 PThread::Sleep(1000);
1299 else {
1300 cout << "Press ? for help." << endl;
1302 PStringStream help;
1304 help << "Select:\n"
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);
1318 for (;;) {
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;
1327 goto endSimpleOPAL;
1330 console >> ch;
1331 PTRACE(3, "console in audio test is " << ch);
1332 switch (tolower(ch)) {
1333 case 'x' :
1334 case 'q' :
1335 goto endSimpleOPAL;
1336 break;
1337 case '?' :
1338 cout << help ;
1339 break;
1341 case 'y' :
1342 AnswerCall(OpalConnection::AnswerCallNow);
1343 console.ignore(INT_MAX, '\n');
1344 break;
1346 case 'n' :
1347 AnswerCall(OpalConnection::AnswerCallDenied);
1348 console.ignore(INT_MAX, '\n');
1349 break;
1351 case 'l' :
1352 ListSpeedDials();
1353 break;
1355 case 'd' :
1357 PString str;
1358 console >> str;
1359 NewSpeedDial(str.Trim());
1361 break;
1363 case 'h' :
1364 HangupCurrentCall();
1365 break;
1367 case 'c' :
1368 if (!currentCallToken.IsEmpty())
1369 cout << "Cannot make call whilst call in progress\n";
1370 else {
1371 PString str;
1372 console >> str;
1373 StartCall(str.Trim());
1375 break;
1377 case 'r':
1378 cout << " current call token is \"" << currentCallToken << "\" " << endl;
1379 break;
1381 case 'm' :
1382 if (currentCallToken.IsEmpty())
1383 cout << "Cannot send a message while no call in progress\n";
1384 else {
1385 PString str;
1386 console >> str;
1387 SendMessageToRemoteNode(str);
1389 break;
1391 default:
1392 if (ch >= '0' || ch <= '9' || ch == '*' || ch == '#') {
1393 if (currentCallToken.IsEmpty())
1394 cout << "Cannot send a digit while no call in progress\n";
1395 else
1396 SendTone(ch);
1398 break;
1401 endSimpleOPAL:
1402 if (!currentCallToken.IsEmpty())
1403 HangupCurrentCall();
1406 cout << "Console finished " << endl;
1409 void MyManager::HangupCurrentCall()
1411 PSafePtr<OpalCall> call = FindCallWithLock(currentCallToken);
1412 if (call != NULL) {
1413 cout << "Clearing call " << *call << endl;
1414 call->Clear();
1415 currentCallToken = PString();
1417 else
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";
1426 return ;
1429 for (PINDEX i = 0; i < endpoints.GetSize(); i++) {
1430 PStringList res = endpoints[i].GetAllConnections();
1431 if (res.GetSize() == 0)
1432 continue;
1434 for(PINDEX j = 0; j < res.GetSize(); j++) {
1435 PSafePtr< OpalConnection > conn = endpoints[i].GetConnectionWithLock (res[j]);
1436 if (conn != NULL) {
1437 conn->SendUserInputString(str);
1438 cout << "Send \"" << str << "\" to " << res[j] << endl;
1442 return;
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)
1450 continue;
1452 for(PINDEX j = 0; j < res.GetSize(); j++) {
1453 PSafePtr< OpalConnection > conn = endpoints[i].GetConnectionWithLock (res[j]);
1454 if (conn != NULL) {
1455 conn->SendUserInputTone(tone, 0);
1456 cout << "Send \"" << tone << "\" to " << res[j] << endl;
1460 return;
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";
1468 return ;
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();
1476 str = PString();
1477 PConfig config("Speeddial");
1478 PINDEX p;
1479 for (p = key.GetLength(); p > 0; p--) {
1481 PString newKey = key.Left(p);
1482 prefix = newKey;
1483 PINDEX q;
1485 // look for wild cards
1486 str = config.GetString(newKey + '*').Trim();
1487 if (!str.IsEmpty())
1488 break;
1490 // look for digit matches
1491 for (q = p; q < key.GetLength(); q++)
1492 newKey += '?';
1493 str = config.GetString(newKey).Trim();
1494 if (!str.IsEmpty())
1495 break;
1497 if (str.IsEmpty()) {
1498 cout << "Speed dial \"" << key << "\" not defined";
1499 cout << endl;
1503 if (!str.IsEmpty())
1504 SetUpCall(srcEP, str, currentCallToken);
1506 return;
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;
1515 return;
1518 PINDEX i;
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";
1538 break;
1539 case OpalConnection::EndedByCallerAbort :
1540 cout << remoteName << " has stopped calling";
1541 break;
1542 case OpalConnection::EndedByRefusal :
1543 cout << remoteName << " did not accept your call";
1544 break;
1545 case OpalConnection::EndedByNoAnswer :
1546 cout << remoteName << " did not answer your call";
1547 break;
1548 case OpalConnection::EndedByTransportFail :
1549 cout << "Call with " << remoteName << " ended abnormally";
1550 break;
1551 case OpalConnection::EndedByCapabilityExchange :
1552 cout << "Could not find common codec with " << remoteName;
1553 break;
1554 case OpalConnection::EndedByNoAccept :
1555 cout << "Did not accept incoming call from " << remoteName;
1556 break;
1557 case OpalConnection::EndedByAnswerDenied :
1558 cout << "Refused incoming call from " << remoteName;
1559 break;
1560 case OpalConnection::EndedByNoUser :
1561 cout << "Gatekeeper or registrar could not find user " << remoteName;
1562 break;
1563 case OpalConnection::EndedByNoBandwidth :
1564 cout << "Call to " << remoteName << " aborted, insufficient bandwidth.";
1565 break;
1566 case OpalConnection::EndedByUnreachable :
1567 cout << remoteName << " could not be reached.";
1568 break;
1569 case OpalConnection::EndedByNoEndPoint :
1570 cout << "No phone running for " << remoteName;
1571 break;
1572 case OpalConnection::EndedByHostOffline :
1573 cout << remoteName << " is not online.";
1574 break;
1575 case OpalConnection::EndedByConnectFail :
1576 cout << "Transport error calling " << remoteName;
1577 break;
1578 default :
1579 cout << "Call with " << remoteName << " completed";
1581 PTime now;
1582 cout << ", on " << now.AsString("w h:mma") << ". Duration "
1583 << setprecision(0) << setw(5) << (now - call.GetStartTime())
1584 << "s." << endl;
1586 OpalManager::OnClearedCall(call);
1590 BOOL MyManager::OnOpenMediaStream(OpalConnection & connection,
1591 OpalMediaStream & stream)
1593 if (!OpalManager::OnOpenMediaStream(connection, stream))
1594 return FALSE;
1596 cout << "Started ";
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();
1603 else
1604 cout << (stream.IsSink() ? "sending " : "receiving ") << stream.GetMediaFormat()
1605 << (stream.IsSink() ? " to " : " from ")<< prefix;
1607 cout << endl;
1609 return TRUE;
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;
1635 cin >> destination;
1637 else {
1638 destination = destinationAddress;
1639 destinationAddress = PString();
1642 return destination;
1646 void MyPCSSEndPoint::OnShowIncoming(const OpalPCSSConnection & connection)
1648 incomingConnectionToken = connection.GetToken();
1650 if (autoAnswer)
1651 AcceptIncomingConnection(incomingConnectionToken);
1652 else {
1653 PTime now;
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)
1663 PTime now;
1664 cout << connection.GetRemotePartyName() << " is ringing on "
1665 << now.AsString("w h:mma") << " ..." << endl;
1666 return TRUE;
1670 BOOL MyPCSSEndPoint::SetSoundDevice(PArgList & args,
1671 const char * optionName,
1672 PSoundChannel::Directions dir)
1674 if (!args.HasOption(optionName))
1675 return TRUE;
1677 PString dev = args.GetOptionString(optionName);
1679 if (dir == PSoundChannel::Player) {
1680 if (SetSoundChannelPlayDevice(dev))
1681 return TRUE;
1683 else {
1684 if (SetSoundChannelRecordDevice(dev))
1685 return TRUE;
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";
1694 return FALSE;
1698 // End of File ///////////////////////////////////////////////////////////////