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