Tidied some trace logs to assure all have a category (bit before a tab character...
[opal/cbnco.git] / src / opal / connection.cxx
blob71e0ba364b90e16a8ec6c2263bffd775d94ba417
1 /*
2 * connection.cxx
4 * Connection abstraction
6 * Open Phone Abstraction Library (OPAL)
7 * Formally known as the Open H323 project.
9 * Copyright (c) 2001 Equivalence Pty. Ltd.
11 * The contents of this file are subject to the Mozilla Public License
12 * Version 1.0 (the "License"); you may not use this file except in
13 * compliance with the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
16 * Software distributed under the License is distributed on an "AS IS"
17 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18 * the License for the specific language governing rights and limitations
19 * under the License.
21 * The Original Code is Open Phone Abstraction Library.
23 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
25 * Contributor(s): ______________________________________.
27 * $Log$
28 * Revision 2.101 2007/04/02 05:51:33 rjongbloed
29 * Tidied some trace logs to assure all have a category (bit before a tab character) set.
31 * Revision 2.100 2007/03/30 02:09:53 rjongbloed
32 * Fixed various GCC warnings
34 * Revision 2.99 2007/03/29 05:16:50 csoutheren
35 * Pass OpalConnection to OpalMediaSream constructor
36 * Add ID to OpalMediaStreams so that transcoders can match incoming and outgoing codecs
38 * Revision 2.98 2007/03/13 02:17:47 csoutheren
39 * Remove warnings/errors when compiling with various turned off
41 * Revision 2.97 2007/03/13 00:33:10 csoutheren
42 * Simple but messy changes to allow compile time removal of protocol
43 * options such as H.450 and H.460
44 * Fix MakeConnection overrides
46 * Revision 2.96 2007/03/01 05:51:04 rjongbloed
47 * Fixed backward compatibility of OnIncomingConnection() virtual
48 * functions on various classes. If an old override returned FALSE
49 * then it will now abort the call as it used to.
51 * Revision 2.95 2007/03/01 05:05:40 csoutheren
52 * Fixed problem with override of OnIncomingConnection
54 * Revision 2.94 2007/03/01 03:55:43 csoutheren
55 * Remove old code
57 * Revision 2.93 2007/03/01 03:53:19 csoutheren
58 * Use local jitter buffer values rather than getting direct from OpalManager
59 * Allow OpalConnection string options to be set during incoming calls
61 * Revision 2.92 2007/02/23 07:10:02 csoutheren
62 * Fixed problem with new reason code
64 * Revision 2.91 2007/02/23 01:01:47 csoutheren
65 * Added abilty to set Q.931 codes through normal OpalConnection::CallEndReason
67 * Revision 2.90 2007/02/19 04:43:42 csoutheren
68 * Added OnIncomingMediaChannels so incoming calls can optionally be handled in two stages
70 * Revision 2.89 2007/02/13 23:36:42 csoutheren
71 * Fix problem with using SIP connections that have no StringOptions
73 * Revision 2.88 2007/01/24 04:00:57 csoutheren
74 * Arrrghh. Changing OnIncomingConnection turned out to have a lot of side-effects
75 * Added some pure viritual functions to prevent old code from breaking silently
76 * New OpalEndpoint and OpalConnection descendants will need to re-implement
77 * OnIncomingConnection. Sorry :)
79 * Revision 2.87 2007/01/24 00:28:28 csoutheren
80 * Fixed overrides of OnIncomingConnection
82 * Revision 2.86 2007/01/18 12:25:33 csoutheren
83 * Add ability to set H.323 call-id via options
85 * Revision 2.85 2007/01/18 04:45:17 csoutheren
86 * Messy, but simple change to add additional options argument to OpalConnection constructor
87 * This allows the provision of non-trivial arguments for connections
89 * Revision 2.84 2006/12/18 03:18:42 csoutheren
90 * Messy but simple fixes
91 * - Add access to SIP REGISTER timeout
92 * - Ensure OpalConnection options are correctly progagated
94 * Revision 2.83 2006/12/08 04:22:06 csoutheren
95 * Applied 1589261 - new release cause for fxo endpoints
96 * Thanks to Frederic Heem
98 * Revision 2.82 2006/11/20 03:37:12 csoutheren
99 * Allow optional inclusion of RTP aggregation
101 * Revision 2.81 2006/11/19 06:02:58 rjongbloed
102 * Moved function that reads User Input into a destination address to
103 * OpalManager so can be easily overidden in applications.
105 * Revision 2.80 2006/11/11 12:23:18 hfriederich
106 * Code reorganisation to improve RFC2833 handling for both SIP and H.323. Thanks Simon Zwahlen for the idea
108 * Revision 2.79 2006/10/28 16:40:28 dsandras
109 * Fixed SIP reinvite without breaking H.323 calls.
111 * Revision 2.78 2006/10/25 13:02:54 rjongbloed
112 * Fixed compiler error due to tone subsystem upgrade
114 * Revision 2.77 2006/10/10 07:18:18 csoutheren
115 * Allow compilation with and without various options
117 * Revision 2.76 2006/09/28 07:42:18 csoutheren
118 * Merge of useful SRTP implementation
120 * Revision 2.75 2006/09/13 00:22:53 csoutheren
121 * Fix reentrancy problems in Release
123 * Revision 2.74 2006/08/29 08:47:43 rjongbloed
124 * Added functions to get average audio signal level from audio streams in
125 * suitable connection types.
127 * Revision 2.73 2006/08/28 00:07:43 csoutheren
128 * Applied 1545125 - SetPhase mutex protection and transition control
129 * Thanks to Drazen Dimoti
131 * Revision 2.72 2006/08/17 23:09:04 rjongbloed
132 * Added volume controls
134 * Revision 2.71 2006/08/10 05:10:33 csoutheren
135 * Various H.323 stability patches merged in from DeimosPrePLuginBranch
137 * Revision 2.70 2006/08/10 04:26:36 csoutheren
138 * Applied 1534434 - OpalConnection::SetAudioJitterDelay - checking of values
139 * Thanks to Drazen Dimoti
141 * Revision 2.69 2006/08/03 04:57:12 csoutheren
142 * Port additional NAT handling logic from OpenH323 and extend into OpalConnection class
144 * Revision 2.68 2006/07/24 14:03:40 csoutheren
145 * Merged in audio and video plugins from CVS branch PluginBranch
147 * Revision 2.67.2.3 2006/08/09 12:49:21 csoutheren
148 * Improve stablity under heavy H.323 load
150 * Revision 2.67.2.2 2006/08/03 08:09:20 csoutheren
151 * Removed old code
153 * Revision 2.67.2.1 2006/08/03 08:01:15 csoutheren
154 * Added additional locking for media stream list to remove crashes in very busy applications
156 * Revision 2.67 2006/07/21 00:42:08 csoutheren
157 * Applied 1525040 - More locking when changing connection's phase
158 * Thanks to Borko Jandras
160 * Revision 2.66 2006/07/05 05:09:12 csoutheren
161 * Applied 1494937 - Allow re-opening of mediastrams
162 * Thanks to mturconi
164 * Revision 2.65 2006/06/30 00:49:07 csoutheren
165 * Applied 1469865 - remove connection from call's connection list
166 * Thanks to Frederich Heem
168 * Revision 2.64 2006/06/27 13:07:37 csoutheren
169 * Patch 1374533 - add h323 Progress handling
170 * Thanks to Frederich Heem
172 * Revision 2.63 2006/06/09 04:22:24 csoutheren
173 * Implemented mapping between SIP release codes and Q.931 codes as specified
174 * by RFC 3398
176 * Revision 2.62 2006/05/30 04:58:06 csoutheren
177 * Added suport for SIP INFO message (untested as yet)
178 * Fixed some issues with SIP state machine on answering calls
179 * Fixed some formatting issues
181 * Revision 2.61 2006/05/23 17:26:52 dsandras
182 * Reverted previous patch preventing OnEstablished to be called with H.323 calls.
184 * Revision 2.60 2006/04/20 16:52:22 hfriederich
185 * Adding support for H.224/H.281
187 * Revision 2.59 2006/04/09 12:12:54 rjongbloed
188 * Changed the media format option merging to include the transcoder formats.
190 * Revision 2.58 2006/03/29 23:57:52 csoutheren
191 * Added patches from Paul Caswell to provide correct operation when using
192 * external RTP with H.323
194 * Revision 2.57 2006/03/20 10:37:47 csoutheren
195 * Applied patch #1453753 - added locking on media stream manipulation
196 * Thanks to Dinis Rosario
198 * Revision 2.56.2.4 2006/04/11 05:12:25 csoutheren
199 * Updated to current OpalMediaFormat changes
201 * Revision 2.56.2.3 2006/04/10 06:24:30 csoutheren
202 * Backport from CVS head up to Plugin_Merge3
204 * Revision 2.56.2.2 2006/04/07 07:57:20 csoutheren
205 * Halfway through media format changes - not working, but closer
207 * Revision 2.56.2.1 2006/04/06 05:33:08 csoutheren
208 * Backports from CVS head up to Plugin_Merge2
210 * Revision 2.59 2006/04/09 12:12:54 rjongbloed
211 * Changed the media format option merging to include the transcoder formats.
213 * Revision 2.58 2006/03/29 23:57:52 csoutheren
214 * Added patches from Paul Caswell to provide correct operation when using
215 * external RTP with H.323
217 * Revision 2.57 2006/03/20 10:37:47 csoutheren
218 * Applied patch #1453753 - added locking on media stream manipulation
219 * Thanks to Dinis Rosario
221 * Revision 2.56 2006/02/22 10:40:10 csoutheren
222 * Added patch #1374583 from Frederic Heem
223 * Added additional H.323 virtual function
225 * Revision 2.55 2005/12/06 21:32:25 dsandras
226 * Applied patch from Frederic Heem <frederic.heem _Atttt_ telsey.it> to fix
227 * assert in PSyncPoint when OnReleased is called twice from different threads.
228 * Thanks! (Patch #1374240)
230 * Revision 2.54 2005/11/30 13:44:20 csoutheren
231 * Removed compile warnings on Windows
233 * Revision 2.53 2005/11/24 20:31:55 dsandras
234 * Added support for echo cancelation using Speex.
235 * Added possibility to add a filter to an OpalMediaPatch for all patches of a connection.
237 * Revision 2.52 2005/10/04 20:31:30 dsandras
238 * Minor code cleanup.
240 * Revision 2.51 2005/10/04 12:59:28 rjongbloed
241 * Removed CanOpenSourceMediaStream/CanOpenSinkMediaStream functions and
242 * now use overides on OpenSourceMediaStream/OpenSinkMediaStream
243 * Moved addition of a media stream to list in OpalConnection to OnOpenMediaStream
244 * so is consistent across protocols.
246 * Revision 2.50 2005/09/15 17:02:40 dsandras
247 * Added the possibility for a connection to prevent the opening of a sink/source media stream.
249 * Revision 2.49 2005/09/06 12:44:49 rjongbloed
250 * Many fixes to finalise the video processing: merging remote media
252 * Revision 2.48 2005/08/24 10:43:51 rjongbloed
253 * Changed create video functions yet again so can return pointers that are not to be deleted.
255 * Revision 2.47 2005/08/23 12:45:09 rjongbloed
256 * Fixed creation of video preview window and setting video grab/display initial frame size.
258 * Revision 2.46 2005/08/04 17:20:22 dsandras
259 * Added functions to close/remove the media streams of a connection.
261 * Revision 2.45 2005/07/14 08:51:19 csoutheren
262 * Removed CreateExternalRTPAddress - it's not needed because you can override GetMediaAddress
263 * to do the same thing
264 * Fixed problems with logic associated with media bypass
266 * Revision 2.44 2005/07/11 06:52:16 csoutheren
267 * Added support for outgoing calls using external RTP
269 * Revision 2.43 2005/07/11 01:52:26 csoutheren
270 * Extended AnsweringCall to work for SIP as well as H.323
271 * Fixed problems with external RTP connection in H.323
272 * Added call to OnClosedMediaStream
274 * Revision 2.42 2005/06/02 13:18:02 rjongbloed
275 * Fixed compiler warnings
277 * Revision 2.41 2005/04/10 21:12:59 dsandras
278 * Added function to put the OpalMediaStreams on pause.
280 * Revision 2.40 2005/04/10 21:12:12 dsandras
281 * Added support for Blind Transfer.
283 * Revision 2.39 2005/04/10 21:11:25 dsandras
284 * Added support for call hold.
286 * Revision 2.38 2004/08/14 07:56:35 rjongbloed
287 * Major revision to utilise the PSafeCollection classes for the connections and calls.
289 * Revision 2.37 2004/07/14 13:26:14 rjongbloed
290 * Fixed issues with the propagation of the "established" phase of a call. Now
291 * calling an OnEstablished() chain like OnAlerting() and OnConnected() to
292 * finally arrive at OnEstablishedCall() on OpalManager
294 * Revision 2.36 2004/07/11 12:42:13 rjongbloed
295 * Added function on endpoints to get the list of all media formats any
296 * connection the endpoint may create can support.
298 * Revision 2.35 2004/05/17 13:24:18 rjongbloed
299 * Added silence suppression.
301 * Revision 2.34 2004/05/15 12:53:03 rjongbloed
302 * Added default username and display name to manager, for all endpoints.
304 * Revision 2.33 2004/05/01 10:00:52 rjongbloed
305 * Fixed ClearCallSynchronous so now is actually signalled when call is destroyed.
307 * Revision 2.32 2004/04/26 04:33:06 rjongbloed
308 * Move various call progress times from H.323 specific to general conenction.
310 * Revision 2.31 2004/04/18 13:31:28 rjongbloed
311 * Added new end call value from OpenH323.
313 * Revision 2.30 2004/03/13 06:25:54 rjongbloed
314 * Slight rearrangement of local party name and alias list to beter match common
315 * behaviour in ancestor.
316 * Abstracted local party name for endpoint into ancestor from H.,323.
318 * Revision 2.29 2004/03/02 09:57:54 rjongbloed
319 * Fixed problems with recent changes to RTP UseSession() function which broke it for H.323
321 * Revision 2.28 2004/02/24 11:30:11 rjongbloed
322 * Normalised RTP session management across protocols
324 * Revision 2.27 2004/01/18 15:36:47 rjongbloed
325 * Fixed problem with symmetric codecs
327 * Revision 2.26 2003/06/02 03:11:01 rjongbloed
328 * Fixed start media streams function actually starting the media streams.
329 * Fixed problem where a sink stream should be opened (for preference) using
330 * the source streams media format. That is no transcoder is used.
332 * Revision 2.25 2003/03/18 06:42:39 robertj
333 * Fixed incorrect return value, thanks gravsten
335 * Revision 2.24 2003/03/17 10:27:00 robertj
336 * Added video support.
338 * Revision 2.23 2003/03/07 08:12:54 robertj
339 * Changed DTMF entry so single # returns itself instead of an empty string.
341 * Revision 2.22 2003/03/06 03:57:47 robertj
342 * IVR support (work in progress) requiring large changes everywhere.
344 * Revision 2.21 2003/01/07 04:39:53 robertj
345 * Updated to OpenH323 v1.11.2
347 * Revision 2.20 2002/11/10 11:33:19 robertj
348 * Updated to OpenH323 v1.10.3
350 * Revision 2.19 2002/07/01 04:56:33 robertj
351 * Updated to OpenH323 v1.9.1
353 * Revision 2.18 2002/06/16 02:24:05 robertj
354 * Fixed memory leak of media streams in non H323 protocols, thanks Ted Szoczei
356 * Revision 2.17 2002/04/10 03:09:01 robertj
357 * Moved code for handling media bypass address resolution into ancestor as
358 * now done ths same way in both SIP and H.323.
360 * Revision 2.16 2002/04/09 00:19:06 robertj
361 * Changed "callAnswered" to better description of "originating".
363 * Revision 2.15 2002/02/19 07:49:23 robertj
364 * Added OpalRFC2833 as a OpalMediaFormat variable.
365 * Restructured media bypass functions to fix problems with RFC2833.
367 * Revision 2.14 2002/02/13 02:31:13 robertj
368 * Added trace for default CanDoMediaBypass
370 * Revision 2.13 2002/02/11 09:32:13 robertj
371 * Updated to openH323 v1.8.0
373 * Revision 2.12 2002/02/11 07:41:58 robertj
374 * Added media bypass for streams between compatible protocols.
376 * Revision 2.11 2002/01/22 05:12:12 robertj
377 * Revamp of user input API triggered by RFC2833 support
379 * Revision 2.10 2001/11/15 06:56:54 robertj
380 * Added session ID to trace log in OenSourceMediaStreams
382 * Revision 2.9 2001/11/14 01:31:55 robertj
383 * Corrected placement of adjusting media format list.
385 * Revision 2.8 2001/11/02 10:45:19 robertj
386 * Updated to OpenH323 v1.7.3
388 * Revision 2.7 2001/10/15 04:34:02 robertj
389 * Added delayed start of media patch threads.
390 * Removed answerCall signal and replaced with state based functions.
392 * Revision 2.6 2001/10/04 00:44:51 robertj
393 * Removed GetMediaFormats() function as is not useful.
395 * Revision 2.5 2001/10/03 05:56:15 robertj
396 * Changes abndwidth management API.
398 * Revision 2.4 2001/08/22 10:20:09 robertj
399 * Changed connection locking to use double mutex to guarantee that
400 * no threads can ever deadlock or access deleted connection.
402 * Revision 2.3 2001/08/17 08:26:26 robertj
403 * Moved call end reasons enum from OpalConnection to global.
405 * Revision 2.2 2001/08/13 05:10:40 robertj
406 * Updates from OpenH323 v1.6.0 release.
408 * Revision 2.1 2001/08/01 05:45:01 robertj
409 * Moved media formats list from endpoint to connection.
411 * Revision 2.0 2001/07/27 15:48:25 robertj
412 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
416 #include <ptlib.h>
418 #ifdef __GNUC__
419 #pragma implementation "connection.h"
420 #endif
422 #include <opal/buildopts.h>
424 #include <opal/connection.h>
426 #include <opal/manager.h>
427 #include <opal/endpoint.h>
428 #include <opal/call.h>
429 #include <opal/transcoders.h>
430 #include <opal/patch.h>
431 #include <codec/silencedetect.h>
432 #include <codec/echocancel.h>
433 #include <codec/rfc2833.h>
434 #include <rtp/rtp.h>
435 #include <t120/t120proto.h>
436 #include <t38/t38proto.h>
437 #include <h224/h224handler.h>
439 #if OPAL_T38FAX
440 #include <t38/t38proto.h>
441 #endif
443 #define new PNEW
446 #if PTRACING
447 ostream & operator<<(ostream & out, OpalConnection::Phases phase)
449 static const char * const names[OpalConnection::NumPhases] = {
450 "UninitialisedPhase",
451 "SetUpPhase",
452 "AlertingPhase",
453 "ConnectedPhase",
454 "EstablishedPhase",
455 "ReleasingPhase",
456 "ReleasedPhase"
458 return out << names[phase];
462 ostream & operator<<(ostream & out, OpalConnection::CallEndReason reason)
464 const char * const names[OpalConnection::NumCallEndReasons] = {
465 "EndedByLocalUser", /// Local endpoint application cleared call
466 "EndedByNoAccept", /// Local endpoint did not accept call OnIncomingCall()=FALSE
467 "EndedByAnswerDenied", /// Local endpoint declined to answer call
468 "EndedByRemoteUser", /// Remote endpoint application cleared call
469 "EndedByRefusal", /// Remote endpoint refused call
470 "EndedByNoAnswer", /// Remote endpoint did not answer in required time
471 "EndedByCallerAbort", /// Remote endpoint stopped calling
472 "EndedByTransportFail", /// Transport error cleared call
473 "EndedByConnectFail", /// Transport connection failed to establish call
474 "EndedByGatekeeper", /// Gatekeeper has cleared call
475 "EndedByNoUser", /// Call failed as could not find user (in GK)
476 "EndedByNoBandwidth", /// Call failed as could not get enough bandwidth
477 "EndedByCapabilityExchange",/// Could not find common capabilities
478 "EndedByCallForwarded", /// Call was forwarded using FACILITY message
479 "EndedBySecurityDenial", /// Call failed a security check and was ended
480 "EndedByLocalBusy", /// Local endpoint busy
481 "EndedByLocalCongestion", /// Local endpoint congested
482 "EndedByRemoteBusy", /// Remote endpoint busy
483 "EndedByRemoteCongestion", /// Remote endpoint congested
484 "EndedByUnreachable", /// Could not reach the remote party
485 "EndedByNoEndPoint", /// The remote party is not running an endpoint
486 "EndedByOffline", /// The remote party is off line
487 "EndedByTemporaryFailure", /// The remote failed temporarily app may retry
488 "EndedByQ931Cause", /// The remote ended the call with unmapped Q.931 cause code
489 "EndedByDurationLimit", /// Call cleared due to an enforced duration limit
490 "EndedByInvalidConferenceID",/// Call cleared due to invalid conference ID
491 "EndedByNoDialTone", /// Call cleared due to missing dial tone
492 "EndedByNoRingBackTone", /// Call cleared due to missing ringback tone
493 "EndedByOutOfService", /// Call cleared because the line is out of service,
494 "EndedByAcceptingCallWaiting", /// Call cleared because another call is answered
496 PAssert((PINDEX)(reason & 0xff) < PARRAYSIZE(names), "Invalid reason");
497 return out << names[reason & 0xff];
500 ostream & operator<<(ostream & o, OpalConnection::AnswerCallResponse s)
502 static const char * const AnswerCallResponseNames[OpalConnection::NumAnswerCallResponses] = {
503 "AnswerCallNow",
504 "AnswerCallDenied",
505 "AnswerCallPending",
506 "AnswerCallDeferred",
507 "AnswerCallAlertWithMedia",
508 "AnswerCallDeferredWithMedia",
509 "AnswerCallProgress",
510 "AnswerCallNowAndReleaseCurrent"
512 if ((PINDEX)s >= PARRAYSIZE(AnswerCallResponseNames))
513 o << "InvalidAnswerCallResponse<" << (unsigned)s << '>';
514 else if (AnswerCallResponseNames[s] == NULL)
515 o << "AnswerCallResponse<" << (unsigned)s << '>';
516 else
517 o << AnswerCallResponseNames[s];
518 return o;
521 ostream & operator<<(ostream & o, OpalConnection::SendUserInputModes m)
523 static const char * const SendUserInputModeNames[OpalConnection::NumSendUserInputModes] = {
524 "SendUserInputAsQ931",
525 "SendUserInputAsString",
526 "SendUserInputAsTone",
527 "SendUserInputAsRFC2833",
528 "SendUserInputAsSeparateRFC2833",
529 "SendUserInputAsProtocolDefault"
532 if ((PINDEX)m >= PARRAYSIZE(SendUserInputModeNames))
533 o << "InvalidSendUserInputMode<" << (unsigned)m << '>';
534 else if (SendUserInputModeNames[m] == NULL)
535 o << "SendUserInputMode<" << (unsigned)m << '>';
536 else
537 o << SendUserInputModeNames[m];
538 return o;
541 #endif
543 /////////////////////////////////////////////////////////////////////////////
545 OpalConnection::OpalConnection(OpalCall & call,
546 OpalEndPoint & ep,
547 const PString & token,
548 unsigned int options,
549 OpalConnection::StringOptions * _stringOptions)
550 : ownerCall(call),
551 endpoint(ep),
552 phase(UninitialisedPhase),
553 callToken(token),
554 originating(FALSE),
555 alertingTime(0),
556 connectedTime(0),
557 callEndTime(0),
558 localPartyName(ep.GetDefaultLocalPartyName()),
559 displayName(ep.GetDefaultDisplayName()),
560 remotePartyName(token),
561 callEndReason(NumCallEndReasons),
562 remoteIsNAT(FALSE),
563 q931Cause(0x100),
564 silenceDetector(NULL),
565 echoCanceler(NULL),
566 #if OPAL_T120DATA
567 t120handler(NULL),
568 #endif
569 #if OPAL_T38FAX
570 t38handler(NULL),
571 #endif
572 #if OPAL_H224
573 h224Handler(NULL),
574 #endif
575 stringOptions((_stringOptions == NULL) ? NULL : new OpalConnection::StringOptions(*_stringOptions))
577 PTRACE(3, "OpalCon\tCreated connection " << *this);
579 PAssert(ownerCall.SafeReference(), PLogicError);
581 // Set an initial value for the A-Party name, if we are in fact the A-Party
582 if (ownerCall.connectionsActive.IsEmpty())
583 ownerCall.partyA = localPartyName;
585 ownerCall.connectionsActive.Append(this);
587 detectInBandDTMF = !endpoint.GetManager().DetectInBandDTMFDisabled();
588 minAudioJitterDelay = endpoint.GetManager().GetMinAudioJitterDelay();
589 maxAudioJitterDelay = endpoint.GetManager().GetMaxAudioJitterDelay();
590 bandwidthAvailable = endpoint.GetInitialBandwidth();
592 switch (options & SendDTMFMask) {
593 case SendDTMFAsString:
594 sendUserInputMode = SendUserInputAsString;
595 break;
596 case SendDTMFAsTone:
597 sendUserInputMode = SendUserInputAsTone;
598 break;
599 case SendDTMFAsRFC2833:
600 sendUserInputMode = SendUserInputAsInlineRFC2833;
601 break;
602 case SendDTMFAsDefault:
603 default:
604 sendUserInputMode = ep.GetSendUserInputMode();
605 break;
608 rfc2833Handler = new OpalRFC2833Proto(PCREATE_NOTIFIER(OnUserInputInlineRFC2833));
609 #if OPAL_T38FAX
610 ciscoNSEHandler = new OpalRFC2833Proto(PCREATE_NOTIFIER(OnUserInputInlineCiscoNSE));
611 #endif
613 securityMode = ep.GetDefaultSecurityMode();
615 switch (options & RTPAggregationMask) {
616 case RTPAggregationDisable:
617 useRTPAggregation = FALSE;
618 break;
619 case RTPAggregationEnable:
620 useRTPAggregation = TRUE;
621 break;
622 default:
623 useRTPAggregation = endpoint.UseRTPAggregation();
626 if (stringOptions != NULL) {
627 PString id((*stringOptions)("Call-Identifier"));
628 if (!id.IsEmpty())
629 callIdentifier = PGloballyUniqueID(id);
633 OpalConnection::~OpalConnection()
636 PWaitAndSignal mutex(mediaStreamMutex);
637 mediaStreams.RemoveAll();
640 delete silenceDetector;
641 delete echoCanceler;
642 delete rfc2833Handler;
643 #if OPAL_T120DATA
644 delete t120handler;
645 #endif
646 #if OPAL_T38FAX
647 delete ciscoNSEHandler;
648 delete t38handler;
649 #endif
650 #if OPAL_H224
651 delete h224Handler;
652 #endif
653 delete stringOptions;
655 ownerCall.connectionsActive.Remove(this);
656 ownerCall.SafeDereference();
658 PTRACE(3, "OpalCon\tConnection " << *this << " destroyed.");
662 void OpalConnection::PrintOn(ostream & strm) const
664 strm << ownerCall << '-'<< endpoint << '[' << callToken << ']';
667 BOOL OpalConnection::OnSetUpConnection()
669 PTRACE(3, "OpalCon\tOnSetUpConnection" << *this);
670 return endpoint.OnSetUpConnection(*this);
673 void OpalConnection::HoldConnection()
679 void OpalConnection::RetrieveConnection()
685 BOOL OpalConnection::IsConnectionOnHold()
687 return FALSE;
690 void OpalConnection::SetCallEndReason(CallEndReason reason)
692 // Only set reason if not already set to something
693 if (callEndReason == NumCallEndReasons) {
694 if ((reason & EndedWithQ931Code) != 0) {
695 SetQ931Cause((int)reason >> 24);
696 reason = (CallEndReason)(reason & 0xff);
698 PTRACE(3, "OpalCon\tCall end reason for " << GetToken() << " set to " << reason);
699 callEndReason = reason;
704 void OpalConnection::ClearCall(CallEndReason reason)
706 // Now set reason for the connection close
707 SetCallEndReason(reason);
708 ownerCall.Clear(reason);
712 void OpalConnection::ClearCallSynchronous(PSyncPoint * sync, CallEndReason reason)
714 // Now set reason for the connection close
715 SetCallEndReason(reason);
716 ownerCall.Clear(reason, sync);
720 void OpalConnection::TransferConnection(const PString & PTRACE_PARAM(remoteParty),
721 const PString & /*callIdentity*/)
723 PTRACE(3, "OpalCon\tCan not transfer connection to " << remoteParty);
727 void OpalConnection::Release(CallEndReason reason)
730 PWaitAndSignal m(phaseMutex);
731 if (phase >= ReleasingPhase) {
732 PTRACE(3, "OpalCon\tAlready released " << *this);
733 return;
735 SetPhase(ReleasingPhase);
739 PSafeLockReadWrite safeLock(*this);
740 if (!safeLock.IsLocked()) {
741 PTRACE(3, "OpalCon\tAlready released " << *this);
742 return;
745 PTRACE(3, "OpalCon\tReleasing " << *this);
747 // Now set reason for the connection close
748 SetCallEndReason(reason);
750 // Add a reference for the thread we are about to start
751 SafeReference();
754 PThread::Create(PCREATE_NOTIFIER(OnReleaseThreadMain), 0,
755 PThread::AutoDeleteThread,
756 PThread::NormalPriority,
757 "OnRelease:%x");
761 void OpalConnection::OnReleaseThreadMain(PThread &, INT)
763 OnReleased();
765 PTRACE(3, "OpalCon\tOnRelease thread completed for " << GetToken());
767 // Dereference on the way out of the thread
768 SafeDereference();
772 void OpalConnection::OnReleased()
774 PTRACE(3, "OpalCon\tOnReleased " << *this);
776 CloseMediaStreams();
778 endpoint.OnReleased(*this);
782 BOOL OpalConnection::OnIncomingConnection()
784 return TRUE;
788 BOOL OpalConnection::OnIncomingConnection(unsigned int /*options*/)
790 return TRUE;
794 BOOL OpalConnection::OnIncomingConnection(unsigned options, OpalConnection::StringOptions * stringOptions)
796 return OnIncomingConnection() &&
797 OnIncomingConnection(options) &&
798 endpoint.OnIncomingConnection(*this, options, stringOptions);
802 PString OpalConnection::GetDestinationAddress()
804 return "*";
808 BOOL OpalConnection::ForwardCall(const PString & /*forwardParty*/)
810 return FALSE;
814 void OpalConnection::OnAlerting()
816 endpoint.OnAlerting(*this);
819 OpalConnection::AnswerCallResponse OpalConnection::OnAnswerCall(const PString & callerName)
821 return endpoint.OnAnswerCall(*this, callerName);
824 void OpalConnection::AnsweringCall(AnswerCallResponse /*response*/)
828 void OpalConnection::OnConnected()
830 endpoint.OnConnected(*this);
834 void OpalConnection::OnEstablished()
836 endpoint.OnEstablished(*this);
840 void OpalConnection::AdjustMediaFormats(OpalMediaFormatList & mediaFormats) const
842 endpoint.AdjustMediaFormats(*this, mediaFormats);
845 BOOL OpalConnection::OpenSourceMediaStream(const OpalMediaFormatList & mediaFormats, unsigned sessionID)
848 PWaitAndSignal m(mediaStreamMutex);
850 // See if already opened
851 OpalMediaStream * stream = GetMediaStream(sessionID, TRUE);
853 if (stream != NULL && stream->IsOpen()) {
854 PTRACE(3, "OpalCon\tOpenSourceMediaStream (already opened) for session "
855 << sessionID << " on " << *this);
856 return TRUE;
859 PTRACE(3, "OpalCon\tOpenSourceMediaStream for session " << sessionID << " on " << *this);
861 OpalMediaFormat sourceFormat, destinationFormat;
862 if (!OpalTranscoder::SelectFormats(sessionID,
863 GetMediaFormats(),
864 mediaFormats,
865 sourceFormat,
866 destinationFormat)) {
867 PTRACE(2, "OpalCon\tOpenSourceMediaStream session " << sessionID
868 << ", could not find compatible media format:\n"
869 " source formats=" << setfill(',') << GetMediaFormats() << "\n"
870 " sink formats=" << mediaFormats << setfill(' '));
871 return FALSE;
874 PTRACE(3, "OpalCon\tSelected media stream " << sourceFormat << " -> " << destinationFormat);
876 if (stream == NULL)
877 stream = CreateMediaStream(sourceFormat, sessionID, TRUE);
879 if (stream == NULL) {
880 PTRACE(1, "OpalCon\tCreateMediaStream returned NULL for session "
881 << sessionID << " on " << *this);
882 return FALSE;
885 if (stream->Open()) {
886 if (OnOpenMediaStream(*stream)) {
887 PTRACE(3, "OpalCon\tOpened source stream " << stream->GetID());
888 return TRUE;
890 PTRACE(2, "OpalCon\tSource media OnOpenMediaStream open of " << sourceFormat << " failed.");
892 else {
893 PTRACE(2, "OpalCon\tSource media stream open of " << sourceFormat << " failed.");
896 if (!RemoveMediaStream(stream))
897 delete stream;
900 return FALSE;
904 OpalMediaStream * OpalConnection::OpenSinkMediaStream(OpalMediaStream & source)
906 unsigned sessionID = source.GetSessionID();
908 PTRACE(3, "OpalCon\tOpenSinkMediaStream " << *this << " session=" << sessionID);
910 OpalMediaFormat sourceFormat = source.GetMediaFormat();
912 // Reorder the media formats from this protocol so we give preference
913 // to what has been selected in the source media stream.
914 OpalMediaFormatList destinationFormats = GetMediaFormats();
915 PStringArray order = sourceFormat;
916 // Second preference is given to the previous media stream already
917 // opened to maintain symmetric codecs, if possible.
919 PWaitAndSignal m(mediaStreamMutex);
920 OpalMediaStream * otherStream = GetMediaStream(sessionID, TRUE);
921 if (otherStream != NULL)
922 order += otherStream->GetMediaFormat();
923 destinationFormats.Reorder(order);
925 OpalMediaFormat destinationFormat;
926 if (!OpalTranscoder::SelectFormats(sessionID,
927 sourceFormat, // Only use selected format on source
928 destinationFormats,
929 sourceFormat,
930 destinationFormat)) {
931 PTRACE(2, "OpalCon\tOpenSinkMediaStream, could not find compatible media format:\n"
932 " source formats=" << setfill(',') << sourceFormat << "\n"
933 " sink formats=" << destinationFormats << setfill(' '));
934 return NULL;
937 PTRACE(3, "OpalCon\tOpenSinkMediaStream, selected " << sourceFormat << " -> " << destinationFormat);
939 OpalMediaStream * stream = CreateMediaStream(destinationFormat, sessionID, FALSE);
940 if (stream == NULL) {
941 PTRACE(1, "OpalCon\tCreateMediaStream " << *this << " returned NULL");
942 return NULL;
945 if (stream->Open()) {
946 if (OnOpenMediaStream(*stream)) {
947 PTRACE(3, "OpalCon\tOpened sink stream " << stream->GetID());
948 return stream;
950 PTRACE(2, "OpalCon\tSink media stream OnOpenMediaStream of " << destinationFormat << " failed.");
952 else {
953 PTRACE(2, "OpalCon\tSink media stream open of " << destinationFormat << " failed.");
956 if (!RemoveMediaStream(stream))
957 delete stream;
960 return NULL;
964 void OpalConnection::StartMediaStreams()
966 PWaitAndSignal mutex(mediaStreamMutex);
967 for (PINDEX i = 0; i < mediaStreams.GetSize(); i++) {
968 if (mediaStreams[i].IsOpen()) {
969 OpalMediaStream & strm = mediaStreams[i];
970 strm.Start();
973 PTRACE(2, "OpalCon\tMedia stream threads started.");
977 void OpalConnection::CloseMediaStreams()
979 PWaitAndSignal mutex(mediaStreamMutex);
980 for (PINDEX i = 0; i < mediaStreams.GetSize(); i++) {
981 OpalMediaStream & strm = mediaStreams[i];
982 if (strm.IsOpen()) {
983 OnClosedMediaStream(strm);
984 strm.Close();
988 PTRACE(2, "OpalCon\tMedia stream threads closed.");
992 void OpalConnection::RemoveMediaStreams()
994 PWaitAndSignal mutex(mediaStreamMutex);
995 CloseMediaStreams();
996 mediaStreams.RemoveAll();
998 PTRACE(2, "OpalCon\tMedia stream threads removed from session.");
1001 void OpalConnection::PauseMediaStreams(BOOL paused)
1003 PWaitAndSignal mutex(mediaStreamMutex);
1004 for (PINDEX i = 0; i < mediaStreams.GetSize(); i++)
1005 mediaStreams[i].SetPaused(paused);
1009 OpalMediaStream * OpalConnection::CreateMediaStream(
1010 #if OPAL_VIDEO
1011 const OpalMediaFormat & mediaFormat,
1012 unsigned sessionID,
1013 BOOL isSource
1014 #else
1015 const OpalMediaFormat & ,
1016 unsigned ,
1017 BOOL
1018 #endif
1021 #if OPAL_VIDEO
1022 if (sessionID == OpalMediaFormat::DefaultVideoSessionID) {
1023 if (isSource) {
1024 PVideoInputDevice * videoDevice;
1025 BOOL autoDelete;
1026 if (CreateVideoInputDevice(mediaFormat, videoDevice, autoDelete)) {
1027 PVideoOutputDevice * previewDevice;
1028 if (!CreateVideoOutputDevice(mediaFormat, TRUE, previewDevice, autoDelete))
1029 previewDevice = NULL;
1030 return new OpalVideoMediaStream(*this, mediaFormat, sessionID, videoDevice, previewDevice, autoDelete);
1033 else {
1034 PVideoOutputDevice * videoDevice;
1035 BOOL autoDelete;
1036 if (CreateVideoOutputDevice(mediaFormat, FALSE, videoDevice, autoDelete))
1037 return new OpalVideoMediaStream(*this, mediaFormat, sessionID, NULL, videoDevice, autoDelete);
1040 #endif
1042 return NULL;
1046 BOOL OpalConnection::OnOpenMediaStream(OpalMediaStream & stream)
1048 if (!endpoint.OnOpenMediaStream(*this, stream))
1049 return FALSE;
1051 if (!LockReadWrite())
1052 return FALSE;
1055 PWaitAndSignal m(mediaStreamMutex);
1056 if (mediaStreams.GetObjectsIndex(&stream) == P_MAX_INDEX)
1057 mediaStreams.Append(&stream);
1060 if (GetPhase() == ConnectedPhase) {
1061 SetPhase(EstablishedPhase);
1062 OnEstablished();
1065 UnlockReadWrite();
1067 return TRUE;
1071 void OpalConnection::OnClosedMediaStream(const OpalMediaStream & stream)
1073 endpoint.OnClosedMediaStream(stream);
1077 void OpalConnection::OnPatchMediaStream(BOOL /*isSource*/, OpalMediaPatch & /*patch*/)
1079 PTRACE(3, "OpalCon\tNew patch created");
1083 void OpalConnection::AttachRFC2833HandlerToPatch(BOOL isSource, OpalMediaPatch & patch)
1085 if (rfc2833Handler != NULL) {
1086 if(isSource) {
1087 PTRACE(3, "OpalCon\tAdding RFC2833 receive handler");
1088 OpalMediaStream & mediaStream = patch.GetSource();
1089 patch.AddFilter(rfc2833Handler->GetReceiveHandler(), mediaStream.GetMediaFormat());
1090 } else {
1091 PTRACE(3, "OpalCon\tAdding RFC2833 transmit handler");
1092 patch.AddFilter(rfc2833Handler->GetTransmitHandler(), patch.GetSinkFormat());
1096 #if OPAL_T38FAX
1097 if (ciscoNSEHandler != NULL) {
1098 if(isSource) {
1099 PTRACE(3, "OpalCon\tAdding Cisco NSE receive handler");
1100 OpalMediaStream & mediaStream = patch.GetSource();
1101 patch.AddFilter(ciscoNSEHandler->GetReceiveHandler(), mediaStream.GetMediaFormat());
1102 } else {
1103 PTRACE(3, "OpalCon\tAdding Cisco NSE transmit handler");
1104 patch.AddFilter(ciscoNSEHandler->GetTransmitHandler(), patch.GetSinkFormat());
1107 #endif
1111 OpalMediaStream * OpalConnection::GetMediaStream(unsigned sessionId, BOOL source) const
1113 PWaitAndSignal mutex(mediaStreamMutex);
1114 for (PINDEX i = 0; i < mediaStreams.GetSize(); i++) {
1115 if (mediaStreams[i].GetSessionID() == sessionId &&
1116 mediaStreams[i].IsSource() == source)
1117 return &mediaStreams[i];
1120 return NULL;
1123 BOOL OpalConnection::RemoveMediaStream(OpalMediaStream * strm)
1125 PWaitAndSignal mutex(mediaStreamMutex);
1126 PINDEX index = mediaStreams.GetObjectsIndex(strm);
1127 if (index == P_MAX_INDEX)
1128 return FALSE;
1130 OpalMediaStream & s = mediaStreams[index];
1131 if (s.IsOpen()) {
1132 OnClosedMediaStream(s);
1133 s.Close();
1135 mediaStreams.RemoveAt(index);
1137 return TRUE;
1142 BOOL OpalConnection::IsMediaBypassPossible(unsigned /*sessionID*/) const
1144 PTRACE(3, "OpalCon\tIsMediaBypassPossible: default returns FALSE");
1145 return FALSE;
1149 BOOL OpalConnection::GetMediaInformation(unsigned sessionID,
1150 MediaInformation & info) const
1152 if (!mediaTransportAddresses.Contains(sessionID)) {
1153 PTRACE(3, "OpalCon\tGetMediaInformation for session " << sessionID << " - no channel.");
1154 return FALSE;
1157 OpalTransportAddress & address = mediaTransportAddresses[sessionID];
1159 PIPSocket::Address ip;
1160 WORD port;
1161 if (address.GetIpAndPort(ip, port)) {
1162 info.data = OpalTransportAddress(ip, (WORD)(port&0xfffe));
1163 info.control = OpalTransportAddress(ip, (WORD)(port|0x0001));
1165 else
1166 info.data = info.control = address;
1168 info.rfc2833 = rfc2833Handler->GetPayloadType();
1169 PTRACE(3, "OpalCon\tGetMediaInformation for session " << sessionID
1170 << " data=" << info.data << " rfc2833=" << info.rfc2833);
1171 return TRUE;
1174 #if OPAL_VIDEO
1176 void OpalConnection::AddVideoMediaFormats(OpalMediaFormatList & mediaFormats) const
1178 endpoint.AddVideoMediaFormats(mediaFormats, this);
1182 BOOL OpalConnection::CreateVideoInputDevice(const OpalMediaFormat & mediaFormat,
1183 PVideoInputDevice * & device,
1184 BOOL & autoDelete)
1186 return endpoint.CreateVideoInputDevice(*this, mediaFormat, device, autoDelete);
1190 BOOL OpalConnection::CreateVideoOutputDevice(const OpalMediaFormat & mediaFormat,
1191 BOOL preview,
1192 PVideoOutputDevice * & device,
1193 BOOL & autoDelete)
1195 return endpoint.CreateVideoOutputDevice(*this, mediaFormat, preview, device, autoDelete);
1198 #endif // OPAL_VIDEO
1201 BOOL OpalConnection::SetAudioVolume(BOOL /*source*/, unsigned /*percentage*/)
1203 return FALSE;
1207 unsigned OpalConnection::GetAudioSignalLevel(BOOL /*source*/)
1209 return UINT_MAX;
1213 RTP_Session * OpalConnection::GetSession(unsigned sessionID) const
1215 return rtpSessions.GetSession(sessionID);
1219 RTP_Session * OpalConnection::UseSession(const OpalTransport & transport,
1220 unsigned sessionID,
1221 RTP_QOS * rtpqos)
1223 RTP_Session * rtpSession = rtpSessions.UseSession(sessionID);
1224 if (rtpSession == NULL) {
1225 rtpSession = CreateSession(transport, sessionID, rtpqos);
1226 rtpSessions.AddSession(rtpSession);
1229 return rtpSession;
1233 void OpalConnection::ReleaseSession(unsigned sessionID,
1234 BOOL clearAll)
1236 rtpSessions.ReleaseSession(sessionID, clearAll);
1240 RTP_Session * OpalConnection::CreateSession(const OpalTransport & transport,
1241 unsigned sessionID,
1242 RTP_QOS * rtpqos)
1244 // We only support RTP over UDP at this point in time ...
1245 if (!transport.IsCompatibleTransport("ip$127.0.0.1"))
1246 return NULL;
1248 // We support video, audio and T38 over IP
1249 if (sessionID != OpalMediaFormat::DefaultAudioSessionID &&
1250 sessionID != OpalMediaFormat::DefaultVideoSessionID
1251 #if OPAL_T38FAX
1252 && sessionID != OpalMediaFormat::DefaultDataSessionID
1253 #endif
1255 return NULL;
1257 PIPSocket::Address localAddress;
1258 transport.GetLocalAddress().GetIpAddress(localAddress);
1260 OpalManager & manager = GetEndPoint().GetManager();
1262 PIPSocket::Address remoteAddress;
1263 transport.GetRemoteAddress().GetIpAddress(remoteAddress);
1264 PSTUNClient * stun = manager.GetSTUN(remoteAddress);
1266 // create an (S)RTP session or T38 pseudo-session as appropriate
1267 RTP_UDP * rtpSession = NULL;
1269 #if OPAL_T38FAX
1270 if (sessionID == OpalMediaFormat::DefaultDataSessionID) {
1271 rtpSession = new T38PseudoRTP(NULL, sessionID, remoteIsNAT);
1273 else
1274 #endif
1276 if (!securityMode.IsEmpty()) {
1277 OpalSecurityMode * parms = PFactory<OpalSecurityMode>::CreateInstance(securityMode);
1278 if (parms == NULL) {
1279 PTRACE(1, "OpalCon\tSecurity mode " << securityMode << " unknown");
1280 return NULL;
1282 rtpSession = parms->CreateRTPSession(
1283 useRTPAggregation ? endpoint.GetRTPAggregator() : NULL,
1284 sessionID, remoteIsNAT);
1285 if (rtpSession == NULL) {
1286 PTRACE(1, "OpalCon\tCannot create RTP session for security mode " << securityMode);
1287 delete parms;
1288 return NULL;
1291 else
1293 rtpSession = new RTP_UDP(
1294 useRTPAggregation ? endpoint.GetRTPAggregator() : NULL,
1295 sessionID, remoteIsNAT);
1298 WORD firstPort = manager.GetRtpIpPortPair();
1299 WORD nextPort = firstPort;
1300 while (!rtpSession->Open(localAddress,
1301 nextPort, nextPort,
1302 manager.GetRtpIpTypeofService(),
1303 stun,
1304 rtpqos)) {
1305 nextPort = manager.GetRtpIpPortPair();
1306 if (nextPort == firstPort) {
1307 delete rtpSession;
1308 return NULL;
1312 localAddress = rtpSession->GetLocalAddress();
1313 if (manager.TranslateIPAddress(localAddress, remoteAddress))
1314 rtpSession->SetLocalAddress(localAddress);
1315 return rtpSession;
1319 BOOL OpalConnection::SetBandwidthAvailable(unsigned newBandwidth, BOOL force)
1321 PTRACE(3, "OpalCon\tSetting bandwidth to " << newBandwidth << "00b/s on connection " << *this);
1323 unsigned used = GetBandwidthUsed();
1324 if (used > newBandwidth) {
1325 if (!force)
1326 return FALSE;
1328 #if 0
1329 // Go through media channels and close down some.
1330 PINDEX chanIdx = GetmediaStreams->GetSize();
1331 while (used > newBandwidth && chanIdx-- > 0) {
1332 OpalChannel * channel = logicalChannels->GetChannelAt(chanIdx);
1333 if (channel != NULL) {
1334 used -= channel->GetBandwidthUsed();
1335 const H323ChannelNumber & number = channel->GetNumber();
1336 CloseLogicalChannel(number, number.IsFromRemote());
1339 #endif
1342 bandwidthAvailable = newBandwidth - used;
1343 return TRUE;
1347 unsigned OpalConnection::GetBandwidthUsed() const
1349 unsigned used = 0;
1351 #if 0
1352 for (PINDEX i = 0; i < logicalChannels->GetSize(); i++) {
1353 OpalChannel * channel = logicalChannels->GetChannelAt(i);
1354 if (channel != NULL)
1355 used += channel->GetBandwidthUsed();
1357 #endif
1359 PTRACE(3, "OpalCon\tBandwidth used is "
1360 << used << "00b/s for " << *this);
1362 return used;
1366 BOOL OpalConnection::SetBandwidthUsed(unsigned releasedBandwidth,
1367 unsigned requiredBandwidth)
1369 PTRACE_IF(3, releasedBandwidth > 0, "OpalCon\tBandwidth release of "
1370 << releasedBandwidth/10 << '.' << releasedBandwidth%10 << "kb/s");
1372 bandwidthAvailable += releasedBandwidth;
1374 PTRACE_IF(3, requiredBandwidth > 0, "OpalCon\tBandwidth request of "
1375 << requiredBandwidth/10 << '.' << requiredBandwidth%10
1376 << "kb/s, available: "
1377 << bandwidthAvailable/10 << '.' << bandwidthAvailable%10
1378 << "kb/s");
1380 if (requiredBandwidth > bandwidthAvailable) {
1381 PTRACE(2, "OpalCon\tAvailable bandwidth exceeded on " << *this);
1382 return FALSE;
1385 bandwidthAvailable -= requiredBandwidth;
1387 return TRUE;
1390 void OpalConnection::SetSendUserInputMode(SendUserInputModes mode)
1392 PTRACE(2, "OPAL\tSetting default User Input send mode to " << mode);
1393 sendUserInputMode = mode;
1396 BOOL OpalConnection::SendUserInputString(const PString & value)
1398 for (const char * c = value; *c != '\0'; c++) {
1399 if (!SendUserInputTone(*c, 0))
1400 return FALSE;
1402 return TRUE;
1406 BOOL OpalConnection::SendUserInputTone(char tone, unsigned duration)
1408 if (duration == 0)
1409 duration = 180;
1411 return rfc2833Handler->SendTone(tone, duration);
1415 void OpalConnection::OnUserInputString(const PString & value)
1417 endpoint.OnUserInputString(*this, value);
1421 void OpalConnection::OnUserInputTone(char tone, unsigned duration)
1423 endpoint.OnUserInputTone(*this, tone, duration);
1427 PString OpalConnection::GetUserInput(unsigned timeout)
1429 PString reply;
1430 if (userInputAvailable.Wait(PTimeInterval(0, timeout))) {
1431 userInputMutex.Wait();
1432 reply = userInputString;
1433 userInputString = PString();
1434 userInputMutex.Signal();
1436 return reply;
1440 void OpalConnection::SetUserInput(const PString & input)
1442 userInputMutex.Wait();
1443 userInputString += input;
1444 userInputMutex.Signal();
1445 userInputAvailable.Signal();
1449 PString OpalConnection::ReadUserInput(const char * terminators,
1450 unsigned lastDigitTimeout,
1451 unsigned firstDigitTimeout)
1453 return endpoint.ReadUserInput(*this, terminators, lastDigitTimeout, firstDigitTimeout);
1457 BOOL OpalConnection::PromptUserInput(BOOL /*play*/)
1459 return TRUE;
1463 void OpalConnection::OnUserInputInlineRFC2833(OpalRFC2833Info & info, INT)
1465 if (!info.IsToneStart())
1466 OnUserInputTone(info.GetTone(), info.GetDuration()/8);
1469 void OpalConnection::OnUserInputInlineCiscoNSE(OpalRFC2833Info & /*info*/, INT)
1471 cout << "Received NSE event" << endl;
1472 //if (!info.IsToneStart())
1473 // OnUserInputTone(info.GetTone(), info.GetDuration()/8);
1476 void OpalConnection::OnUserInputInBandDTMF(RTP_DataFrame & frame, INT)
1478 // This function is set up as an 'audio filter'.
1479 // This allows us to access the 16 bit PCM audio (at 8Khz sample rate)
1480 // before the audio is passed on to the sound card (or other output device)
1482 // Pass the 16 bit PCM audio through the DTMF decoder
1483 PString tones = dtmfDecoder.Decode((const short *)frame.GetPayloadPtr(), frame.GetPayloadSize()/sizeof(short));
1484 if (!tones.IsEmpty()) {
1485 PTRACE(1, "OPAL\tDTMF detected. " << tones);
1486 PINDEX i;
1487 for (i = 0; i < tones.GetLength(); i++) {
1488 OnUserInputTone(tones[i], 0);
1493 #if OPAL_T120DATA
1495 OpalT120Protocol * OpalConnection::CreateT120ProtocolHandler()
1497 if (t120handler == NULL)
1498 t120handler = endpoint.CreateT120ProtocolHandler(*this);
1499 return t120handler;
1502 #endif
1504 #if OPAL_T38FAX
1506 OpalT38Protocol * OpalConnection::CreateT38ProtocolHandler()
1508 if (t38handler == NULL)
1509 t38handler = endpoint.CreateT38ProtocolHandler(*this);
1510 return t38handler;
1513 #endif
1515 #if OPAL_H224
1517 OpalH224Handler * OpalConnection::CreateH224ProtocolHandler(unsigned sessionID)
1519 if(h224Handler == NULL)
1520 h224Handler = endpoint.CreateH224ProtocolHandler(*this, sessionID);
1522 return h224Handler;
1525 OpalH281Handler * OpalConnection::CreateH281ProtocolHandler(OpalH224Handler & h224Handler)
1527 return endpoint.CreateH281ProtocolHandler(h224Handler);
1530 #endif
1532 void OpalConnection::SetLocalPartyName(const PString & name)
1534 localPartyName = name;
1538 void OpalConnection::SetAudioJitterDelay(unsigned minDelay, unsigned maxDelay)
1540 maxDelay = PMAX(10, PMIN(maxDelay, 999));
1541 minDelay = PMAX(10, PMIN(minDelay, 999));
1543 if (maxDelay < minDelay)
1544 maxDelay = minDelay;
1546 minAudioJitterDelay = minDelay;
1547 maxAudioJitterDelay = maxDelay;
1550 void OpalConnection::SetPhase(Phases phaseToSet)
1552 PTRACE(3, "OpalCon\tSetPhase from " << phase << " to " << phaseToSet);
1554 PWaitAndSignal m(phaseMutex);
1556 // With next few lines we will prevent phase to ever go down when it
1557 // reaches ReleasingPhase - end result - once you call Release you never
1558 // go back.
1559 if (phase < ReleasingPhase) {
1560 phase = phaseToSet;
1561 } else if (phase == ReleasingPhase && phaseToSet == ReleasedPhase) {
1562 phase = phaseToSet;
1566 BOOL OpalConnection::OnOpenIncomingMediaChannels()
1568 return TRUE;
1571 void OpalConnection::SetStringOptions(StringOptions * options)
1573 PWaitAndSignal m(phaseMutex);
1575 if (stringOptions != NULL)
1576 delete stringOptions;
1577 stringOptions = options;
1581 void OpalConnection::ApplyStringOptions()
1583 PWaitAndSignal m(phaseMutex);
1584 if (stringOptions != NULL) {
1585 if (stringOptions->Contains("Disable-Jitter"))
1586 maxAudioJitterDelay = minAudioJitterDelay = 0;
1587 PString str = (*stringOptions)("Max-Jitter");
1588 if (!str.IsEmpty())
1589 maxAudioJitterDelay = str.AsUnsigned();
1590 str = (*stringOptions)("Min-Jitter");
1591 if (!str.IsEmpty())
1592 minAudioJitterDelay = str.AsUnsigned();
1597 /////////////////////////////////////////////////////////////////////////////