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
21 * The Original Code is Open Phone Abstraction Library.
23 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
25 * Contributor(s): ______________________________________.
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
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
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
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
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)
419 #pragma implementation "connection.h"
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>
435 #include <t120/t120proto.h>
436 #include <t38/t38proto.h>
437 #include <h224/h224handler.h>
440 #include <t38/t38proto.h>
447 ostream
& operator<<(ostream
& out
, OpalConnection::Phases phase
)
449 static const char * const names
[OpalConnection::NumPhases
] = {
450 "UninitialisedPhase",
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
] = {
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
<< '>';
517 o
<< AnswerCallResponseNames
[s
];
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
<< '>';
537 o
<< SendUserInputModeNames
[m
];
543 /////////////////////////////////////////////////////////////////////////////
545 OpalConnection::OpalConnection(OpalCall
& call
,
547 const PString
& token
,
548 unsigned int options
,
549 OpalConnection::StringOptions
* _stringOptions
)
552 phase(UninitialisedPhase
),
558 localPartyName(ep
.GetDefaultLocalPartyName()),
559 displayName(ep
.GetDefaultDisplayName()),
560 remotePartyName(token
),
561 callEndReason(NumCallEndReasons
),
564 silenceDetector(NULL
),
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
;
597 sendUserInputMode
= SendUserInputAsTone
;
599 case SendDTMFAsRFC2833
:
600 sendUserInputMode
= SendUserInputAsInlineRFC2833
;
602 case SendDTMFAsDefault
:
604 sendUserInputMode
= ep
.GetSendUserInputMode();
608 rfc2833Handler
= new OpalRFC2833Proto(PCREATE_NOTIFIER(OnUserInputInlineRFC2833
));
610 ciscoNSEHandler
= new OpalRFC2833Proto(PCREATE_NOTIFIER(OnUserInputInlineCiscoNSE
));
613 securityMode
= ep
.GetDefaultSecurityMode();
615 switch (options
& RTPAggregationMask
) {
616 case RTPAggregationDisable
:
617 useRTPAggregation
= FALSE
;
619 case RTPAggregationEnable
:
620 useRTPAggregation
= TRUE
;
623 useRTPAggregation
= endpoint
.UseRTPAggregation();
626 if (stringOptions
!= NULL
) {
627 PString
id((*stringOptions
)("Call-Identifier"));
629 callIdentifier
= PGloballyUniqueID(id
);
633 OpalConnection::~OpalConnection()
636 PWaitAndSignal
mutex(mediaStreamMutex
);
637 mediaStreams
.RemoveAll();
640 delete silenceDetector
;
642 delete rfc2833Handler
;
647 delete ciscoNSEHandler
;
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()
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);
735 SetPhase(ReleasingPhase
);
739 PSafeLockReadWrite
safeLock(*this);
740 if (!safeLock
.IsLocked()) {
741 PTRACE(3, "OpalCon\tAlready released " << *this);
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
754 PThread::Create(PCREATE_NOTIFIER(OnReleaseThreadMain
), 0,
755 PThread::AutoDeleteThread
,
756 PThread::NormalPriority
,
761 void OpalConnection::OnReleaseThreadMain(PThread
&, INT
)
765 PTRACE(3, "OpalCon\tOnRelease thread completed for " << GetToken());
767 // Dereference on the way out of the thread
772 void OpalConnection::OnReleased()
774 PTRACE(3, "OpalCon\tOnReleased " << *this);
778 endpoint
.OnReleased(*this);
782 BOOL
OpalConnection::OnIncomingConnection()
788 BOOL
OpalConnection::OnIncomingConnection(unsigned int /*options*/)
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()
808 BOOL
OpalConnection::ForwardCall(const PString
& /*forwardParty*/)
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);
859 PTRACE(3, "OpalCon\tOpenSourceMediaStream for session " << sessionID
<< " on " << *this);
861 OpalMediaFormat sourceFormat
, destinationFormat
;
862 if (!OpalTranscoder::SelectFormats(sessionID
,
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(' '));
874 PTRACE(3, "OpalCon\tSelected media stream " << sourceFormat
<< " -> " << destinationFormat
);
877 stream
= CreateMediaStream(sourceFormat
, sessionID
, TRUE
);
879 if (stream
== NULL
) {
880 PTRACE(1, "OpalCon\tCreateMediaStream returned NULL for session "
881 << sessionID
<< " on " << *this);
885 if (stream
->Open()) {
886 if (OnOpenMediaStream(*stream
)) {
887 PTRACE(3, "OpalCon\tOpened source stream " << stream
->GetID());
890 PTRACE(2, "OpalCon\tSource media OnOpenMediaStream open of " << sourceFormat
<< " failed.");
893 PTRACE(2, "OpalCon\tSource media stream open of " << sourceFormat
<< " failed.");
896 if (!RemoveMediaStream(stream
))
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
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(' '));
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");
945 if (stream
->Open()) {
946 if (OnOpenMediaStream(*stream
)) {
947 PTRACE(3, "OpalCon\tOpened sink stream " << stream
->GetID());
950 PTRACE(2, "OpalCon\tSink media stream OnOpenMediaStream of " << destinationFormat
<< " failed.");
953 PTRACE(2, "OpalCon\tSink media stream open of " << destinationFormat
<< " failed.");
956 if (!RemoveMediaStream(stream
))
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
];
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
];
983 OnClosedMediaStream(strm
);
988 PTRACE(2, "OpalCon\tMedia stream threads closed.");
992 void OpalConnection::RemoveMediaStreams()
994 PWaitAndSignal
mutex(mediaStreamMutex
);
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(
1011 const OpalMediaFormat
& mediaFormat
,
1015 const OpalMediaFormat
& ,
1022 if (sessionID
== OpalMediaFormat::DefaultVideoSessionID
) {
1024 PVideoInputDevice
* videoDevice
;
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
);
1034 PVideoOutputDevice
* videoDevice
;
1036 if (CreateVideoOutputDevice(mediaFormat
, FALSE
, videoDevice
, autoDelete
))
1037 return new OpalVideoMediaStream(*this, mediaFormat
, sessionID
, NULL
, videoDevice
, autoDelete
);
1046 BOOL
OpalConnection::OnOpenMediaStream(OpalMediaStream
& stream
)
1048 if (!endpoint
.OnOpenMediaStream(*this, stream
))
1051 if (!LockReadWrite())
1055 PWaitAndSignal
m(mediaStreamMutex
);
1056 if (mediaStreams
.GetObjectsIndex(&stream
) == P_MAX_INDEX
)
1057 mediaStreams
.Append(&stream
);
1060 if (GetPhase() == ConnectedPhase
) {
1061 SetPhase(EstablishedPhase
);
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
) {
1087 PTRACE(3, "OpalCon\tAdding RFC2833 receive handler");
1088 OpalMediaStream
& mediaStream
= patch
.GetSource();
1089 patch
.AddFilter(rfc2833Handler
->GetReceiveHandler(), mediaStream
.GetMediaFormat());
1091 PTRACE(3, "OpalCon\tAdding RFC2833 transmit handler");
1092 patch
.AddFilter(rfc2833Handler
->GetTransmitHandler(), patch
.GetSinkFormat());
1097 if (ciscoNSEHandler
!= NULL
) {
1099 PTRACE(3, "OpalCon\tAdding Cisco NSE receive handler");
1100 OpalMediaStream
& mediaStream
= patch
.GetSource();
1101 patch
.AddFilter(ciscoNSEHandler
->GetReceiveHandler(), mediaStream
.GetMediaFormat());
1103 PTRACE(3, "OpalCon\tAdding Cisco NSE transmit handler");
1104 patch
.AddFilter(ciscoNSEHandler
->GetTransmitHandler(), patch
.GetSinkFormat());
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
];
1123 BOOL
OpalConnection::RemoveMediaStream(OpalMediaStream
* strm
)
1125 PWaitAndSignal
mutex(mediaStreamMutex
);
1126 PINDEX index
= mediaStreams
.GetObjectsIndex(strm
);
1127 if (index
== P_MAX_INDEX
)
1130 OpalMediaStream
& s
= mediaStreams
[index
];
1132 OnClosedMediaStream(s
);
1135 mediaStreams
.RemoveAt(index
);
1142 BOOL
OpalConnection::IsMediaBypassPossible(unsigned /*sessionID*/) const
1144 PTRACE(3, "OpalCon\tIsMediaBypassPossible: default returns 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.");
1157 OpalTransportAddress
& address
= mediaTransportAddresses
[sessionID
];
1159 PIPSocket::Address ip
;
1161 if (address
.GetIpAndPort(ip
, port
)) {
1162 info
.data
= OpalTransportAddress(ip
, (WORD
)(port
&0xfffe));
1163 info
.control
= OpalTransportAddress(ip
, (WORD
)(port
|0x0001));
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
);
1176 void OpalConnection::AddVideoMediaFormats(OpalMediaFormatList
& mediaFormats
) const
1178 endpoint
.AddVideoMediaFormats(mediaFormats
, this);
1182 BOOL
OpalConnection::CreateVideoInputDevice(const OpalMediaFormat
& mediaFormat
,
1183 PVideoInputDevice
* & device
,
1186 return endpoint
.CreateVideoInputDevice(*this, mediaFormat
, device
, autoDelete
);
1190 BOOL
OpalConnection::CreateVideoOutputDevice(const OpalMediaFormat
& mediaFormat
,
1192 PVideoOutputDevice
* & device
,
1195 return endpoint
.CreateVideoOutputDevice(*this, mediaFormat
, preview
, device
, autoDelete
);
1198 #endif // OPAL_VIDEO
1201 BOOL
OpalConnection::SetAudioVolume(BOOL
/*source*/, unsigned /*percentage*/)
1207 unsigned OpalConnection::GetAudioSignalLevel(BOOL
/*source*/)
1213 RTP_Session
* OpalConnection::GetSession(unsigned sessionID
) const
1215 return rtpSessions
.GetSession(sessionID
);
1219 RTP_Session
* OpalConnection::UseSession(const OpalTransport
& transport
,
1223 RTP_Session
* rtpSession
= rtpSessions
.UseSession(sessionID
);
1224 if (rtpSession
== NULL
) {
1225 rtpSession
= CreateSession(transport
, sessionID
, rtpqos
);
1226 rtpSessions
.AddSession(rtpSession
);
1233 void OpalConnection::ReleaseSession(unsigned sessionID
,
1236 rtpSessions
.ReleaseSession(sessionID
, clearAll
);
1240 RTP_Session
* OpalConnection::CreateSession(const OpalTransport
& transport
,
1244 // We only support RTP over UDP at this point in time ...
1245 if (!transport
.IsCompatibleTransport("ip$127.0.0.1"))
1248 // We support video, audio and T38 over IP
1249 if (sessionID
!= OpalMediaFormat::DefaultAudioSessionID
&&
1250 sessionID
!= OpalMediaFormat::DefaultVideoSessionID
1252 && sessionID
!= OpalMediaFormat::DefaultDataSessionID
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
;
1270 if (sessionID
== OpalMediaFormat::DefaultDataSessionID
) {
1271 rtpSession
= new T38PseudoRTP(NULL
, sessionID
, remoteIsNAT
);
1276 if (!securityMode
.IsEmpty()) {
1277 OpalSecurityMode
* parms
= PFactory
<OpalSecurityMode
>::CreateInstance(securityMode
);
1278 if (parms
== NULL
) {
1279 PTRACE(1, "OpalCon\tSecurity mode " << securityMode
<< " unknown");
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
);
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
,
1302 manager
.GetRtpIpTypeofService(),
1305 nextPort
= manager
.GetRtpIpPortPair();
1306 if (nextPort
== firstPort
) {
1312 localAddress
= rtpSession
->GetLocalAddress();
1313 if (manager
.TranslateIPAddress(localAddress
, remoteAddress
))
1314 rtpSession
->SetLocalAddress(localAddress
);
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
) {
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());
1342 bandwidthAvailable
= newBandwidth
- used
;
1347 unsigned OpalConnection::GetBandwidthUsed() const
1352 for (PINDEX i
= 0; i
< logicalChannels
->GetSize(); i
++) {
1353 OpalChannel
* channel
= logicalChannels
->GetChannelAt(i
);
1354 if (channel
!= NULL
)
1355 used
+= channel
->GetBandwidthUsed();
1359 PTRACE(3, "OpalCon\tBandwidth used is "
1360 << used
<< "00b/s for " << *this);
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
1380 if (requiredBandwidth
> bandwidthAvailable
) {
1381 PTRACE(2, "OpalCon\tAvailable bandwidth exceeded on " << *this);
1385 bandwidthAvailable
-= requiredBandwidth
;
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))
1406 BOOL
OpalConnection::SendUserInputTone(char tone
, unsigned duration
)
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
)
1430 if (userInputAvailable
.Wait(PTimeInterval(0, timeout
))) {
1431 userInputMutex
.Wait();
1432 reply
= userInputString
;
1433 userInputString
= PString();
1434 userInputMutex
.Signal();
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*/)
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
);
1487 for (i
= 0; i
< tones
.GetLength(); i
++) {
1488 OnUserInputTone(tones
[i
], 0);
1495 OpalT120Protocol
* OpalConnection::CreateT120ProtocolHandler()
1497 if (t120handler
== NULL
)
1498 t120handler
= endpoint
.CreateT120ProtocolHandler(*this);
1506 OpalT38Protocol
* OpalConnection::CreateT38ProtocolHandler()
1508 if (t38handler
== NULL
)
1509 t38handler
= endpoint
.CreateT38ProtocolHandler(*this);
1517 OpalH224Handler
* OpalConnection::CreateH224ProtocolHandler(unsigned sessionID
)
1519 if(h224Handler
== NULL
)
1520 h224Handler
= endpoint
.CreateH224ProtocolHandler(*this, sessionID
);
1525 OpalH281Handler
* OpalConnection::CreateH281ProtocolHandler(OpalH224Handler
& h224Handler
)
1527 return endpoint
.CreateH281ProtocolHandler(h224Handler
);
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
1559 if (phase
< ReleasingPhase
) {
1561 } else if (phase
== ReleasingPhase
&& phaseToSet
== ReleasedPhase
) {
1566 BOOL
OpalConnection::OnOpenIncomingMediaChannels()
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");
1589 maxAudioJitterDelay
= str
.AsUnsigned();
1590 str
= (*stringOptions
)("Min-Jitter");
1592 minAudioJitterDelay
= str
.AsUnsigned();
1597 /////////////////////////////////////////////////////////////////////////////