1 /*
2 * rtpconn.cxx
3 *
4 * Connection abstraction
5 *
6 * Open Phone Abstraction Library (OPAL)
7 *
8 * Copyright (C) 2007 Post Increment
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Open Phone Abstraction Library.
21 *
22 * The Initial Developer of the Original Code is Post Increment
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 26728 $
27 * $Author: rjongbloed $
28 * $Date: 2011-12-01 22:59:14 -0600 (Thu, 01 Dec 2011) $
29 */
30
31 #include <ptlib.h>
32
33 #ifdef P_USE_PRAGMA
34 #pragma implementation "rtpconn.h"
35 #endif
36
37 #include <opal/buildopts.h>
38
39 #include <opal/rtpconn.h>
40 #include <opal/rtpep.h>
41 #include <opal/manager.h>
42 #include <codec/rfc2833.h>
43 #include <t38/t38proto.h>
44 #include <opal/patch.h>
45
46 #if OPAL_VIDEO
47 #include <codec/vidcodec.h>
48 #endif
49
50
51 #define new PNEW
52
53
54 #ifdef OPAL_ZRTP
55 extern OpalZRTPConnectionInfo * OpalLibZRTPConnInfo_Create();
56 #endif
57
58
OpalRTPConnection(OpalCall & call,OpalRTPEndPoint & ep,const PString & token,unsigned int options,StringOptions * stringOptions)59 OpalRTPConnection::OpalRTPConnection(OpalCall & call,
60 OpalRTPEndPoint & ep,
61 const PString & token,
62 unsigned int options,
63 StringOptions * stringOptions)
64 : OpalConnection(call, ep, token, options, stringOptions)
65 #ifdef _MSC_VER
66 #pragma warning(disable:4355)
67 #endif
68 , m_rtpSessions(*this)
69 #ifdef _MSC_VER
70 #pragma warning(default:4355)
71 #endif
72 , remoteIsNAT(false)
73 {
74 rfc2833Handler = new OpalRFC2833Proto(*this, PCREATE_NOTIFIER(OnUserInputInlineRFC2833), OpalRFC2833);
75 #if OPAL_T38_CAPABILITY
76 ciscoNSEHandler = new OpalRFC2833Proto(*this, PCREATE_NOTIFIER(OnUserInputInlineCiscoNSE), OpalCiscoNSE);
77 #endif
78
79 #ifdef OPAL_ZRTP
80 zrtpEnabled = ep.GetZRTPEnabled();
81 zrtpConnInfo = NULL;
82 #endif
83 }
84
~OpalRTPConnection()85 OpalRTPConnection::~OpalRTPConnection()
86 {
87 delete rfc2833Handler;
88 #if OPAL_T38_CAPABILITY
89 delete ciscoNSEHandler;
90 #endif
91 }
92
93
OnReleased()94 void OpalRTPConnection::OnReleased()
95 {
96 OpalConnection::OnReleased();
97 CloseSession(0);
98 }
99
100
GetNextSessionID(const OpalMediaType & mediaType,bool isSource)101 unsigned OpalRTPConnection::GetNextSessionID(const OpalMediaType & mediaType, bool isSource)
102 {
103 unsigned nextSessionId = m_rtpSessions.GetNextSessionID();
104
105 if (GetMediaStream(mediaType, isSource) != NULL)
106 return nextSessionId;
107
108 OpalMediaStreamPtr mediaStream = GetMediaStream(mediaType, !isSource);
109 if (mediaStream != NULL)
110 return mediaStream->GetSessionID();
111
112 unsigned defaultSessionId = mediaType.GetDefinition()->GetDefaultSessionId();
113 if (defaultSessionId >= nextSessionId ||
114 GetMediaStream(defaultSessionId, isSource) != NULL ||
115 GetMediaStream(defaultSessionId, !isSource) != NULL)
116 return nextSessionId;
117
118 return defaultSessionId;
119 }
120
121
GetSession(unsigned sessionID) const122 RTP_Session * OpalRTPConnection::GetSession(unsigned sessionID) const
123 {
124 return m_rtpSessions.GetSession(sessionID);
125 }
126
127
GetMediaSession(unsigned sessionID) const128 OpalMediaSession * OpalRTPConnection::GetMediaSession(unsigned sessionID) const
129 {
130 return m_rtpSessions.GetMediaSession(sessionID);
131 }
132
133
UseSession(const OpalTransport & transport,unsigned sessionID,const OpalMediaType & mediaType,RTP_QOS * rtpqos)134 RTP_Session * OpalRTPConnection::UseSession(const OpalTransport & transport, unsigned sessionID, const OpalMediaType & mediaType, RTP_QOS * rtpqos)
135 {
136 RTP_Session * rtpSession = m_rtpSessions.GetSession(sessionID);
137 if (rtpSession == NULL) {
138 rtpSession = CreateSession(transport, sessionID, mediaType, rtpqos);
139 m_rtpSessions.AddSession(rtpSession, mediaType);
140 }
141
142 return rtpSession;
143 }
144
145
CreateSession(const OpalTransport & transport,unsigned sessionID,const OpalMediaType & mediaType,RTP_QOS * rtpqos)146 RTP_Session * OpalRTPConnection::CreateSession(const OpalTransport & transport,
147 unsigned sessionID,
148 const OpalMediaType & mediaType,
149 RTP_QOS * rtpqos)
150 {
151 // We only support RTP over UDP at this point in time ...
152 if (!transport.IsCompatibleTransport("ip$127.0.0.1"))
153 return NULL;
154
155 // create an RTP session
156 RTP_UDP * rtpSession = CreateRTPSession(sessionID, mediaType, remoteIsNAT);
157 if (rtpSession == NULL)
158 return NULL;
159
160 PIPSocket::Address localAddress;
161 transport.GetLocalAddress(false).GetIpAddress(localAddress);
162
163 PIPSocket::Address remoteAddress;
164 transport.GetRemoteAddress().GetIpAddress(remoteAddress);
165
166 OpalManager & manager = GetEndPoint().GetManager();
167 PNatMethod * natMethod = manager.GetNatMethod(remoteAddress);
168
169 WORD firstPort = manager.GetRtpIpPortPair();
170 WORD nextPort = firstPort;
171 while (!rtpSession->Open(localAddress, nextPort, nextPort, manager.GetMediaTypeOfService(mediaType), natMethod, rtpqos)) {
172 nextPort = manager.GetRtpIpPortPair();
173 if (nextPort == firstPort) {
174 PTRACE(1, "RTPCon\tNo ports available for RTP session " << sessionID << ","
175 " base=" << manager.GetRtpIpPortBase() << ","
176 " max=" << manager.GetRtpIpPortMax() << ","
177 " bind=" << localAddress << ","
178 " for " << *this);
179 delete rtpSession;
180 return NULL;
181 }
182 }
183
184 localAddress = rtpSession->GetLocalAddress();
185 if (manager.TranslateIPAddress(localAddress, remoteAddress)){
186 rtpSession->SetLocalAddress(localAddress);
187 }
188
189 return rtpSession;
190 }
191
192
CreateRTPSession(unsigned sessionID,const OpalMediaType & mediaType,bool remoteIsNAT)193 RTP_UDP * OpalRTPConnection::CreateRTPSession(unsigned sessionID, const OpalMediaType & mediaType, bool remoteIsNAT)
194 {
195 OpalMediaTypeDefinition * def = mediaType.GetDefinition();
196 if (def == NULL) {
197 PTRACE(1, "RTPCon\tNo definition for media type " << mediaType);
198 return NULL;
199 }
200
201 #ifdef OPAL_ZRTP
202 // create ZRTP channel if enabled
203 {
204 PWaitAndSignal m(zrtpConnInfoMutex);
205 if (zrtpEnabled) {
206 if (zrtpConnInfo == NULL)
207 zrtpConnInfo = OpalLibZRTPConnInfo_Create();
208 if (zrtpConnInfo != NULL) {
209 RTP_UDP * rtpSession = zrtpConnInfo->CreateRTPSession(*this, sessionID, remoteIsNAT);
210 if (rtpSession != NULL)
211 return rtpSession;
212 delete zrtpConnInfo;
213 zrtpConnInfo = NULL;
214 }
215 }
216 }
217 #endif
218
219 return def->CreateRTPSession(*this, sessionID, remoteIsNAT);
220 }
221
222
ChangeSessionID(unsigned fromSessionID,unsigned toSessionID)223 bool OpalRTPConnection::ChangeSessionID(unsigned fromSessionID, unsigned toSessionID)
224 {
225 PTRACE(3, "RTPCon\tChanging session ID " << fromSessionID << " to " << toSessionID);
226 if (!m_rtpSessions.ChangeSessionID(fromSessionID, toSessionID))
227 return false;
228
229 for (OpalMediaStreamPtr stream(mediaStreams, PSafeReference); stream != NULL; ++stream) {
230 if (stream->GetSessionID() == fromSessionID) {
231 stream->SetSessionID(toSessionID);
232 OpalMediaPatch * patch = stream->GetPatch();
233 if (patch != NULL) {
234 patch->GetSource().SetSessionID(toSessionID);
235 OpalMediaStreamPtr otherStream;
236 for (PINDEX i = 0; (otherStream = patch->GetSink(i)) != NULL; ++i)
237 otherStream->SetSessionID(toSessionID);
238 }
239 }
240 }
241
242 return true;
243 }
244
245
CloseSession(unsigned sessionID)246 void OpalRTPConnection::CloseSession(unsigned sessionID)
247 {
248 #ifdef HAS_LIBZRTP
249 //check is security mode ZRTP
250 if (0 == securityMode.Find("ZRTP")) {
251 RTP_Session *session = GetSession(sessionID);
252 if (NULL != session){
253 OpalZrtp_UDP *zsession = (OpalZrtp_UDP*)session;
254 if (NULL != zsession->zrtpStream){
255 ::zrtp_stop_stream(zsession->zrtpStream);
256 zsession->zrtpStream = NULL;
257 }
258 }
259 }
260
261 printf("release session %i\n", sessionID);
262 #endif
263
264 m_rtpSessions.CloseSession(sessionID);
265 }
266
267
IsRTPNATEnabled(const PIPSocket::Address & localAddr,const PIPSocket::Address & peerAddr,const PIPSocket::Address & sigAddr,PBoolean incoming)268 PBoolean OpalRTPConnection::IsRTPNATEnabled(const PIPSocket::Address & localAddr,
269 const PIPSocket::Address & peerAddr,
270 const PIPSocket::Address & sigAddr,
271 PBoolean incoming)
272 {
273 return static_cast<OpalRTPEndPoint &>(endpoint).IsRTPNATEnabled(*this, localAddr, peerAddr, sigAddr, incoming);
274 }
275
276
OnMediaCommand(OpalMediaStream & stream,const OpalMediaCommand & command)277 bool OpalRTPConnection::OnMediaCommand(OpalMediaStream & stream, const OpalMediaCommand & command)
278 {
279 bool done = OpalConnection::OnMediaCommand(stream, command);
280
281 #if OPAL_VIDEO
282
283 unsigned sessionID = stream.GetSessionID();
284 RTP_Session * session = m_rtpSessions.GetSession(sessionID);
285 if (session != NULL) {
286 PCaselessString rtcp_fb;
287 OpalMediaStreamPtr videoStream = GetMediaStream(sessionID, true);
288 if (videoStream != NULL)
289 rtcp_fb = videoStream->GetMediaFormat().GetOptionString("RTCP-FB");
290
291 if (PIsDescendant(&command, OpalVideoUpdatePicture)) {
292 bool no_AVPF_PLI = rtcp_fb.Find("pli") == P_MAX_INDEX;
293 bool no_AVPF_FIR = rtcp_fb.Find("fir") == P_MAX_INDEX;
294
295 if (no_AVPF_PLI && no_AVPF_FIR)
296 session->SendIntraFrameRequest(true, false); // Fall back to RFC2032
297 else if (no_AVPF_PLI)
298 session->SendIntraFrameRequest(false, false); // Unusual, but possible, use RFC5104 FIR
299 else if (no_AVPF_FIR)
300 session->SendIntraFrameRequest(false, true); // More common, use RFC4585 PLI
301 else
302 session->SendIntraFrameRequest(false, PIsDescendant(&command, OpalVideoPictureLoss));
303
304 #if OPAL_STATISTICS
305 m_VideoUpdateRequestsSent++;
306 #endif
307
308 done = true;
309 }
310 else if (PIsDescendant(&command, OpalTemporalSpatialTradeOff) && rtcp_fb.Find("tstr") != P_MAX_INDEX) {
311 session->SendTemporalSpatialTradeOff(dynamic_cast<const OpalTemporalSpatialTradeOff &>(command).GetTradeOff());
312 done = true;
313 }
314 }
315 #endif // OPAL_VIDEO
316
317 return done;
318 }
319
320
AttachRFC2833HandlerToPatch(PBoolean isSource,OpalMediaPatch & patch)321 void OpalRTPConnection::AttachRFC2833HandlerToPatch(PBoolean isSource, OpalMediaPatch & patch)
322 {
323 if (isSource) {
324 OpalRTPMediaStream * mediaStream = dynamic_cast<OpalRTPMediaStream *>(&patch.GetSource());
325 if (mediaStream != NULL) {
326 RTP_Session & rtpSession = mediaStream->GetRtpSession();
327 if (rfc2833Handler != NULL) {
328 PTRACE(3, "RTPCon\tAdding RFC2833 receive handler");
329 rtpSession.AddFilter(rfc2833Handler->GetReceiveHandler());
330 }
331 #if OPAL_T38_CAPABILITY
332 if (ciscoNSEHandler != NULL) {
333 PTRACE(3, "RTPCon\tAdding Cisco NSE receive handler");
334 rtpSession.AddFilter(ciscoNSEHandler->GetReceiveHandler());
335 }
336 #endif
337 }
338 }
339 }
340
341
SendUserInputTone(char tone,unsigned duration)342 PBoolean OpalRTPConnection::SendUserInputTone(char tone, unsigned duration)
343 {
344 if (GetRealSendUserInputMode() == SendUserInputAsRFC2833) {
345 if (
346 #if OPAL_T38_CAPABILITY
347 ciscoNSEHandler->SendToneAsync(tone, duration) ||
348 #endif
349 rfc2833Handler->SendToneAsync(tone, duration))
350 return true;
351
352 PTRACE(2, "RTPCon\tCould not send tone '" << tone << "' via RFC2833.");
353 }
354
355 return OpalConnection::SendUserInputTone(tone, duration);
356 }
357
358
GetMediaInformation(unsigned sessionID,MediaInformation & info) const359 PBoolean OpalRTPConnection::GetMediaInformation(unsigned sessionID,
360 MediaInformation & info) const
361 {
362 if (!mediaTransportAddresses.Contains(sessionID)) {
363 PTRACE(2, "RTPCon\tGetMediaInformation for session " << sessionID << " - no channel.");
364 return PFalse;
365 }
366
367 OpalTransportAddress & address = mediaTransportAddresses[sessionID];
368
369 PIPSocket::Address ip;
370 WORD port;
371 if (address.GetIpAndPort(ip, port)) {
372 info.data = OpalTransportAddress(ip, (WORD)(port&0xfffe));
373 info.control = OpalTransportAddress(ip, (WORD)(port|0x0001));
374 }
375 else
376 info.data = info.control = address;
377
378 info.rfc2833 = rfc2833Handler->GetRxMediaFormat().GetPayloadType();
379 PTRACE(3, "RTPCon\tGetMediaInformation for session " << sessionID
380 << " data=" << info.data << " rfc2833=" << info.rfc2833);
381 return PTrue;
382 }
383
IsMediaBypassPossible(unsigned) const384 PBoolean OpalRTPConnection::IsMediaBypassPossible(unsigned) const
385 {
386 return true;
387 }
388
CreateMediaStream(const OpalMediaFormat & mediaFormat,unsigned sessionID,PBoolean isSource)389 OpalMediaStream * OpalRTPConnection::CreateMediaStream(const OpalMediaFormat & mediaFormat, unsigned sessionID, PBoolean isSource)
390 {
391 if (ownerCall.IsMediaBypassPossible(*this, sessionID))
392 return new OpalNullMediaStream(*this, mediaFormat, sessionID, isSource);
393
394 for (OpalMediaStreamPtr mediaStream(mediaStreams, PSafeReference); mediaStream != NULL; ++mediaStream) {
395 if (mediaStream->GetSessionID() == sessionID && mediaStream->IsSource() == isSource && !mediaStream->IsOpen())
396 return mediaStream;
397 }
398
399 if (mediaFormat.GetMediaType().GetDefinition()->UsesRTP()) {
400 if (UseSession(GetTransport(), sessionID, mediaFormat.GetMediaType(), NULL) == NULL) {
401 PTRACE(1, "RTPCon\tCreateMediaStream could not find/create session " << sessionID);
402 return NULL;
403 }
404 }
405
406 OpalMediaSession * mediaSession = GetMediaSession(sessionID);
407 if (mediaSession == NULL) {
408 PTRACE(1, "RTPCon\tUnable to create media stream for session " << sessionID);
409 return NULL;
410 }
411
412 return PAssertNULL(mediaSession)->CreateMediaStream(mediaFormat, sessionID, isSource);
413 }
414
415
AdjustMediaFormats(bool local,const OpalConnection * otherConnection,OpalMediaFormatList & mediaFormats) const416 void OpalRTPConnection::AdjustMediaFormats(bool local,
417 const OpalConnection * otherConnection,
418 OpalMediaFormatList & mediaFormats) const
419 {
420 if (otherConnection == NULL && local) {
421 OpalMediaFormatList::iterator fmt = mediaFormats.begin();
422 while (fmt != mediaFormats.end()) {
423 if (fmt->IsTransportable())
424 ++fmt;
425 else
426 mediaFormats -= *fmt++;
427 }
428 }
429
430 OpalConnection::AdjustMediaFormats(local, otherConnection, mediaFormats);
431 }
432
433
OnPatchMediaStream(PBoolean isSource,OpalMediaPatch & patch)434 void OpalRTPConnection::OnPatchMediaStream(PBoolean isSource, OpalMediaPatch & patch)
435 {
436 OpalConnection::OnPatchMediaStream(isSource, patch);
437
438 if (patch.GetSource().GetMediaFormat().GetMediaType() == OpalMediaType::Audio())
439 AttachRFC2833HandlerToPatch(isSource, patch);
440 }
441
OnUserInputInlineRFC2833(OpalRFC2833Info & info,INT type)442 void OpalRTPConnection::OnUserInputInlineRFC2833(OpalRFC2833Info & info, INT type)
443 {
444 // trigger on start of tone only
445 if (type == 0)
446 OnUserInputTone(info.GetTone(), info.GetDuration() > 0 ? info.GetDuration()/8 : 100);
447 }
448
OnUserInputInlineCiscoNSE(OpalRFC2833Info & info,INT type)449 void OpalRTPConnection::OnUserInputInlineCiscoNSE(OpalRFC2833Info & info, INT type)
450 {
451 // trigger on start of tone only
452 if (type == 0)
453 OnUserInputTone(info.GetTone(), info.GetDuration() > 0 ? info.GetDuration()/8 : 100);
454 }
455
SessionFailing(RTP_Session & session)456 void OpalRTPConnection::SessionFailing(RTP_Session & session)
457 {
458 // set this session as failed
459 session.SetFailed(true);
460
461 // check to see if all RTP session have failed
462 // if so, clear the call
463 if (m_rtpSessions.AllSessionsFailing()) {
464 PTRACE(2, "RTPCon\tClearing call as all RTP session are failing");
465 Release();
466 }
467 }
468
469 /////////////////////////////////////////////////////////////////////////////
470
OpalMediaSession(OpalConnection & _conn,const OpalMediaType & _mediaType,unsigned _sessionId)471 OpalMediaSession::OpalMediaSession(OpalConnection & _conn, const OpalMediaType & _mediaType, unsigned _sessionId)
472 : connection(_conn)
473 , mediaType(_mediaType)
474 , sessionId(_sessionId)
475 {
476 }
477
OpalMediaSession(const OpalMediaSession & _obj)478 OpalMediaSession::OpalMediaSession(const OpalMediaSession & _obj)
479 : PObject(_obj)
480 , connection(_obj.connection)
481 , mediaType(_obj.mediaType)
482 , sessionId(_obj.sessionId)
483 {
484 }
485
486 /////////////////////////////////////////////////////////////////////////////
487
OpalRTPMediaSession(OpalConnection & conn,const OpalMediaType & mediaType,unsigned sessionId)488 OpalRTPMediaSession::OpalRTPMediaSession(OpalConnection & conn,
489 const OpalMediaType & mediaType,
490 unsigned sessionId)
491 : OpalMediaSession(conn, mediaType, sessionId)
492 , rtpSession(NULL)
493 {
494 }
495
496
OpalRTPMediaSession(const OpalRTPMediaSession & obj)497 OpalRTPMediaSession::OpalRTPMediaSession(const OpalRTPMediaSession & obj)
498 : OpalMediaSession(obj)
499 , rtpSession(NULL)
500 {
501 }
502
503
~OpalRTPMediaSession()504 OpalRTPMediaSession::~OpalRTPMediaSession()
505 {
506 if (rtpSession != NULL) {
507 PTRACE(4, "RTP\tDeleting session " << rtpSession->GetSessionID());
508 ((OpalRTPEndPoint &)connection.GetEndPoint()).SetConnectionByRtpLocalPort(rtpSession, NULL);
509 delete rtpSession;
510 }
511 }
512
513
Attach(RTP_Session * rtp)514 void OpalRTPMediaSession::Attach(RTP_Session * rtp)
515 {
516 if (PAssert(rtpSession == NULL, "Cannot attach with already existing session")) {
517 rtpSession = rtp;
518 ((OpalRTPEndPoint &)connection.GetEndPoint()).SetConnectionByRtpLocalPort(rtpSession, &connection);
519 }
520 }
521
522
Close()523 void OpalRTPMediaSession::Close()
524 {
525 if (rtpSession != NULL) {
526 PTRACE(3, "RTP\tClosing session " << rtpSession->GetSessionID());
527 ((OpalRTPEndPoint &)connection.GetEndPoint()).SetConnectionByRtpLocalPort(rtpSession, NULL);
528 if (rtpSession->GetPacketsReceived() > 0 || rtpSession->GetPacketsSent() > 0)
529 rtpSession->SendBYE();
530 rtpSession->Close(PTrue);
531 rtpSession->SetJitterBufferSize(0, 0);
532 }
533 }
534
GetLocalMediaAddress() const535 OpalTransportAddress OpalRTPMediaSession::GetLocalMediaAddress() const
536 {
537 PIPSocket::Address addr = ((RTP_UDP *)rtpSession)->GetLocalAddress();
538 WORD port = ((RTP_UDP *)rtpSession)->GetLocalDataPort();
539 return OpalTransportAddress(addr, port, "udp$");
540 }
541
542 #if OPAL_SIP
543
CreateSDPMediaDescription(const OpalTransportAddress & sdpContactAddress)544 SDPMediaDescription * OpalRTPMediaSession::CreateSDPMediaDescription(const OpalTransportAddress & sdpContactAddress)
545 {
546 return mediaType.GetDefinition()->CreateSDPMediaDescription(sdpContactAddress);
547 }
548
549 #endif
550
CreateMediaStream(const OpalMediaFormat & mediaFormat,unsigned,PBoolean isSource)551 OpalMediaStream * OpalRTPMediaSession::CreateMediaStream(const OpalMediaFormat & mediaFormat,
552 unsigned /*sessionID*/,
553 PBoolean isSource)
554 {
555 mediaType = mediaFormat.GetMediaType();
556 return new OpalRTPMediaStream((OpalRTPConnection &)connection, mediaFormat, isSource, *rtpSession,
557 connection.GetMinAudioJitterDelay(),
558 connection.GetMaxAudioJitterDelay());
559 }
560
561
562 /////////////////////////////////////////////////////////////////////////////
563
OpalRTPSessionManager(OpalRTPConnection & connection)564 OpalRTPSessionManager::OpalRTPSessionManager(OpalRTPConnection & connection)
565 : m_connection(connection)
566 {
567 }
568
569
OpalRTPSessionManager(const OpalRTPSessionManager & other)570 OpalRTPSessionManager::OpalRTPSessionManager(const OpalRTPSessionManager & other)
571 : PObject(other)
572 , m_connection(other.m_connection)
573 , sessions(other.sessions)
574 {
575 }
576
577
~OpalRTPSessionManager()578 OpalRTPSessionManager::~OpalRTPSessionManager()
579 {
580 }
581
582
GetNextSessionID()583 unsigned OpalRTPSessionManager::GetNextSessionID()
584 {
585 unsigned maxSessionID = 0;
586
587 for (PINDEX i = 0; i < sessions.GetSize(); ++i) {
588 unsigned sessionID = sessions.GetDataAt(i).sessionId;
589 if (maxSessionID < sessionID)
590 maxSessionID = sessionID;
591 }
592
593 return maxSessionID+1;
594 }
595
596
AddSession(RTP_Session * rtpSession,const OpalMediaType & mediaType)597 void OpalRTPSessionManager::AddSession(RTP_Session * rtpSession, const OpalMediaType & mediaType)
598 {
599 if (rtpSession == NULL)
600 return;
601
602 PWaitAndSignal m(m_mutex);
603
604 unsigned sessionID = rtpSession->GetSessionID();
605 OpalMediaSession * session = sessions.GetAt(sessionID);
606 if (session == NULL) {
607 session = new OpalRTPMediaSession(m_connection, mediaType, sessionID);
608 sessions.Insert(POrdinalKey(sessionID), session);
609 PTRACE(3, "RTP\tCreating new session " << *rtpSession);
610 }
611
612 OpalRTPMediaSession * s = dynamic_cast<OpalRTPMediaSession *>(session);
613 if (PAssert(s != NULL, "RTP session type does not match"))
614 s->Attach(rtpSession);
615 }
616
617
AddMediaSession(OpalMediaSession * mediaSession,const OpalMediaType &)618 void OpalRTPSessionManager::AddMediaSession(OpalMediaSession * mediaSession, const OpalMediaType & /*mediaType*/)
619 {
620 PWaitAndSignal m(m_mutex);
621
622 PAssert(sessions.GetAt(mediaSession->sessionId) == NULL, "Cannot add already existing session");
623 sessions.Insert(POrdinalKey(mediaSession->sessionId), mediaSession);
624 }
625
626
CloseSession(unsigned sessionID)627 void OpalRTPSessionManager::CloseSession(unsigned sessionID)
628 {
629 PWaitAndSignal mutex(m_mutex);
630 if (sessionID == 0) {
631 for (PINDEX i = 0; i < sessions.GetSize(); ++i) {
632 PTRACE(3, "RTP\tClosing session " << sessions.GetKeyAt(i));
633 sessions.GetDataAt(i).Close();
634 }
635 }
636 else {
637 PTRACE(3, "RTP\tClosing session " << sessionID);
638 sessions[sessionID].Close();
639 }
640 }
641
642
GetMediaSession(unsigned sessionID) const643 OpalMediaSession * OpalRTPSessionManager::GetMediaSession(unsigned sessionID) const
644 {
645 PWaitAndSignal wait(m_mutex);
646
647 OpalMediaSession * session;
648 if (((session = sessions.GetAt(sessionID)) == NULL) || !session->IsActive()) {
649 PTRACE(3, "RTP\tCannot find media session " << sessionID);
650 return NULL;
651 }
652
653 PTRACE(3, "RTP\tFound existing media session " << sessionID);
654 return session;
655 }
656
657
GetSession(unsigned sessionID) const658 RTP_Session * OpalRTPSessionManager::GetSession(unsigned sessionID) const
659 {
660 PWaitAndSignal wait(m_mutex);
661
662 OpalMediaSession * session;
663 if ( ((session = sessions.GetAt(sessionID)) == NULL) ||
664 !session->IsActive() ||
665 !session->IsRTP()
666 ) {
667 PTRACE(3, "RTP\tCannot find RTP session " << sessionID);
668 return NULL;
669 }
670
671 PTRACE(3, "RTP\tFound existing RTP session " << sessionID);
672 return ((OpalRTPMediaSession *)session)->GetSession();
673 }
674
675
ChangeSessionID(unsigned fromSessionID,unsigned toSessionID)676 bool OpalRTPSessionManager::ChangeSessionID(unsigned fromSessionID, unsigned toSessionID)
677 {
678 PWaitAndSignal wait(m_mutex);
679
680 if (sessions.Contains(toSessionID)) {
681 PTRACE(2, "RTP\tAttempt to renumber session " << fromSessionID << " to existing sesion ID " << toSessionID);
682 return false;
683 }
684
685 sessions.DisallowDeleteObjects();
686 OpalMediaSession * session = sessions.RemoveAt(fromSessionID);
687 sessions.AllowDeleteObjects();
688
689 if (session == NULL)
690 return false;
691
692 OpalRTPMediaSession * rtpSession = dynamic_cast<OpalRTPMediaSession *>(session);
693 if (rtpSession != NULL)
694 rtpSession->GetSession()->SetSessionID(toSessionID);
695
696 session->sessionId = toSessionID;
697 return sessions.SetAt(POrdinalKey(toSessionID), session);
698 }
699
700
AllSessionsFailing()701 bool OpalRTPSessionManager::AllSessionsFailing()
702 {
703 PWaitAndSignal wait(m_mutex);
704
705 for (PINDEX i = 0; i < sessions.GetSize(); ++i) {
706 OpalMediaSession & session = sessions.GetDataAt(i);
707 if (session.IsActive() && !session.HasFailed())
708 return false;
709 }
710
711 return true;
712 }
713
714 /////////////////////////////////////////////////////////////////////////////
715
716