[asterisk-scf-commits] asterisk-scf/release/sip.git branch "master" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Mon Oct 3 18:04:24 CDT 2011
branch "master" has been updated
via d1c51b7c05833b65bffdc3599253dd6690580d34 (commit)
from bf97df459f0c054d095331534252ec3755abc1e2 (commit)
Summary of changes:
config/Sip.config | 24 +
config/SipConfigurator.py | 51 +-
.../SipSessionManager/SipConfigurationIf.ice | 26 +
.../SipSessionManager/SipStateReplicationIf.ice | 3 +
src/NATOptions.h | 6 +-
src/PJSipSessionModule.cpp | 9 +-
src/SipConfiguration.cpp | 12 +
src/SipEndpoint.cpp | 102 ++-
src/SipEndpoint.h | 22 +-
src/SipSession.cpp | 863 ++++++++++++++------
src/SipSession.h | 14 +-
src/SipStateReplicatorListener.cpp | 3 +-
12 files changed, 830 insertions(+), 305 deletions(-)
- Log -----------------------------------------------------------------
commit d1c51b7c05833b65bffdc3599253dd6690580d34
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Oct 3 20:04:29 2011 -0300
Add T.38 UDPTL support.
diff --git a/config/Sip.config b/config/Sip.config
index 7946dba..e72b415 100644
--- a/config/Sip.config
+++ b/config/Sip.config
@@ -89,8 +89,32 @@ direction=both
securetransport=none
# Whether to use IPv6 for media transport or not
rtpoveripv6=no
+# Whether to use IPv6 for UDPTL transport or not
+udptloveripv6=no
+
+#
+# Configure endpoint to create ICE enabled UDPTL streams. Disabled by default.
+#
+# udptloverice=false
+
+#
+# Configure endpoint to enable TURN support for ICE enabled UDPTL streams. ICE must be enabled
+# for this to have an effect. Disable by default.
+#
+# udptlwithturn=false
+
# Allowable media formats for the endpoint. Each format is separated using , and follows the format
# <name>/<sample rate>@<frame size>;<format specific parameters>
+#
+# If you would like to enable T.38 you can specify t38udptl here. This will enable T.38 with no overridden
+# datagram and no error correction scheme. To override the datagram add maxdatagram with a value in the format
+# specific parameters section. To enable error correction add errorcorrect with either fec, redundancy, or none
+# as the value.
+#
+# Example of T.38 with an overridden max datagram of 400: t38udptl;maxdatagram=400
+# Example of T.38 with fec error correction: t38udptl;errorcorrect=fec
+# Example of T.38 with overridden max datagram and fec error correction: t38udptl;maxdatagram=400&errorcorrect=fec
+#
formats=ulaw/8000,alaw/8000
# Whether media should be allowed to flow directly between endpoints or not
diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 5505f2a..f6c09b7 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -206,6 +206,11 @@ class SipSectionVisitors(Configurator.SectionVisitors):
item = AsteriskSCF.Configuration.SipSessionManager.V1.DirectMediaItem()
mapper.map('directmedia', item, 'enabled', 'directmedia', config.getboolean, None)
+ item = AsteriskSCF.Configuration.SipSessionManager.V1.SipUDPTLMediaServiceItem()
+ mapper.map('udptloveripv6', item, 'requireIPv6', 'udptlmediaservice', config.getboolean, None)
+ mapper.map('udptloverice', item, 'enableICE', 'udptlmediaservice', config.getboolean, None)
+ mapper.map('udptlwithturn', item, 'enableTURN', 'udptlmediaservice', config.getboolean, None)
+
item = AsteriskSCF.Configuration.SipSessionManager.V1.SipCryptoCertificateItem()
mapper.map('certificateauthorityfile', item, 'certificateAuthority', 'cryptocert', config.get, None)
mapper.map('certificatefile', item, 'certificate', 'cryptocert', config.get, None)
@@ -263,21 +268,43 @@ class SipSectionVisitors(Configurator.SectionVisitors):
formats = config.get(section, 'formats')
configuredFormats = formats.split(',')
for format in configuredFormats:
- name, found, rest = format.partition('/')
- sampleRate, found, rest = rest.partition('@')
- frameSize, found, formatSpecific = rest.partition(';')
-
item = AsteriskSCF.Configuration.SipSessionManager.V1.SipMediaFormatItem()
- item.name = name
- if sampleRate:
- item.sampleRate = sampleRate
- if frameSize:
- item.frameSize = frameSize
+
+ front, found, rest = format.partition('/')
+ if found:
+ item.name = front
+ else:
+ rest = front
+
+ front, found, rest = rest.partition('@')
+ if found:
+ if item.name:
+ item.sampleRate = front
+ else:
+ item.name = front
+ else:
+ rest = front
+
+ front, found, rest = rest.partition(';')
+ if found:
+ if item.name:
+ item.frameSize = front
+ else:
+ item.name = front
+ else:
+ rest = front
+
item.formatSpecific = [ ]
- if formatSpecific:
- item.formatSpecific.append(formatSpecific)
- group.configurationItems[format] = item
+ if not item.name:
+ item.name = format
+
+ if item.name:
+ while rest:
+ front, found, rest = rest.partition('&')
+ item.formatSpecific.append(front)
+
+ group.configurationItems[format] = item
except:
print 'No configured formats for endpoint ' + section
diff --git a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
index c22c91b..3641291 100644
--- a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
@@ -334,6 +334,32 @@ class SipRTPMediaServiceItem extends SipConfigurationItem
};
/**
+ * UDPTL Media service configuration item
+ */
+class SipUDPTLMediaServiceItem extends SipConfigurationItem
+{
+ /**
+ * Name of the UDPTL media service to use
+ */
+ string mediaServiceName;
+
+ /**
+ * Whether to choose an IPv6 UDPTL media service or not
+ */
+ bool requireIPv6 = false;
+
+ /**
+ * Boolean for whether ICE is enabled
+ */
+ bool enableICE = false;
+
+ /**
+ * Boolean for whether TURN is enabled
+ */
+ bool enableTURN = false;
+};
+
+/**
* Signaling NAT configuration item
*/
class SipSignalingNATItem extends SipConfigurationItem
diff --git a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
index f982668..f9eab87 100644
--- a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
@@ -19,6 +19,7 @@
#include <Ice/Identity.ice>
#include <AsteriskSCF/Media/MediaIf.ice>
#include <AsteriskSCF/Media/RTP/MediaRTPIf.ice>
+#include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.ice>
#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.ice>
#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.ice>
#include <AsteriskSCF/System/Component/ConfigurationIf.ice>
@@ -140,6 +141,7 @@ module V1
};
dictionary<string, AsteriskSCF::Media::RTP::V1::RTPSession*> RTPMediaSessionDict;
+ sequence<AsteriskSCF::Media::UDPTL::V1::UDPTLSession*> UDPTLMediaSessionSeq;
class SipSessionStateItem extends SipStateItem
{
@@ -153,6 +155,7 @@ module V1
AsteriskSCF::Media::V1::StreamSinkSeq sinks;
AsteriskSCF::Media::V1::StreamInformationDict streams;
RTPMediaSessionDict rtpMediaSessions;
+ UDPTLMediaSessionSeq udptlMediaSessions;
AsteriskSCF::SessionCommunications::V1::SessionListenerSeq listeners;
AsteriskSCF::SessionCommunications::V1::Bridge *bridge;
AsteriskSCF::SessionCommunications::V1::SessionCookieDict cookies;
diff --git a/src/NATOptions.h b/src/NATOptions.h
index 2319c50..5c71700 100644
--- a/src/NATOptions.h
+++ b/src/NATOptions.h
@@ -27,9 +27,11 @@ struct NATEndpointOptions
bool enableICE;
bool enableTURN;
bool enableSIPSTUN;
+ bool enableUDPTLICE;
+ bool enableUDPTLTURN;
- NATEndpointOptions(bool ice, bool turn, bool sip) :
- enableICE(ice), enableTURN(turn), enableSIPSTUN(sip)
+ NATEndpointOptions(bool ice, bool turn, bool sip, bool udptlice, bool udptlturn) :
+ enableICE(ice), enableTURN(turn), enableSIPSTUN(sip), enableUDPTLICE(udptlice), enableUDPTLTURN(udptlturn)
{
}
};
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 3b97fd4..9504d47 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -108,6 +108,7 @@ void PJSipSessionModInfo::updateSessionState(pjsip_inv_session *inv_session)
mSessionState->sources = mSession->getMediaSources();
mSessionState->sinks = mSession->getMediaSinks();
mSessionState->rtpMediaSessions = mSession->getRTPMediaSessions();
+ mSessionState->udptlMediaSessions = mSession->getUDPTLMediaSessions();
mSessionState->listeners = mSession->getListeners();
mSessionState->streams = mSession->getStreams();
try
@@ -1508,14 +1509,8 @@ private:
ServiceLocatorPrx mServiceLocator;
};
-void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t status)
+void PJSipSessionModule::invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t)
{
- if (status != PJ_SUCCESS)
- {
- // We have nothing, zip, nada, kablamo, in common.
- return;
- }
-
lg(Debug) << "Queuing HandleMediaUpdate";
enqueueSessionWork(new HandleMediaUpdate(inv, mModule.id, mServiceLocator), inv);
}
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index f4c07ef..cd00465 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -310,6 +310,11 @@ class EndpointConfigHelper : public boost::enable_shared_from_this<EndpointConfi
mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateMediaService, mConfig, service));
};
+ void visitSipUDPTLMediaServiceItem(const SipUDPTLMediaServiceItemPtr& service)
+ {
+ mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateUDPTLMediaService, mConfig, service));
+ };
+
void visitSipEndpointTransportItem(const SipEndpointTransportItemPtr& transport)
{
mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateTransport, mConfig, transport));
@@ -460,6 +465,13 @@ public:
mEndpoint->setRTPOverIPv6(service->requireIPv6);
}
+ void updateUDPTLMediaService(const SipUDPTLMediaServiceItemPtr& service)
+ {
+ mEndpoint->setUDPTLOverIPv6(service->requireIPv6);
+ mEndpoint->enableUDPTLICE(service->enableICE);
+ mEndpoint->enableUDPTLTURN(service->enableTURN);
+ }
+
void updateTransport(const SipEndpointTransportItemPtr& transport)
{
mEndpoint->setSecureTransport(translateCallDirection(transport->secureTransport));
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index d017a06..f03e3ac 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -337,12 +337,26 @@ void SipEndpoint::setRTPOverIPv6(bool enabled)
mImplPriv->mConfig.sessionConfig.rtpOverIPv6 = enabled;
}
-
void SipEndpoint::setDirectMedia(bool enabled)
{
mImplPriv->mConfig.sessionConfig.directMedia = enabled;
}
+void SipEndpoint::setUDPTLOverIPv6(bool enabled)
+{
+ mImplPriv->mConfig.sessionConfig.udptlOverIPv6 = enabled;
+}
+
+void SipEndpoint::enableUDPTLICE(bool enabled)
+{
+ mImplPriv->mConfig.sessionConfig.udptlOverICE = enabled;
+}
+
+void SipEndpoint::enableUDPTLTURN(bool enabled)
+{
+ mImplPriv->mConfig.sessionConfig.udptlWithTURN = enabled;
+}
+
void SipEndpoint::setMediaNATOptions(bool useICE, bool useTURN)
{
mImplPriv->mConfig.sessionConfig.rtpOverICE = useICE;
@@ -446,8 +460,10 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(
true,
mImplPriv->mConfig,
NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE,
- mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
- mImplPriv->mConfig.transportConfig.enableNAT));
+ mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+ mImplPriv->mConfig.transportConfig.enableNAT,
+ mImplPriv->mConfig.sessionConfig.udptlOverICE,
+ mImplPriv->mConfig.sessionConfig.udptlWithTURN));
mImplPriv->mSessions.push_back(session);
@@ -475,7 +491,9 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
mImplPriv->mConfig,
NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE,
mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
- mImplPriv->mConfig.transportConfig.enableNAT)
+ mImplPriv->mConfig.transportConfig.enableNAT,
+ mImplPriv->mConfig.sessionConfig.udptlOverICE,
+ mImplPriv->mConfig.sessionConfig.udptlWithTURN)
);
mImplPriv->mSessions.push_back(session);
@@ -493,28 +511,32 @@ SipSessionPtr SipEndpoint::createSession
const Ice::Identity& controllerid,
const Ice::Identity& mediaid,
const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
{
SipSessionPtr session = SipSession::create
- (mImplPriv->mAdapter,
- this,
- destination,
- sessionid,
- controllerid,
- mediaid,
- mediasessions,
- sources,
- sinks,
- mImplPriv->mManager,
- mImplPriv->mServiceLocator,
- mImplPriv->mReplicationContext,
- 0,
- false,
- mImplPriv->mConfig,
- NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE,
- mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
- mImplPriv->mConfig.transportConfig.enableNAT));
+ (mImplPriv->mAdapter,
+ this,
+ destination,
+ sessionid,
+ controllerid,
+ mediaid,
+ mediasessions,
+ udptlMediaSessions,
+ sources,
+ sinks,
+ mImplPriv->mManager,
+ mImplPriv->mServiceLocator,
+ mImplPriv->mReplicationContext,
+ 0,
+ false,
+ mImplPriv->mConfig,
+ NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE,
+ mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
+ mImplPriv->mConfig.transportConfig.enableNAT,
+ mImplPriv->mConfig.sessionConfig.udptlOverICE,
+ mImplPriv->mConfig.sessionConfig.udptlWithTURN));
mImplPriv->mSessions.push_back(session);
return session;
@@ -767,6 +789,36 @@ SDPDescriptorPtr SipEndpoint::getDescriptor(const FormatPtr& format)
return 0;
}
+SDPDescriptorPtr SipEndpoint::getInterpretedDescriptor(const FormatPtr& format)
+{
+ for (std::vector<ConfiguredFormatPtr>::const_iterator configuredFormat = mImplPriv->mFormats.begin();
+ configuredFormat != mImplPriv->mFormats.end();
+ ++configuredFormat)
+ {
+ if ((*configuredFormat)->getFormat()->name == format->name)
+ {
+ return (*configuredFormat)->getDescriptorService()->getDescriptor(format);
+ }
+ }
+
+ return 0;
+}
+
+FormatPtr SipEndpoint::getFormat(const FormatPtr& format)
+{
+ for (std::vector<ConfiguredFormatPtr>::const_iterator configuredFormat = mImplPriv->mFormats.begin();
+ configuredFormat != mImplPriv->mFormats.end();
+ ++configuredFormat)
+ {
+ if ((*configuredFormat)->getFormat()->name == format->name)
+ {
+ return (*configuredFormat)->getFormat();
+ }
+ }
+
+ return 0;
+}
+
StreamInformationDict SipEndpoint::getStreamTopology()
{
StreamInformationDict topology;
@@ -776,6 +828,12 @@ StreamInformationDict SipEndpoint::getStreamTopology()
configuredFormat != mImplPriv->mFormats.end();
++configuredFormat)
{
+ // Initial stream topology does not support T.38 streams
+ if ((*configuredFormat)->getDescriptor()->type == "image")
+ {
+ continue;
+ }
+
// See if a stream already exists for this type
StreamInformationDict::iterator stream = topology.find((*configuredFormat)->getDescriptor()->type);
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 0a07081..037b1b3 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -161,6 +161,12 @@ public:
bool rtpOverIPv6;
// Whether we are allowing direct media or not
bool directMedia;
+ // Whether we are using IPv6 for UDPTL transport or not.
+ bool udptlOverIPv6;
+ // Whether ICE is enabled for UDPTL.
+ bool udptlOverICE;
+ // Whether TURN is enabled for UDPTL.
+ bool udptlWithTURN;
// The method by which we will transmit
// DTMF to an endpoint
AsteriskSCF::Configuration::SipSessionManager::V1::SipDTMFOption dtmf;
@@ -321,6 +327,7 @@ public:
AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&);
AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&, const Ice::Identity&, const Ice::Identity&,
const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict&,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq&,
const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&);
void removeSession(const AsteriskSCF::SessionCommunications::V1::SessionPtr&);
@@ -336,6 +343,9 @@ public:
void setSecureTransport(enum Direction);
void setRTPOverIPv6(bool);
void setDirectMedia(bool);
+ void setUDPTLOverIPv6(bool);
+ void enableUDPTLICE(bool);
+ void enableUDPTLTURN(bool);
void addFormat(const std::string& name, int sampleRate, int frameSize, const Ice::StringSeq& formatSpecific);
/**
@@ -345,11 +355,21 @@ public:
const AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr&);
/**
- * API call which returns a descriptor given a media format.
+ * API call which returns a locally cached descriptor given a media format.
*/
AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr getDescriptor(const AsteriskSCF::Media::V1::FormatPtr&);
/**
+ * API call which returns a descriptor given a media format.
+ */
+ AsteriskSCF::Media::SDP::V1::SDPDescriptorPtr getInterpretedDescriptor(const AsteriskSCF::Media::V1::FormatPtr&);
+
+ /**
+ * API call which returns the local format given a media format.
+ */
+ AsteriskSCF::Media::V1::FormatPtr getFormat(const AsteriskSCF::Media::V1::FormatPtr&);
+
+ /**
* API call which returns the stream topology to be used for an SDP offer.
*/
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index dce14ab..3182731 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -40,6 +40,9 @@
#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
#include <AsteriskSCF/Media/SDP/MediaSDPIf.h>
#include <AsteriskSCF/Media/RTP/MediaRTCPIf.h>
+#include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.h>
+#include <AsteriskSCF/Media/Formats/T38UdptlFormat.h>
+#include <AsteriskSCF/Media/NetworkIf.h>
#include <AsteriskSCF/SessionCookies/SipSessionManager/SipSessionCookiesIf.h>
#include <AsteriskSCF/Collections/HandleSet.h>
#include "NATOptions.h"
@@ -52,6 +55,9 @@ using namespace AsteriskSCF::Media::RTP::V1;
using namespace AsteriskSCF::Media::V1;
using namespace AsteriskSCF::Media;
using namespace AsteriskSCF::Media::SDP::V1;
+using namespace AsteriskSCF::Media::UDPTL::V1;
+using namespace AsteriskSCF::Media::Formats::T38Udptl::V1;
+using namespace AsteriskSCF::Network::V1;
using namespace AsteriskSCF::System::V1;
using namespace AsteriskSCF::Helpers;
using namespace std;
@@ -284,6 +290,11 @@ public:
RTPMediaSessionDict mRTPSessions;
/**
+ * A vector of UDPTL media sessions belonging to this session.
+ */
+ UDPTLMediaSessionSeq mUDPTLSessions;
+
+ /**
* A vector of media sources associated with this endpoint.
*/
AsteriskSCF::Media::V1::StreamSourceSeq mSources;
@@ -1276,37 +1287,39 @@ SipSessionPtr SipSession::create(const Ice::ObjectAdapterPtr& adapter,
* Factory used by a standby component to create replicas.
*/
SipSessionPtr SipSession::create(const Ice::ObjectAdapterPtr& adapter,
- const SipEndpointPtr& endpoint,
- const std::string& destination,
- const Ice::Identity& sessionid,
- const Ice::Identity& controllerid,
- const Ice::Identity& mediaid,
- const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
- const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
- const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
- const PJSipManagerPtr& manager,
- const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const SipReplicationContextPtr& replicationContext,
- const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
- bool isUAC,
- const SipEndpointConfig &config,
- const NATEndpointOptions& natOptions)
+ const SipEndpointPtr& endpoint,
+ const std::string& destination,
+ const Ice::Identity& sessionid,
+ const Ice::Identity& controllerid,
+ const Ice::Identity& mediaid,
+ const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
+ const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
+ const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
+ const PJSipManagerPtr& manager,
+ const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+ const SipReplicationContextPtr& replicationContext,
+ const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookPrx& oneShotHook,
+ bool isUAC,
+ const SipEndpointConfig &config,
+ const NATEndpointOptions& natOptions)
{
SipSessionPtr newSession = new SipSession(adapter,
- endpoint,
- destination,
- sessionid,
- controllerid,
- mediaid,
- mediasessions,
- sources,
- sinks,
- manager,
- serviceLocator,
- replicationContext,
- isUAC,
- config,
- natOptions);
+ endpoint,
+ destination,
+ sessionid,
+ controllerid,
+ mediaid,
+ mediasessions,
+ udptlMediaSessions,
+ sources,
+ sinks,
+ manager,
+ serviceLocator,
+ replicationContext,
+ isUAC,
+ config,
+ natOptions);
AsteriskSCF::SessionCommunications::ExtensionPoints::V1::SessionCreationHookSeq hooks =
newSession->mImplPriv->mManager->getSessionModule()->getSessionCreationHooks();
@@ -1376,6 +1389,7 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
const Ice::Identity& controllerid,
const Ice::Identity& mediaid,
const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
const PJSipManagerPtr& manager,
@@ -1401,6 +1415,7 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter,
adapter->addFacet(directMedia, sessionid, directMediaConnectionFacet);
mImplPriv->mRTPSessions = mediasessions;
+ mImplPriv->mUDPTLSessions = udptlMediaSessions;
mImplPriv->mSources = sources;
mImplPriv->mSinks = sinks;
@@ -2434,6 +2449,19 @@ public:
lg(Error) << "Exception caught while trying to release a media session\n" << ex.what();
}
}
+
+ for (UDPTLMediaSessionSeq::const_iterator i = mSessionPriv->mUDPTLSessions.begin();
+ i != mSessionPriv->mUDPTLSessions.end(); ++i)
+ {
+ try
+ {
+ (*i)->release();
+ }
+ catch (const Ice::Exception& ex)
+ {
+ lg(Error) << "Exception caught while trying to release a udptl session\n" << ex.what();
+ }
+ }
}
mSessionPriv->mEndpoint->removeSession(mSession);
return Complete;
@@ -2710,111 +2738,224 @@ pjmedia_sdp_session *SipSession::createSDPOffer(const AsteriskSCF::Media::V1::St
// Update the stream with the actual formats
stream->second->formats = formats;
- RTPServiceLocatorParamsPtr params = new RTPServiceLocatorParams();
- params->category = "rtp";
- params->formats = stream->second->formats;
- params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.rtpOverIPv6;
+ // Determine what media this stream is carrying
+ AudioFormatPtr audio;
+ VideoFormatPtr video;
+ T38UdptlFormatPtr t38;
- // Try to find a factory for RTP sessions matching what we need
- RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
-
- // If none exist we can't provide the stream
- if (factory == 0)
+ // If this stream contains an audio or video format the stream is transported using RTP
+ if ((audio = AudioFormatPtr::dynamicCast(formats.front())) || (video = VideoFormatPtr::dynamicCast(formats.front())))
{
- continue;
- }
+ RTPServiceLocatorParamsPtr params = new RTPServiceLocatorParams();
+ params->category = "rtp";
+ params->formats = stream->second->formats;
+ params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.rtpOverIPv6;
+
+ // Try to find a factory for RTP sessions matching what we need
+ RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+
+ if (factory == 0)
+ {
+ continue;
+ }
- // Allocate a new RTP session to carry the media formats we have in common
+ // Allocate a new RTP session to carry the media formats we have in common
- RTPOptionsPtr options(new RTPOptions());
- RTPAllocationOutputsPtr outputs;
+ RTPOptionsPtr options(new RTPOptions());
+ RTPAllocationOutputsPtr outputs;
- SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
- if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
- {
- options->handleTelephonyEvents = true;
- }
+ SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
+ if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
+ {
+ options->handleTelephonyEvents = true;
+ }
- RTPSessionPrx session = factory->allocate(params, options, outputs);
+ RTPSessionPrx session = factory->allocate(params, options, outputs);
- // Double check to make sure they actually gave us a sesson back... they could have had a problem
- if (session == 0)
- {
- continue;
- }
+ // Double check to make sure they actually gave us a sesson back... they could have had a problem
+ if (session == 0)
+ {
+ continue;
+ }
- if (outputs)
- {
- mImplPriv->mExternalEventSources = outputs->eventSources;
- mImplPriv->mExternalEventSinks = outputs->eventSinks;
- }
+ if (outputs)
+ {
+ mImplPriv->mExternalEventSources = outputs->eventSources;
+ mImplPriv->mExternalEventSinks = outputs->eventSinks;
+ }
- // RTP sessions should only provide a single sink, so grab it and update the connection details with that
- // of the remote party
- StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
- mImplPriv->mSinks.push_back(sink);
- stream->second->sinks.push_back(sink);
+ // RTP sessions should only provide a single sink, so grab it and update the connection details with that
+ // of the remote party
+ StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
+ mImplPriv->mSinks.push_back(sink);
+ stream->second->sinks.push_back(sink);
- // Ditto goes for source
- StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
- mImplPriv->mSources.push_back(source);
- stream->second->sources.push_back(source);
+ // Ditto goes for source
+ StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
+ mImplPriv->mSources.push_back(source);
+ stream->second->sources.push_back(source);
- // Update the SIP session with some RTP session details
- mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), session));
+ // Update the SIP session with some RTP session details
+ mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), session));
+
+ // Add the stream to the SDP
+ pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
- // Add the stream to the SDP
- pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+ // The media count is purposely not incremented here since it is done when the stream is added to the sequence
+ // of streams
+ mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
+ pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
+ stream->second->formats.front())->type.c_str());
- // The media count is purposely not incremented here since it is done when the stream is added to the sequence
- // of streams
- mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
- pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
- stream->second->formats.front())->type.c_str());
+ pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
- // TODO: This should not be hardcoded
- pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
+ // Add connection level details
+ media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
- // Add connection level details
- media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
- pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
+ if (params->ipv6 == true)
+ {
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+ }
+ else
+ {
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
+ }
- if (params->ipv6 == true)
- {
- pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+
+ // If session level connection information has not yet been set then set it to us
+ if (!mImplPriv->mSDP->conn)
+ {
+ mImplPriv->mSDP->conn = media->conn;
+ }
+
+ media->desc.port = (pj_uint16_t) source->getLocalPort();
+ media->desc.port_count = 1;
+
+ RTCP::V1::RTCPSessionPrx rtcpSession;
+ if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
+ {
+ pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
+ pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "rtcp");
+ pj_strdup2(mImplPriv->mDialog->pool, &attr->value, boost::lexical_cast<std::string>(rtcpSession->getLocalPort()).c_str());
+ media->attr[media->attr_count++] = attr;
+ }
+
+ PayloadMap payloads;
+
+ // Add all of the formats to the SDP
+ addFormatstoSDP(stream->second->formats, media, payloads);
+
+ // Push the payload mapping to the RTP session so it'll correctly map things
+ session->associatePayloads(payloads);
}
- else
+ else if ((t38 = T38UdptlFormatPtr::dynamicCast(formats.front())))
{
- pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
- }
+ UDPTLServiceLocatorParamsPtr params;
- pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+ if (mImplPriv->mNatOptions.enableUDPTLICE)
+ {
+ AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParamsPtr iceParams =
+ new AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParams;
+ params = iceParams;
+ iceParams->enableICE = true;
+ iceParams->enableTURN = mImplPriv->mNatOptions.enableUDPTLTURN;
+ }
+ else
+ {
+ params = new AsteriskSCF::Media::UDPTL::V1::UDPTLServiceLocatorParams;
+ }
- // If session level connection information has not yet been set then set it to us
- if (!mImplPriv->mSDP->conn)
- {
- mImplPriv->mSDP->conn = media->conn;
- }
+ params->category = "udptl";
+ params->ipv6 = mImplPriv->mEndpoint->getConfig().sessionConfig.udptlOverIPv6;
- media->desc.port = (pj_uint16_t) source->getLocalPort();
- media->desc.port_count = 1;
+ UDPTLMediaServicePrx factory = UDPTLMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+ if (factory == 0)
+ {
+ continue;
+ }
- RTCP::V1::RTCPSessionPrx rtcpSession;
- if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
- {
- pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
- pj_strdup2(mImplPriv->mDialog->pool, &attr->name, "rtcp");
- pj_strdup2(mImplPriv->mDialog->pool, &attr->value, boost::lexical_cast<std::string>(rtcpSession->getLocalPort()).c_str());
- media->attr[media->attr_count++] = attr;
- }
+ UDPTLSessionPrx session = factory->allocate(params);
+ if (session == 0)
+ {
+ continue;
+ }
- PayloadMap payloads;
+ StreamSinkUDPTLPrx sink = StreamSinkUDPTLPrx::uncheckedCast(session->getSinks().front());
+ mImplPriv->mSinks.push_back(sink);
+ stream->second->sinks.push_back(sink);
+
+ StreamSourceUDPTLPrx source = StreamSourceUDPTLPrx::uncheckedCast(session->getSources().front());
+ mImplPriv->mSources.push_back(source);
+ stream->second->sources.push_back(source);
+
+ mImplPriv->mUDPTLSessions.push_back(session);
+
+ // Add the stream to the SDP
+ mImplPriv->mSDP->media_count = 0;
- // Add all of the formats to the SDP
- addFormatstoSDP(stream->second->formats, media, payloads);
+ // Since we may be replacing an existing stream go ahead and remove it
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count));
+
+ pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+ // The media count is purposely not incremented here since it is done when the stream is added to the sequence
+ // of streams
+ mImplPriv->mSDP->media[mImplPriv->mSDP->media_count] = media;
+
+ pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(
+ stream->second->formats.front())->type.c_str());
+
+ pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "UDPTL");
+
+ pj_strdup2(mImplPriv->mDialog->pool, &media->desc.fmt[media->desc.fmt_count++], "t38");
+
+ // Add connection level details
+ media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->net_type, "IN");
+
+ if (params->ipv6 == true)
+ {
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP6");
+ }
+ else
+ {
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr_type, "IP4");
+ }
+
+ AddressInformation info = source->getLocalDetails();
+
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, info.ipAddress.c_str());
+
+ // If session level connection information has not yet been set then set it to us
+ if (!mImplPriv->mSDP->conn)
+ {
+ mImplPriv->mSDP->conn = media->conn;
+ }
+
+ media->desc.port = (pj_uint16_t) info.port;
+ media->desc.port_count = 1;
- // Push the payload mapping to the RTP session so it'll correctly map things
- session->associatePayloads(payloads);
+ // Use the configured format to set the error correction
+ T38UdptlFormatPtr t38Configuration = T38UdptlFormatPtr::dynamicCast(mImplPriv->mEndpoint->getFormat(t38));
+
+ t38->errorCorrection = t38Configuration->errorCorrection;
+
+ SDPDescriptorPtr ourDescriptor = mImplPriv->mEndpoint->getInterpretedDescriptor(t38);
+ for (SDPFormatParameterSeq::const_iterator parameter = ourDescriptor->parameters.begin();
+ parameter != ourDescriptor->parameters.end();
+ ++parameter)
+ {
+ pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
+ pj_strdup2(mImplPriv->mDialog->pool, &attr->name, (*parameter).c_str());
+ media->attr[media->attr_count++] = attr;
+ }
+ }
+ else
+ {
+ // The media format type is just unknown to us, so we can not create a stream for this
+ continue;
+ }
// Make the caller aware of this new stream
newStreams.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), stream->second));
@@ -2903,11 +3044,21 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
{
SDPDescriptorPtr descriptor = new SDPDescriptor();
- std::string payload = std::string(pj_strbuf(&offer->media[stream]->desc.fmt[format]),
- pj_strlen(&offer->media[stream]->desc.fmt[format]));
- descriptor->payload = boost::lexical_cast<int>(payload);
descriptor->type = std::string(pj_strbuf(&offer->media[stream]->desc.media),
pj_strlen(&offer->media[stream]->desc.media));
+ std::string payload = std::string(pj_strbuf(&offer->media[stream]->desc.fmt[format]),
+ pj_strlen(&offer->media[stream]->desc.fmt[format]));
+
+ // If this is for T.38 it is actually special
+ if (descriptor->type == "image" && (payload == "T38" || payload == "t38"))
+ {
+ descriptor->payload = 96;
+ descriptor->subtype = "UDPTL";
+ }
+ else
+ {
+ descriptor->payload = boost::lexical_cast<int>(payload);
+ }
// Some devices rely solely on the payload for known formats (such as PCMU) so the following format
// parameters are completely optional
@@ -2992,8 +3143,29 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
continue;
}
- // Update the stream with the formats
- ourStream->formats = formats;
+ // Update the stream with the formats
+ ourStream->formats = formats;
+
+ // Record the old state so we can relay the state change to the controller if needed
+ StreamState oldState = ourStream->state;
+
+ // Determine the state of the stream and update it
+ if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendonly", NULL))
+ {
+ ourStream->state = SendOnly;
+ }
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "recvonly", NULL))
+ {
+ ourStream->state = ReceiveOnly;
+ }
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "inactive", NULL))
+ {
+ ourStream->state = Inactive;
+ }
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendrecv", NULL))
+ {
+ ourStream->state = SendAndReceive;
+ }
// Assume that no connection level details exist until proven otherwise
std::string connection = destination;
@@ -3003,193 +3175,366 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
pj_strlen(&offer->media[stream]->conn->addr));
}
- RTPSessionPrx session;
+ AudioFormatPtr audio;
+ VideoFormatPtr video;
+ T38UdptlFormatPtr t38;
- // If no sink and no source is present then this stream has no RTP session yet so find one
- if (ourStream->sinks.empty() && ourStream->sources.empty())
- {
- RTPServiceLocatorParamsPtr params;
- if (mImplPriv->mNatOptions.enableICE)
- {
- AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
- new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
- params = iceParams;
- iceParams->enableRTPOverICE = true;
- iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
- }
- else
+ if ((audio = AudioFormatPtr::dynamicCast(formats.front())) || (video = VideoFormatPtr::dynamicCast(formats.front())))
{
- params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
- }
-
- params->category = "rtp";
- params->formats = formats;
-
- // See what address family the connection address is in so we can request the right RTP service
- if (connection.find(":") != std::string::npos)
+ // If this is a modified stream make sure the transport is RTP, if not clear things out
+ if (!ourStream->sinks.empty())
{
- params->ipv6 = true;
+ StreamSinkRTPPrx rtpSink = StreamSinkRTPPrx::checkedCast(ourStream->sinks.front());
+ if (!rtpSink)
+ {
+ ourStream->sinks.clear();
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ }
}
- else
+
+ if (!ourStream->sources.empty())
{
- params->ipv6 = false;
+ StreamSourceRTPPrx rtpSource = StreamSourceRTPPrx::checkedCast(ourStream->sources.front());
+ if (!rtpSource)
+ {
+ ourStream->sources.clear();
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ }
}
- // Try to find a factory for RTP sessions matching what we need
- RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+ RTPSessionPrx session;
- // If none exist we can't provide accept the stream
- if (factory == 0)
+ // If no sink and no source is present then this stream has no RTP session yet so find one
+ if (ourStream->sinks.empty() && ourStream->sources.empty())
{
- // The only time this should ever occur is on the initial INVITE so removing the stream from everywhere
- // is perfectly acceptable since nothing has seen it
- mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
- newStreams.erase(boost::lexical_cast<std::string>(stream));
- continue;
+ RTPServiceLocatorParamsPtr params;
+ if (mImplPriv->mNatOptions.enableICE)
+ {
+ AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
+ new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
+ params = iceParams;
+ iceParams->enableRTPOverICE = true;
+ iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
+ }
+ else
+ {
+ params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
+ }
+
+ params->category = "rtp";
+ params->formats = formats;
+
+ // See what address family the connection address is in so we can request the right RTP service
+ if (connection.find(":") != std::string::npos)
+ {
+ params->ipv6 = true;
+ }
+ else
+ {
+ params->ipv6 = false;
+ }
+
+ // Try to find a factory for RTP sessions matching what we need
+ RTPMediaServicePrx factory = RTPMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
+
+ // If none exist we can't provide accept the stream
+ if (factory == 0)
+ {
+ // The only time this should ever occur is on the initial INVITE so removing the stream from everywhere
+ // is perfectly acceptable since nothing has seen it
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ continue;
+ }
+
+ // Allocate a new RTP session to carry the media formats we have in common
+
+ RTPOptionsPtr options(new RTPOptions());
+ RTPAllocationOutputsPtr outputs;
+
+ SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
+ if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
+ {
+ options->handleTelephonyEvents = true;
+ }
+
+ session = factory->allocate(params, options, outputs);
+
+ // Double check to make sure they actually gave us a sesson back... they could have had a problem
+ if (session == 0)
+ {
+ // The only time this should ever occur is on the initial INVITE so removing the stream from everywhere
+ // is perfectly acceptable since nothing has seen it
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ continue;
+ }
+
+ if (outputs)
+ {
+ mImplPriv->mExternalEventSources = outputs->eventSources;
+ mImplPriv->mExternalEventSinks = outputs->eventSinks;
+ }
+
+ // RTP sessions only provide a single sink and source so that makes this easy
+ StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
+ mImplPriv->mSinks.push_back(sink);
+ ourStream->sinks.push_back(sink);
+
+ StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
+ mImplPriv->mSources.push_back(source);
+ ourStream->sources.push_back(source);
+
+ // Update the SIP session with some RTP session details
+ mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), session));
+
+ // Just by common sense alone since we just got an RTP session for this stream we obviously
+ // have not added it to the answer SDP either, so do it
+ pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+ mImplPriv->mSDP->media[mImplPriv->mSDP->media_count++] = media;
+
+ // Since our stream should be like the offering stream we can just use some values from there
+ media->desc.media = offer->media[stream]->desc.media;
+ media->desc.transport = offer->media[stream]->desc.transport;
+ media->desc.fmt[0] = offer->media[stream]->desc.fmt[0];
+
+ // Add connection level information so they know our IP address
+ media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+ media->conn->net_type = offer->origin.net_type;
+ media->conn->addr_type = offer->origin.addr_type;
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+
+ // If session level connection information has not yet been set then set it to us
+ if (!mImplPriv->mSDP->conn)
+ {
+ mImplPriv->mSDP->conn = media->conn;
+ }
+
+ // Add port information so they can talk to us
+ media->desc.port = (pj_uint16_t) source->getLocalPort();
+ media->desc.port_count = 1;
+
+ PayloadMap payloads;
+
+ addFormatstoSDP(formats, media, payloads);
+
+ // Push the payload mapping to the RTP session so it'll correctly map things
+ session->associatePayloads(payloads);
}
-
- RTPOptionsPtr options(new RTPOptions());
- RTPAllocationOutputsPtr outputs;
- SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
- if (config.sessionConfig.dtmf == AsteriskSCF::Configuration::SipSessionManager::V1::RFC4733)
+ // If the RTP session supports RTCP determine the connection details for it
+ RTCP::V1::RTCPSessionPrx rtcpSession;
+ if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
{
- options->handleTelephonyEvents = true;
+ // Assume RTCP is destined for the same address and the RTP port + 1 as it probably is
+ std::string rtcpConnection = connection;
+ int rtcpPort = offer->media[stream]->desc.port + 1;
+
+ pjmedia_sdp_attr *attr;
+ pjmedia_sdp_rtcp_attr rtcpAttr;
+
+ if ((attr = pjmedia_sdp_media_find_attr2(offer->media[stream], "rtcp", NULL)) &&
+ (pjmedia_sdp_attr_get_rtcp(attr, &rtcpAttr) == PJ_SUCCESS))
+ {
+ rtcpPort = rtcpAttr.port;
+
+ if (rtcpAttr.addr.slen)
+ {
+ rtcpConnection = std::string(pj_strbuf(&rtcpAttr.addr), pj_strlen(&rtcpAttr.addr));
+ }
+ }
+
+ rtcpSession->setRemoteDetails(rtcpConnection, rtcpPort);
}
- // Allocate a new RTP session to carry the media formats we have in common
- session = factory->allocate(params, options, outputs);
+ // Update connection information
+ StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(ourStream->sinks.front());
- // Double check to make sure they actually gave us a sesson back... they could have had a problem
- if (session == 0)
+ // If the remote party attempts to use an invalid address bring down the session since obviously
+ // something is critically wrong and stuff will most likely fall apart quickly
+ try
{
- // The only time this should ever occur is on the initial INVITE so removing the stream from everywhere
- // is perfectly acceptable since nothing has seen it
- mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
- newStreams.erase(boost::lexical_cast<std::string>(stream));
- continue;
+ sink->setRemoteDetails(connection, offer->media[stream]->desc.port);
+ }
+ catch (const AsteriskSCF::Media::RTP::V1::InvalidAddress&)
+ {
+ pjsip_tx_data *packet;
+ if (pjsip_inv_end_session(mImplPriv->mInviteSession, 488, NULL, &packet) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
+ }
+ return 0;
}
+ }
+ else if ((t38 = T38UdptlFormatPtr::dynamicCast(formats.front())))
+ {
+ // Ensure the offer is valid
+ if (t38->faxRateManagement == UNSPECIFIED_TCF)
+ {
+ continue;
+ }
- if (outputs)
+ // If this is a modified stream make sure the transport is UDPTL, if not clear things out
+ if (!ourStream->sinks.empty())
{
- mImplPriv->mExternalEventSources = outputs->eventSources;
- mImplPriv->mExternalEventSinks = outputs->eventSinks;
+ StreamSinkUDPTLPrx udptlSink = StreamSinkUDPTLPrx::checkedCast(ourStream->sinks.front());
+ if (!udptlSink)
+ {
+ ourStream->sinks.clear();
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ }
}
- // RTP sessions only provide a single sink and source so that makes this easy
- StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(session->getSinks().front());
- mImplPriv->mSinks.push_back(sink);
- ourStream->sinks.push_back(sink);
+ if (!ourStream->sources.empty())
+ {
+ StreamSourceUDPTLPrx udptlSource = StreamSourceUDPTLPrx::checkedCast(ourStream->sources.front());
+ if (!udptlSource)
+ {
+ ourStream->sources.clear();
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ }
+ }
- StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
- mImplPriv->mSources.push_back(source);
- ourStream->sources.push_back(source);
+ if (ourStream->sinks.empty() && ourStream->sources.empty())
+ {
+ UDPTLServiceLocatorParamsPtr params;
- // Update the SIP session with some RTP session details
- mImplPriv->mRTPSessions.insert(make_pair(boost::lexical_cast<std::string>(stream), session));
+ if (mImplPriv->mNatOptions.enableUDPTLICE)
+ {
+ AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParamsPtr iceParams =
+ new AsteriskSCF::Media::UDPTL::V1::UDPTLOverICEServiceLocatorParams;
+ params = iceParams;
+ iceParams->enableICE = true;
+ iceParams->enableTURN = mImplPriv->mNatOptions.enableUDPTLTURN;
+ }
+ else
+ {
+ params = new AsteriskSCF::Media::UDPTL::V1::UDPTLServiceLocatorParams;
+ }
- // Just by common sense alone since we just got an RTP session for this stream we obviously
- // have not added it to the answer SDP either, so do it
- pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
- mImplPriv->mSDP->media[mImplPriv->mSDP->media_count++] = media;
+ params->category = "udptl";
- // Since our stream should be like the offering stream we can just use some values from there
- media->desc.media = offer->media[stream]->desc.media;
- media->desc.transport = offer->media[stream]->desc.transport;
+ if (connection.find(":") != std::string::npos)
+ {
+ params->ipv6 = true;
+ }
+ else
+ {
+ params->ipv6 = false;
+ }
- // Add connection level information so they know our IP address
- media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
- media->conn->net_type = offer->origin.net_type;
- media->conn->addr_type = offer->origin.addr_type;
- pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, source->getLocalAddress().c_str());
+ UDPTLMediaServicePrx factory = UDPTLMediaServicePrx::uncheckedCast(mImplPriv->mServiceLocator->locate(params));
- // If session level connection information has not yet been set then set it to us
- if (!mImplPriv->mSDP->conn)
- {
- mImplPriv->mSDP->conn = media->conn;
- }
+ if (factory == 0)
+ {
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ continue;
+ }
- // Add port information so they can talk to us
- media->desc.port = (pj_uint16_t) source->getLocalPort();
- media->desc.port_count = 1;
+ UDPTLSessionPrx session = factory->allocate(params);
- PayloadMap payloads;
+ if (session == 0)
+ {
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ continue;
+ }
- addFormatstoSDP(formats, media, payloads);
+ StreamSinkUDPTLPrx sink = StreamSinkUDPTLPrx::uncheckedCast(session->getSinks().front());
+ mImplPriv->mSinks.push_back(sink);
+ ourStream->sinks.push_back(sink);
- // Push the payload mapping to the RTP session so it'll correctly map things
- session->associatePayloads(payloads);
- }
+ StreamSourceUDPTLPrx source = StreamSourceUDPTLPrx::uncheckedCast(session->getSources().front());
+ mImplPriv->mSources.push_back(source);
+ ourStream->sources.push_back(source);
- // Record the old state so we can relay the state change to the controller if needed
- StreamState oldState = ourStream->state;
-
- // Determine the state of the stream and update it
- if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendonly", NULL))
- {
- ourStream->state = SendOnly;
- }
- else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "recvonly", NULL))
- {
- ourStream->state = ReceiveOnly;
- }
- else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "inactive", NULL))
- {
- ourStream->state = Inactive;
- }
- else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendrecv", NULL))
- {
- ourStream->state = SendAndReceive;
- }
+ mImplPriv->mUDPTLSessions.push_back(session);
- // If the RTP session supports RTCP determine the connection details for it
- RTCP::V1::RTCPSessionPrx rtcpSession;
- if ((rtcpSession = RTCP::V1::RTCPSessionPrx::checkedCast(session, RTCP::V1::SessionFacet)))
- {
- // Assume RTCP is destined for the same address and the RTP port + 1 as it probably is
- std::string rtcpConnection = connection;
- int rtcpPort = offer->media[stream]->desc.port + 1;
+ mImplPriv->mSDP->media_count = 0;
- pjmedia_sdp_attr *attr;
- pjmedia_sdp_rtcp_attr rtcpAttr;
+ pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
+ mImplPriv->mSDP->media[mImplPriv->mSDP->media_count++] = media;
- if ((attr = pjmedia_sdp_media_find_attr2(offer->media[stream], "rtcp", NULL)) &&
- (pjmedia_sdp_attr_get_rtcp(attr, &rtcpAttr) == PJ_SUCCESS))
- {
- rtcpPort = rtcpAttr.port;
+ media->desc.media = offer->media[stream]->desc.media;
+ media->desc.transport = offer->media[stream]->desc.transport;
+ media->desc.fmt[0] = offer->media[stream]->desc.fmt[0];
+ media->desc.fmt_count++;
+
+ media->conn = allocate_from_pool<pjmedia_sdp_conn>(mImplPriv->mDialog->pool);
+ media->conn->net_type = offer->origin.net_type;
+ media->conn->addr_type = offer->origin.addr_type;
+
+ AddressInformation info = source->getLocalDetails();
+
+ pj_strdup2(mImplPriv->mDialog->pool, &media->conn->addr, info.ipAddress.c_str());
+
+ if (!mImplPriv->mSDP->conn)
+ {
+ mImplPriv->mSDP->conn = media->conn;
+ }
+
+ media->desc.port = (pj_uint16_t) info.port;
+ media->desc.port_count = 1;
- if (rtcpAttr.addr.slen)
+ SDPDescriptorPtr ourDescriptor = mImplPriv->mEndpoint->getInterpretedDescriptor(t38);
+ for (SDPFormatParameterSeq::const_iterator parameter = ourDescriptor->parameters.begin();
+ parameter != ourDescriptor->parameters.end();
+ ++parameter)
{
- rtcpConnection = std::string(pj_strbuf(&rtcpAttr.addr), pj_strlen(&rtcpAttr.addr));
+ pjmedia_sdp_attr *attr = allocate_from_pool<pjmedia_sdp_attr>(mImplPriv->mDialog->pool);
+ pj_strdup2(mImplPriv->mDialog->pool, &attr->name, (*parameter).c_str());
+ media->attr[media->attr_count++] = attr;
}
}
- rtcpSession->setRemoteDetails(rtcpConnection, rtcpPort);
- }
+ StreamSinkUDPTLPrx sink = StreamSinkUDPTLPrx::uncheckedCast(ourStream->sinks.front());
+ try
+ {
+ sink->setRemoteDetails(connection, offer->media[stream]->desc.port);
+ }
+ catch (const AsteriskSCF::Network::V1::InvalidAddress&)
+ {
+ pjsip_tx_data *packet;
+ if (pjsip_inv_end_session(mImplPriv->mInviteSession, 488, NULL, &packet) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
+ }
+ return 0;
+ }
- // If the state changed we need to notify the controller if one is around
- if (oldState != ourStream->state)
- {
- streamsChanged.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream->state));
- }
+ T38UdptlFormatPtr t38Configuration = T38UdptlFormatPtr::dynamicCast(mImplPriv->mEndpoint->getFormat(t38));
+
+ // If the max datagram has been overridden then use that instead of what they offered
+ if (t38Configuration->maxDatagram)
+ {
+ sink->setFarMaxDatagram(t38Configuration->maxDatagram);
+ }
+ else
+ {
+ sink->setFarMaxDatagram(t38->maxDatagram);
+ }
- // Update connection information
- StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(ourStream->sinks.front());
+ sink->setErrorCorrectionScheme(t38->errorCorrection);
- // If the remote party attempts to use an invalid address bring down the session since obviously
- // something is critically wrong and stuff will most likely fall apart quickly
- try
+ break;
+ }
+ else
{
- sink->setRemoteDetails(connection, offer->media[stream]->desc.port);
+ // The type of this stream is just unknown to us, we can not accept it
+ mImplPriv->mStreams.erase(boost::lexical_cast<std::string>(stream));
+ newStreams.erase(boost::lexical_cast<std::string>(stream));
+ continue;
}
- catch (const InvalidAddress&)
+
+ // If the state changed we need to notify the controller if one is around
+ if (oldState != ourStream->state)
{
- pjsip_tx_data *packet;
- if (pjsip_inv_end_session(mImplPriv->mInviteSession, 488, NULL, &packet) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
- }
- return 0;
+ streamsChanged.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream->state));
}
}
@@ -3571,6 +3916,14 @@ RTPMediaSessionDict SipSession::getRTPMediaSessions()
}
/**
+ * Internal function which returns the UDPTL media sessions that are hidden inside the SIP session.
+ */
+UDPTLMediaSessionSeq SipSession::getUDPTLMediaSessions()
+{
+ return mImplPriv->mUDPTLSessions;
+}
+
+/**
* Internal function which sets the streams explicitly.
*/
void SipSession::setStreams(const AsteriskSCF::Media::V1::StreamInformationDict& streams)
diff --git a/src/SipSession.h b/src/SipSession.h
index bb36ff5..50da5f9 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -141,6 +141,7 @@ public:
const Ice::Identity& controllerid,
const Ice::Identity& mediaid,
const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict& mediasessions,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq& udptlMediaSessions,
const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
const PJSipManagerPtr& manager,
@@ -331,6 +332,8 @@ public:
AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict getRTPMediaSessions();
+ AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq getUDPTLMediaSessions();
+
void enqueueSessionWork(const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkPtr&);
void setTelephonyEventSourcesAndSinks(const SipEndpointConfig& config);
@@ -355,11 +358,12 @@ private:
bool ipv6, bool isUAC, const SipEndpointConfig& config, const NATEndpointOptions& natOptions);
SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&, const Ice::Identity&,
- const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict&,
- const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
- const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const SipReplicationContextPtr& replicationContext,
- bool isUAC, const SipEndpointConfig& config, const NATEndpointOptions& natOptions);
+ const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionDict&,
+ const AsteriskSCF::Replication::SipSessionManager::V1::UDPTLMediaSessionSeq&,
+ const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
+ const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+ const SipReplicationContextPtr& replicationContext,
+ bool isUAC, const SipEndpointConfig& config, const NATEndpointOptions& natOptions);
void initializePJSIPStructs();
diff --git a/src/SipStateReplicatorListener.cpp b/src/SipStateReplicatorListener.cpp
index 168b25d..689785a 100644
--- a/src/SipStateReplicatorListener.cpp
+++ b/src/SipStateReplicatorListener.cpp
@@ -326,7 +326,8 @@ public:
// Now that all is well we can create an actual session
SipSessionPtr localSession = endpoint->createSession("", session->sessionObjectId,
session->sessionControllerObjectId,
- session->mediaSessionObjectId, session->rtpMediaSessions, session->sources, session->sinks);
+ session->mediaSessionObjectId, session->rtpMediaSessions,
+ session->udptlMediaSessions, session->sources, session->sinks);
localitem->setSession(localSession);
}
else
-----------------------------------------------------------------------
--
asterisk-scf/release/sip.git
More information about the asterisk-scf-commits
mailing list