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