[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 Aug 1 13:58:17 CDT 2011
branch "master" has been updated
via 1ac8012e89cb5412937c803dbb6b7451d08b297d (commit)
via 319dee0a90edc3e89106b2ac39c464f294602516 (commit)
via 685298fee308c586f5fb058740da50cf83c91847 (commit)
via 713bee189b2ce86098341723895204c3633e32a9 (commit)
from 736155bbeb65c6636154eb241939bdee6ad97947 (commit)
Summary of changes:
config/SipConfigurator.py | 5 +-
.../SipSessionManager/SipConfigurationIf.ice | 2 +-
.../SipSessionManager/SipStateReplicationIf.ice | 2 +
src/PJSipSessionModule.cpp | 180 +++--
src/PJSipSessionModule.h | 1 +
src/PJSipSessionModuleConstruction.cpp | 6 +
src/SipConfiguration.cpp | 3 +-
src/SipEndpoint.cpp | 24 +-
src/SipEndpoint.h | 5 +-
src/SipSession.cpp | 877 +++++++++++++++++---
src/SipSession.h | 31 +-
src/SipStateReplicatorListener.cpp | 2 +
12 files changed, 915 insertions(+), 223 deletions(-)
- Log -----------------------------------------------------------------
commit 1ac8012e89cb5412937c803dbb6b7451d08b297d
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Aug 1 15:36:44 2011 -0300
Throw exception instead of returning nothing.
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index 430b51a..b354d31 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -1111,7 +1111,8 @@ public:
if (mImplPriv->mSessionController)
{
- mCb->ice_response(0);
+ mCb->ice_exception(AsteriskSCF::SessionCommunications::V1::ControllerAlreadySet());
+ return Complete;
}
mImplPriv->mSessionController = mController;
commit 319dee0a90edc3e89106b2ac39c464f294602516
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Aug 1 15:26:41 2011 -0300
Remove a strange message.
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index 8dec889..65a40a2 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -1131,7 +1131,6 @@ private:
{
endpointGroup = i->second;
}
- std::cerr << "XXX wha" << std::endl;
SipEndpointPtr endpoint = mEndpointFactory->findByName(group->name);
if (!endpoint)
{
commit 685298fee308c586f5fb058740da50cf83c91847
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Aug 1 15:26:03 2011 -0300
Remove duplicate logic caused by merge.
diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 99dac9e..49a7b62 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -230,29 +230,6 @@ class SipSectionVisitors(Configurator.SectionVisitors):
self.groups.append(group)
- try:
- 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
- item.formatSpecific = [ ]
- if formatSpecific:
- item.formatSpecific.append(formatSpecific)
-
- group.configurationItems[format] = item
- except:
- traceback.print_exc()
- print 'No configured formats for endpoint ' + section
-
def visit_unsupported(self, config, section):
if config.get(section, 'type') == 'transport-udp':
self.visit_transport_udp(config, section)
commit 713bee189b2ce86098341723895204c3633e32a9
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Aug 1 14:51:02 2011 -0300
Add support for media streams and session controllers.
diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
index 2d61c7a..99dac9e 100755
--- a/config/SipConfigurator.py
+++ b/config/SipConfigurator.py
@@ -206,6 +206,28 @@ class SipSectionVisitors(Configurator.SectionVisitors):
mapper.execute(group, section, option)
mapper.finish(group)
+ try:
+ 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
+ item.formatSpecific = [ ]
+ if formatSpecific:
+ item.formatSpecific.append(formatSpecific)
+
+ group.configurationItems[format] = item
+ except:
+ print 'No configured formats for endpoint ' + section
+
self.groups.append(group)
try:
diff --git a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
index c0c85fb..715e039 100644
--- a/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/SipSessionManager/SipConfigurationIf.ice
@@ -429,7 +429,7 @@ class SipMediaFormatItem extends SipConfigurationItem
int frameSize;
/**
- * Any format specific parameters
+ * Format specific attributes.
*/
Ice::StringSeq formatSpecific;
};
diff --git a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
index 59e121c..06e7f17 100644
--- a/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/SipSessionManager/SipStateReplicationIf.ice
@@ -155,8 +155,10 @@ module V1
string mEndpointName;
Ice::Identity mSessionObjectId;
Ice::Identity mMediaSessionObjectId;
+ Ice::Identity mSessionControllerObjectId;
AsteriskSCF::Media::V1::StreamSourceSeq mSources;
AsteriskSCF::Media::V1::StreamSinkSeq mSinks;
+ AsteriskSCF::Media::V1::StreamInformationDict mStreams;
RTPMediaSessionSeq mRTPMediaSessions;
SessionListenerSeq mListeners;
AsteriskSCF::SessionCommunications::V1::Bridge *mBridge;
diff --git a/src/PJSipSessionModule.cpp b/src/PJSipSessionModule.cpp
index 90da6e7..76d0d54 100644
--- a/src/PJSipSessionModule.cpp
+++ b/src/PJSipSessionModule.cpp
@@ -23,6 +23,8 @@
#include <IceUtil/UUID.h>
+#include <boost/lexical_cast.hpp>
+
#include <AsteriskSCF/Core/Endpoint/EndpointIf.h>
#include <AsteriskSCF/Core/Routing/RoutingIf.h>
#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
@@ -100,10 +102,12 @@ void PJSipSessionModInfo::updateSessionState(pjsip_inv_session *inv_session)
mSessionState->mEndpointName = mSession->getEndpoint()->getName();
mSessionState->mSessionObjectId = mSession->getSessionProxy()->ice_getIdentity();
mSessionState->mMediaSessionObjectId = mSession->getMediaSessionProxy()->ice_getIdentity();
+ mSessionState->mSessionControllerObjectId = mSession->getOurSessionControllerProxy()->ice_getIdentity();
mSessionState->mSources = mSession->getSources();
mSessionState->mSinks = mSession->getSinks();
mSessionState->mRTPMediaSessions = mSession->getRTPMediaSessions();
mSessionState->mListeners = mSession->getListeners();
+ mSessionState->mStreams = mSession->getStreams();
try
{
mSessionState->mBridge = mSession->getBridge();
@@ -461,16 +465,17 @@ protected:
// Create an SDP offer or answer
const pjmedia_sdp_session *remote_sdp = NULL;
pjmedia_sdp_session *sdp;
+ StreamInformationDict streams;
if (!mInv->neg || (pjmedia_sdp_neg_get_neg_remote(mInv->neg, &remote_sdp) != PJ_SUCCESS))
{
// No SDP was present in the INVITE so we need to create an offer
- sdp = mSession->createSDPOffer();
+ sdp = mSession->createSDPOffer(StreamInformationDict(), streams);
}
else
{
// SDP was present in the INVITE so we need to create an answer using their offer
- sdp = mSession->createSDPAnswer(remote_sdp);
+ sdp = mSession->createSDPAnswer(remote_sdp, streams);
}
if (!sdp)
@@ -1213,6 +1218,7 @@ protected:
{
lg(Error) << "Ice exception when attempting to indicate something or other";
}
+
return Complete;
}
private:
@@ -1498,13 +1504,9 @@ void PJSipSessionModule::invOnTsxStateChanged(pjsip_inv_session *inv, pjsip_tran
}
}
-/**
- * This is the only of the PJSIP callbacks that involves no queueing.
- */
-void PJSipSessionModule::invOnRxOffer(pjsip_inv_session* inv, const pjmedia_sdp_session*)
+void PJSipSessionModule::invOnRxOffer(pjsip_inv_session*, const pjmedia_sdp_session*)
{
- PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)inv->mod_data[mModule.id];
- pjsip_inv_set_sdp_answer(inv, session_mod_info->getSessionPtr()->createSDPOffer());
+ //stub
}
void PJSipSessionModule::invOnCreateOffer(pjsip_inv_session*, pjmedia_sdp_session**)
@@ -1536,77 +1538,9 @@ protected:
PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModuleId];
SipSessionPtr session = session_mod_info->getSessionPtr();
- //
- // In case there is no stream level connection details store this away
- //
- std::string destination(pj_strbuf(&remote_sdp->conn->addr), pj_strlen(&remote_sdp->conn->addr));
- StreamSinkSeq sinks = session->getSinks();
-
- // Each stream has its own set of formats, so go to that granularity
- for (unsigned int stream = 0; stream < remote_sdp->media_count; stream++)
- {
- // Do some sanity checking to confirm we have a stream setup for their answer stream
- if (sinks.size() < (stream + 1))
- {
- continue;
- }
-
- // Assume no stream level details until proven otherwise
- std::string connection = destination;
- if (remote_sdp->media[stream]->conn)
- {
- connection = std::string(pj_strbuf(&remote_sdp->media[stream]->conn->addr),
- pj_strlen(&remote_sdp->media[stream]->conn->addr));
- }
-
- // TODO: Add parsing of RTCP attribute
-
- // The order of the media lines should match our offer so we can get the sink to update
- // connection details on based on what stream number this is, easy!
- StreamSinkRTPPrx sink = StreamSinkRTPPrx::uncheckedCast(sinks[stream]);
-
- // If this throws an exception then they answered with an address that is incompatible
- // for the session, so we abort since our relationship with the other side seems to be
- // broken
- try
- {
- sink->setRemoteDetails(connection, remote_sdp->media[stream]->desc.port);
- }
- catch (const InvalidAddress&)
- {
- pjsip_tx_data *packet;
- if (pjsip_inv_end_session(mInv, 488, NULL, &packet) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mInv, packet);
- }
- return Complete;
- }
-
- // TODO: Add format parsing stuff here so we can determine the formats actually negotiated
- }
+ StreamInformationDict added;
+ session->createSDPAnswer(remote_sdp, added);
- //
- // Assuming all of the pre-setup for the sinks/sources went ok, then we can tell
- // the session to start off any negotiated connections.
- //
- try
- {
- const pjmedia_sdp_session* local;
- pj_status_t result = pjmedia_sdp_neg_get_active_local(mInv->neg, &local);
- if (result == PJ_SUCCESS)
- {
- session->startMedia(local, remote_sdp);
- }
- }
- catch (const AsteriskSCF::Media::RTP::V1::InvalidAddress&)
- {
- pjsip_tx_data *packet;
- if (pjsip_inv_end_session(mInv, 488, NULL, &packet) == PJ_SUCCESS)
- {
- pjsip_inv_send_msg(mInv, packet);
- }
- return Complete;
- }
return Complete;
}
@@ -1646,6 +1580,96 @@ void PJSipSessionModule::authTimeout(pj_timer_heap_t *timer_heap, pj_timer_entry
mAuthManager->authTimeout(timer_heap, entry);
}
+class HandleSendReinviteResponse : public SipQueueableOperation
+{
+public:
+ HandleSendReinviteResponse(pjsip_inv_session *inv, const int moduleId, pjsip_tx_data *tdata)
+ : mInv(inv), mModuleId(moduleId), mResponse(tdata) { }
+
+protected:
+ SuspendableWorkResult initial(const SuspendableWorkListenerPtr&)
+ {
+ PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModuleId];
+ SipSessionPtr session = session_mod_info->getSessionPtr();
+ SessionControllerPrx controller = session->getSessionControllerProxy();
+
+ // If we have no session controller respond to the reinvite with the same SDP that we previously had
+ if (!controller)
+ {
+ pjsip_inv_set_sdp_answer(mInv, session->modifySDP(StreamInformationDict()));
+ pjsip_inv_send_reinvite_response(mInv, mResponse);
+ return Complete;
+ }
+
+ const pjmedia_sdp_session *offer_sdp;
+ pj_status_t status;
+ if ((status = pjmedia_sdp_neg_get_neg_remote(mInv->neg, &offer_sdp)) != PJ_SUCCESS)
+ {
+ return Complete;
+ }
+
+ // Call into the session for the serious work
+ session->createSDPAnswer(offer_sdp, mStreamsAdded);
+
+ // If no streams were added we can respond to the offer with the SDP we had previously and move on
+ if (mStreamsAdded.empty())
+ {
+ pjsip_inv_set_sdp_answer(mInv, session->modifySDP(StreamInformationDict()));
+ pjsip_inv_send_reinvite_response(mInv, mResponse);
+ return Complete;
+ }
+
+ // If any streams were added we need to call into the session controller to see what ones
+ // we can actually accept
+ SipAMICallbackPtr cb(new SipAMICallback(0, session, this, false, true));
+ Ice::CallbackPtr d = Ice::newCallback(cb, &SipAMICallback::callback);
+ session->getSessionControllerProxy()->begin_addStreams(mStreamsAdded, d);
+
+ return Complete;
+ }
+
+ SuspendableWorkResult calledBack(const Ice::AsyncResultPtr& asyncResult)
+ {
+ SessionControllerPrx controller = SessionControllerPrx::uncheckedCast(asyncResult->getProxy());
+ StreamInformationDict accepted = controller->end_addStreams(asyncResult);
+
+ // Remove any streams that were accepted by the session controller, we don't need to do anything
+ // more with them since our initial call to createSDPAnswer will have created the proper SDP
+ for (StreamInformationDict::iterator stream = accepted.begin();
+ stream != accepted.end();
+ ++stream)
+ {
+ mStreamsAdded.erase(stream->first);
+ }
+
+ // We do have to modify the SDP though to remove the streams that were not accepted
+ PJSipSessionModInfo *session_mod_info = (PJSipSessionModInfo*)mInv->mod_data[mModuleId];
+ SipSessionPtr session = session_mod_info->getSessionPtr();
+
+ // Note that this is not a mistake, mStreamsAdded now contains all the streams that were
+ // actually not accepted so we are removing them from the SDP
+ const pjmedia_sdp_session *sdp = session->modifySDP(mStreamsAdded);
+
+ // Since that is now done we can set this new SDP as our answer and send a response to the reinvite
+ pjsip_inv_set_sdp_answer(mInv, sdp);
+ pjsip_inv_send_reinvite_response(mInv, mResponse);
+
+ return Complete;
+ }
+
+private:
+ pjsip_inv_session *mInv;
+ const int mModuleId;
+ pjsip_tx_data *mResponse;
+ StreamInformationDict mStreamsAdded;
+};
+
+void PJSipSessionModule::invOnSendReinviteResponse(pjsip_inv_session* inv, pjsip_tx_data* tdata)
+{
+ lg(Debug) << "Queuing HandleSendReinviteResponse";
+ enqueueSessionWork(new HandleSendReinviteResponse(inv, mModule.id, tdata), inv);
+}
+
QueuePtr PJSipSessionModule::getThreadPoolQueue()
{
return mPoolQueue;
diff --git a/src/PJSipSessionModule.h b/src/PJSipSessionModule.h
index 79b0212..3f9ed89 100644
--- a/src/PJSipSessionModule.h
+++ b/src/PJSipSessionModule.h
@@ -126,6 +126,7 @@ public:
void invOnMediaUpdate(pjsip_inv_session *inv, pj_status_t status);
pjsip_redirect_op invOnRedirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e);
pjsip_dialog *uaOnDialogForked(pjsip_dialog *first_set, pjsip_rx_data *rdata);
+ void invOnSendReinviteResponse(pjsip_inv_session *inv, pjsip_tx_data *tdata);
// Missing onsendack for now
void authTimeout(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
void replicateState(PJSipDialogModInfo *dlgInfo, PJSipTransactionModInfo *tsxInfo,
diff --git a/src/PJSipSessionModuleConstruction.cpp b/src/PJSipSessionModuleConstruction.cpp
index adcbb8a..7d86a95 100644
--- a/src/PJSipSessionModuleConstruction.cpp
+++ b/src/PJSipSessionModuleConstruction.cpp
@@ -113,6 +113,11 @@ void sessionAuthTimeout(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entr
return sessionModule->authTimeout(timer_heap, entry);
}
+static void invOnSendReinviteResponse(pjsip_inv_session *inv, pjsip_tx_data *tdata)
+{
+ return sessionModule->invOnSendReinviteResponse(inv, tdata);
+}
+
PJSipSessionModule::PJSipSessionModule(pjsip_endpoint *endpt,
const boost::shared_ptr<SipEndpointFactory>& endpointFactoryPtr,
const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::SessionCommunications::V1::SessionRouterPrx>& sessionRouter,
@@ -169,6 +174,7 @@ PJSipSessionModule::PJSipSessionModule(pjsip_endpoint *endpt,
mInvCallback.on_media_update = AsteriskSCF::SipSessionManager::invOnMediaUpdate;
//mInvCallback.on_send_ack = invOnSendAck;
mInvCallback.on_redirected = AsteriskSCF::SipSessionManager::invOnRedirected;
+ mInvCallback.on_send_reinvite_response = AsteriskSCF::SipSessionManager::invOnSendReinviteResponse;
}
pjsip_tsx_layer_init_module(endpt);
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index b710c35..8dec889 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -189,7 +189,7 @@ class EndpointConfigHelper : public boost::enable_shared_from_this<EndpointConfi
{
mUpdates.push_back(boost::bind(&EndpointConfigHelper::updateDirection, mConfig, direction));
}
-
+
void visitSipMediaFormatItem(const SipMediaFormatItemPtr& format)
{
mUpdates.push_back(boost::bind(&EndpointConfigHelper::addFormat, mConfig, format));
diff --git a/src/SipEndpoint.cpp b/src/SipEndpoint.cpp
index 8c5465a..624da0c 100644
--- a/src/SipEndpoint.cpp
+++ b/src/SipEndpoint.cpp
@@ -21,10 +21,11 @@
#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
#include <AsteriskSCF/logger.h>
-#include "NATOptions.h"
#include <AsteriskSCF/Media/MediaIf.h>
#include <AsteriskSCF/Media/SDP/MediaSDPIf.h>
+#include "NATOptions.h"
+
using namespace AsteriskSCF::System::Logging;
using namespace AsteriskSCF::Media::V1;
using namespace AsteriskSCF::Media::SDP::V1;
@@ -370,6 +371,7 @@ AsteriskSCF::SessionCommunications::V1::SessionPrx SipEndpoint::createSession(co
mImplPriv->mServiceLocator, mImplPriv->mReplica, mImplPriv->mConfig.sessionConfig.rtpOverIPv6, true,
NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
mImplPriv->mConfig.transportConfig.enableNAT));
+
mImplPriv->mSessions.push_back(session);
std::cout << "And now we're returing a session proxy..." << std::endl;
return session->getSessionProxy();
@@ -382,17 +384,19 @@ AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const s
NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
mImplPriv->mConfig.transportConfig.enableNAT)
);
+
mImplPriv->mSessions.push_back(session);
return session;
}
AsteriskSCF::SipSessionManager::SipSessionPtr SipEndpoint::createSession(const std::string& destination,
- const Ice::Identity& sessionid, const Ice::Identity& mediaid,
+ const Ice::Identity& sessionid, const Ice::Identity& controllerid,
+ const Ice::Identity& mediaid,
const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
const AsteriskSCF::Media::V1::StreamSourceSeq& sources,
const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
{
- SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, mediaid, mediasessions,
+ SipSessionPtr session = new SipSession(mImplPriv->mAdapter, this, destination, sessionid, controllerid, mediaid, mediasessions,
sources, sinks, mImplPriv->mManager, mImplPriv->mServiceLocator, mImplPriv->mReplica, false,
NATEndpointOptions(mImplPriv->mConfig.sessionConfig.rtpOverICE, mImplPriv->mConfig.sessionConfig.rtpICEIncludeTURN,
mImplPriv->mConfig.transportConfig.enableNAT));
@@ -478,9 +482,9 @@ SDPDescriptorPtr SipEndpoint::getDescriptor(const FormatPtr& format)
return 0;
}
-StreamTopologyMap SipEndpoint::getStreamTopology()
+StreamInformationDict SipEndpoint::getStreamTopology()
{
- StreamTopologyMap topology;
+ StreamInformationDict topology;
// Iterate through all the configured formats placing the same types on the same stream
for (std::vector<ConfiguredFormatPtr>::const_iterator configuredFormat = mImplPriv->mFormats.begin();
@@ -488,19 +492,19 @@ StreamTopologyMap SipEndpoint::getStreamTopology()
++configuredFormat)
{
// See if a stream already exists for this type
- StreamTopologyMap::iterator stream = topology.find((*configuredFormat)->getDescriptor()->type);
+ StreamInformationDict::iterator stream = topology.find((*configuredFormat)->getDescriptor()->type);
if (stream == topology.end())
{
// If one does not exist we have to create it and add it to the map
- FormatSeq formats;
- formats.push_back((*configuredFormat)->getFormat());
- topology.insert(make_pair((*configuredFormat)->getDescriptor()->type, formats));
+ StreamInformationPtr newStream = new StreamInformation();
+ newStream->formats.push_back((*configuredFormat)->getFormat());
+ topology.insert(make_pair((*configuredFormat)->getDescriptor()->type, newStream));
}
else
{
// If one does exist we can simply add the format to it
- stream->second.push_back((*configuredFormat)->getFormat());
+ stream->second->formats.push_back((*configuredFormat)->getFormat());
}
}
diff --git a/src/SipEndpoint.h b/src/SipEndpoint.h
index 2ce13ff..a0657d5 100644
--- a/src/SipEndpoint.h
+++ b/src/SipEndpoint.h
@@ -298,7 +298,7 @@ public:
// dependency insanity
//
AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&);
- AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&, const Ice::Identity&,
+ AsteriskSCF::SipSessionManager::SipSessionPtr createSession(const std::string&, const Ice::Identity&, const Ice::Identity&,
const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq&,
const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&);
@@ -330,11 +330,10 @@ public:
/**
* API call which returns the stream topology to be used for an SDP offer.
*/
- StreamTopologyMap getStreamTopology();
-
void setMediaNATOptions(bool useICE, bool useTURN);
void setSRTPOptions(const SipEndpointMediaSRTPConfig& srtpConfig);
void setSignalingNATOptions(bool enable);
+ AsteriskSCF::Media::V1::StreamInformationDict getStreamTopology();
private:
/**
diff --git a/src/SipSession.cpp b/src/SipSession.cpp
index fd5758e..430b51a 100755
--- a/src/SipSession.cpp
+++ b/src/SipSession.cpp
@@ -29,6 +29,8 @@
#include <AsteriskSCF/System/WorkQueue/WorkQueueIf.h>
#include <AsteriskSCF/logger.h>
#include <AsteriskSCF/System/NAT/NATTraversalIf.h>
+#include <AsteriskSCF/Media/MediaIf.h>
+#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
#include <AsteriskSCF/Media/SDP/MediaSDPIf.h>
#include "NATOptions.h"
@@ -98,8 +100,7 @@ public:
const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
const NATEndpointOptions& natOptions)
: mAdapter(adapter), mDialog(0), mInviteSession(0), mEndpoint(endpoint), mDestination(destination),
- mManager(manager), mServiceLocator(serviceLocator), mReplica(replica), mNatOptions(natOptions), mSDP(0),
- mSDPFinalized(false)
+ mManager(manager), mServiceLocator(serviceLocator), mReplica(replica), mNatOptions(natOptions), mSDP(0)
{
}
@@ -197,6 +198,16 @@ public:
AsteriskSCF::Media::V1::SessionPrx mMediaSessionProxy;
/**
+ * An instance of a session controller.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPtr mOurSessionController;
+
+ /**
+ * A proxy to our own session controller.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx mOurSessionControllerProxy;
+
+ /**
* A proxy to this communications session.
*/
AsteriskSCF::SessionCommunications::V1::SessionPrx mSessionProxy;
@@ -282,9 +293,30 @@ public:
pjmedia_sdp_session *mSDP;
/**
- * Whether the SDP has been finalized or not.
+ * Streams present on the session.
*/
- bool mSDPFinalized;
+ StreamInformationDict mStreams;
+
+ /**
+ * Newly added streams that are awaiting a response from the remote party on acceptance.
+ */
+ StreamInformationDict mNewStreams;
+
+ /**
+ * A proxy to the SessionController we are controlling.
+ */
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx mSessionController;
+
+ /**
+ * A pointer to the callback class used to send a response to the SessionController with which streams
+ * have been added.
+ */
+ AsteriskSCF::SessionCommunications::V1::AMD_SessionController_addStreamsPtr mAddStreamsCb;
+
+ /**
+ * A mapping for requested stream identifier to our stream identifier.
+ */
+ std::map<std::string, std::string> mAddStreamsMapping;
};
/**
@@ -296,10 +328,266 @@ inline T *allocate_from_pool(pj_pool_t *pool)
return static_cast<T*>(pj_pool_zalloc(pool, sizeof(T)));
}
+class ChangeStreamStatesOperation : public SuspendableWork
+{
+public:
+ ChangeStreamStatesOperation(
+ const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_changeStreamStatesPtr& cb,
+ const AsteriskSCF::Media::V1::StreamStateDict& streams,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv)
+ : mCb(cb), mStreams(streams), mImplPriv(sessionPriv) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing a changeStreamStates Operation";
+
+ // This boolean is set to true if at least one stream is actually changed. This is to prevent
+ // needless reinvites.
+ bool changed = false;
+
+ // We iterate through each stream making sure we have one that matches it
+ for (AsteriskSCF::Media::V1::StreamStateDict::const_iterator stream = mStreams.begin();
+ stream != mStreams.end();
+ ++stream)
+ {
+ AsteriskSCF::Media::V1::StreamInformationDict::iterator ourStream = mImplPriv->mStreams.find(stream->first);
+
+ // If we don't have a stream stored locally then they gave us a stream that we really know nothing about it
+ if (ourStream == mImplPriv->mStreams.end())
+ {
+ continue;
+ }
+
+ // If this doesn't actually alter the state of the stream do nothing, since it would just be silly
+ if (ourStream->second->state == stream->second)
+ {
+ continue;
+ }
+
+ // The implementation of how we store streams and SDP are linked together, if we can find a stream
+ // in our dictionary of streams than it also exists in the SDP
+ pjmedia_sdp_media *media = mImplPriv->mSDP->media[boost::lexical_cast<int>(stream->first)];
+
+ // Depending on the current state go ahead and remove the current attribute
+ if (ourStream->second->state == SendAndReceive)
+ {
+ pjmedia_sdp_media_remove_all_attr(media, "sendrecv");
+ }
+ else if (ourStream->second->state == SendOnly)
+ {
+ pjmedia_sdp_media_remove_all_attr(media, "sendonly");
+ }
+ else if (ourStream->second->state == ReceiveOnly)
+ {
+ pjmedia_sdp_media_remove_all_attr(media, "recvonly");
+ }
+ else if (ourStream->second->state == Inactive)
+ {
+ pjmedia_sdp_media_remove_all_attr(media, "inactive");
+ }
+
+ // Now that the old attribute is removed we can go ahead and update our state
+ ourStream->second->state = stream->second;
+
+ // Now we can go ahead and add in the corret attribute
+ pjmedia_sdp_attr *attr = NULL;
+
+ if (ourStream->second->state == SendAndReceive)
+ {
+ attr = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "sendrecv", NULL);
+ }
+ else if (ourStream->second->state == SendOnly)
+ {
+ attr = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "sendonly", NULL);
+ }
+ else if (ourStream->second->state == ReceiveOnly)
+ {
+ attr = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "recvonly", NULL);
+ }
+ else if (ourStream->second->state == Inactive)
+ {
+ attr = pjmedia_sdp_attr_create(mImplPriv->mDialog->pool, "inactive", NULL);
+ }
+
+ if (attr)
+ {
+ pjmedia_sdp_media_add_attr(media, attr);
+ changed = true;
+ }
+ }
+
+ // If any streams were actually updated trigger a reinvite if need be
+ if (changed == true)
+ {
+ // TODO: Add code here to determine if we really do need to send the reinvite, if we haven't actually answered yet
+ // what we really want to do is just update our answer SDP
+ pjsip_tx_data *packet = NULL;
+
+ if ((pjsip_inv_reinvite(mImplPriv->mInviteSession, NULL, mImplPriv->mSDP, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
+ }
+ }
+
+ mCb->ice_response();
+
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_SessionController_changeStreamStatesPtr mCb;
+ AsteriskSCF::Media::V1::StreamStateDict mStreams;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+};
+
+class AddStreamsOperation : public SuspendableWork
+{
+public:
+ AddStreamsOperation(
+ const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_addStreamsPtr& cb,
+ const AsteriskSCF::Media::V1::StreamInformationDict& streams,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv,
+ const SipSessionPtr& session)
+ : mCb(cb), mStreams(streams), mImplPriv(sessionPriv), mSession(session) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing an addStreams Operation";
+
+ // If there is an outstanding transaction then no streams can be added at this time
+ if (mImplPriv->mInviteSession->invite_tsx)
+ {
+ mCb->ice_response(StreamInformationDict());
+ return Complete;
+ }
+
+ // Create an offer adding in the requested streams
+ StreamInformationDict added;
+ pjmedia_sdp_session *sdp = mSession->createSDPOffer(mStreams, added);
+
+ // If no streams were actually added respond back appropriately
+ if (added.empty())
+ {
+ mCb->ice_response(StreamInformationDict());
+ return Complete;
+ }
+
+ // Store callback information so when the remote party responds with which streams were accepted we can
+ // communicate it to the controller
+ mImplPriv->mAddStreamsCb = mCb;
+
+ // Okay, create and send the reinvite!
+ pjsip_tx_data *packet = NULL;
+
+ if ((pjsip_inv_reinvite(mImplPriv->mInviteSession, NULL, sdp, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
+ }
+ else
+ {
+ // If we couldn't create the reinvite no streams were added
+ mCb->ice_response(StreamInformationDict());
+ }
+
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_SessionController_addStreamsPtr mCb;
+ AsteriskSCF::Media::V1::StreamInformationDict mStreams;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+ SipSessionPtr mSession;
+};
+
+class RemoveStreamsOperation : public SuspendableWork
+{
+public:
+ RemoveStreamsOperation(
+ const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_removeStreamsPtr& cb,
+ const AsteriskSCF::Media::V1::StreamInformationDict& streams,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv,
+ const SipSessionPtr& session)
+ : mCb(cb), mStreams(streams), mImplPriv(sessionPriv), mSession(session) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing a removeStreams Operation";
+
+ pjmedia_sdp_session *sdp = mSession->modifySDP(mStreams);
+
+ // If there is an outstanding transaction just set this as the answer SDP, otherwise trigger a reinvite
+ if (!mImplPriv->mInviteSession->invite_tsx)
+ {
+ pjsip_tx_data *packet = NULL;
+
+ if ((pjsip_inv_reinvite(mImplPriv->mInviteSession, NULL, mImplPriv->mSDP, &packet)) == PJ_SUCCESS)
+ {
+ pjsip_inv_send_msg(mImplPriv->mInviteSession, packet);
+ }
+ }
+ else
+ {
+ pjsip_inv_set_sdp_answer(mImplPriv->mInviteSession, sdp);
+ }
+
+ mCb->ice_response();
+
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_SessionController_removeStreamsPtr mCb;
+ AsteriskSCF::Media::V1::StreamInformationDict mStreams;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+ SipSessionPtr mSession;
+};
+
+/**
+ * Implementation of a SessionController interface for the SipSession.
+ */
+class SipSessionController : public AsteriskSCF::SessionCommunications::V1::SessionController
+{
+public:
+ SipSessionController(boost::shared_ptr<SipSessionPriv> implPriv, const SipSessionPtr& session) :
+ mImplPriv(implPriv), mSession(session) { }
+
+ void changeStreamStates_async(const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_changeStreamStatesPtr& cb,
+ const AsteriskSCF::Media::V1::StreamStateDict& states, const Ice::Current&)
+ {
+ lg(Debug) << "Queueing changeStreamStates operation";
+ mSession->enqueueSessionWork(new ChangeStreamStatesOperation(cb, states, mImplPriv));
+ }
+
+ void addStreams_async(const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_addStreamsPtr& cb,
+ const AsteriskSCF::Media::V1::StreamInformationDict& streams, const Ice::Current&)
+ {
+ lg(Debug) << "Queueing addStreams operation";
+ mSession->enqueueSessionWork(new AddStreamsOperation(cb, streams, mImplPriv, mSession));
+ }
+
+ void removeStreams_async(const AsteriskSCF::SessionCommunications::V1::AMD_SessionController_removeStreamsPtr& cb,
+ const AsteriskSCF::Media::V1::StreamInformationDict& streams, const Ice::Current&)
+ {
+ lg(Debug) << "Queueing removeStreams operation";
+ mSession->enqueueSessionWork(new RemoveStreamsOperation(cb, streams, mImplPriv, mSession));
+ }
+
+private:
+ /**
+ * Private implementation details for SipSession.
+ */
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+
+ /**
+ * A pointer to the communications session that created us.
+ */
+ SipSessionPtr mSession;
+};
+
void SipSession::initializePJSIPStructs()
{
SipEndpointConfig& config = mImplPriv->mEndpoint->getConfig();
-
+
std::string prefix;
if (config.transportConfig.secureTransport == OUTBOUND || config.transportConfig.secureTransport == BOTH)
{
@@ -399,7 +687,8 @@ void SipSession::initializePJSIPStructs()
pjsip_inv_session *inviteSession;
// Create an SDP offer based on what is configured
- pjmedia_sdp_session *sdp = createSDPOffer();
+ StreamInformationDict added;
+ pjmedia_sdp_session *sdp = createSDPOffer(StreamInformationDict(), added);
if ((pjsip_inv_create_uac(dialog, sdp, 0, &inviteSession)) != PJ_SUCCESS)
{
@@ -476,6 +765,10 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
mImplPriv->mMediaSessionProxy =
AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(adapter->addWithUUID(mImplPriv->mMediaSession));
+ mImplPriv->mOurSessionController = new SipSessionController(mImplPriv, this);
+ mImplPriv->mOurSessionControllerProxy =
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx::uncheckedCast(adapter->addWithUUID(mImplPriv->mOurSessionController));
+
if (isUAC)
{
lg(Debug) << "New session is UAC, so we're creating the necessary PJSIP structures";
@@ -487,11 +780,12 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
* Replica constructor.
*/
SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPtr& endpoint,
- const std::string& destination, const Ice::Identity& /* sessionid */,
- const Ice::Identity& mediaid, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
- const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
- const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
- const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool isUAC, const NATEndpointOptions& natOptions)
+ const std::string& destination, const Ice::Identity& /* sessionid */,
+ const Ice::Identity& controllerid,
+ const Ice::Identity& mediaid, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq& mediasessions,
+ const AsteriskSCF::Media::V1::StreamSourceSeq& sources, const AsteriskSCF::Media::V1::StreamSinkSeq& sinks,
+ const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
+ const AsteriskSCF::System::Component::V1::ReplicaPtr& replica, bool isUAC, const NATEndpointOptions& natOptions)
: mImplPriv(new SipSessionPriv(adapter, endpoint, destination, manager, serviceLocator, replica, natOptions))
{
activateIceObjects(mImplPriv->mManager->getSessionModule()->getSessionCreationHooks());
@@ -500,6 +794,10 @@ SipSession::SipSession(const Ice::ObjectAdapterPtr& adapter, const SipEndpointPt
mImplPriv->mMediaSessionProxy =
AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(adapter->add(mImplPriv->mMediaSession, mediaid));
+ mImplPriv->mOurSessionController = new SipSessionController(mImplPriv, this);
+ mImplPriv->mOurSessionControllerProxy =
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx::uncheckedCast(adapter->add(mImplPriv->mOurSessionController, controllerid));
+
mImplPriv->mRTPSessions = mediasessions;
mImplPriv->mSources = sources;
mImplPriv->mSinks = sinks;
@@ -769,6 +1067,115 @@ void SipSession::getBridge_async(
enqueueSessionWork(new GetBridgeOperation(cb, mImplPriv));
}
+class GetStreamsOperation : public SuspendableWork
+{
+public:
+ GetStreamsOperation(const AsteriskSCF::SessionCommunications::V1::AMD_Session_getStreamsPtr& cb,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv)
+ : mCb(cb), mImplPriv(sessionPriv) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing a GetStreams operation";
+ mCb->ice_response(mImplPriv->mStreams);
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_Session_getStreamsPtr mCb;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+};
+
+/**
+ * An implementation of the getStreams method as defined in SessionCommunications.ice
+ */
+void SipSession::getStreams_async(
+ const AsteriskSCF::SessionCommunications::V1::AMD_Session_getStreamsPtr& cb,
+ const Ice::Current&)
+{
+ lg(Debug) << "queuing a getStreams operation";
+ enqueueSessionWork(new GetStreamsOperation(cb, mImplPriv));
+}
+
+class SetAndGetSessionControllerOperation : public SuspendableWork
+{
+public:
+ SetAndGetSessionControllerOperation(const AsteriskSCF::SessionCommunications::V1::AMD_Session_setAndGetSessionControllerPtr& cb,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& controller,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv)
+ : mCb(cb), mController(controller), mImplPriv(sessionPriv) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing a SetAndGetSessionController operation";
+
+ if (mImplPriv->mSessionController)
+ {
+ mCb->ice_response(0);
+ }
+
+ mImplPriv->mSessionController = mController;
+ mCb->ice_response(mImplPriv->mOurSessionControllerProxy);
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_Session_setAndGetSessionControllerPtr mCb;
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx mController;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+};
+
+/**
+ * An implementation of the setAndGetSessionController method as defined in SessionCommunications.ice
+ */
+void SipSession::setAndGetSessionController_async(
+ const AsteriskSCF::SessionCommunications::V1::AMD_Session_setAndGetSessionControllerPtr& cb,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& controller,
+ const Ice::Current&)
+{
+ lg(Debug) << "queueing a setAndGetSessionController operation";
+ enqueueSessionWork(new SetAndGetSessionControllerOperation(cb, controller, mImplPriv));
+}
+
+class RemoveSessionControllerOperation : public SuspendableWork
+{
+public:
+ RemoveSessionControllerOperation(const AsteriskSCF::SessionCommunications::V1::AMD_Session_removeSessionControllerPtr& cb,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& controller,
+ const boost::shared_ptr<SipSessionPriv>& sessionPriv)
+ : mCb(cb), mController(controller), mImplPriv(sessionPriv) { }
+
+ SuspendableWorkResult execute(const SuspendableWorkListenerPtr&)
+ {
+ lg(Debug) << "Executing a RemoveSessionController operation";
+
+ if (mImplPriv->mSessionController == mController)
+ {
+ mImplPriv->mSessionController = 0;
+ }
+
+ mCb->ice_response();
+ return Complete;
+ }
+
+private:
+ AsteriskSCF::SessionCommunications::V1::AMD_Session_removeSessionControllerPtr mCb;
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx mController;
+ boost::shared_ptr<SipSessionPriv> mImplPriv;
+};
+
+
+/**
+ * An implementation of the removeSessionController method as defined in SessionCommunications.ice
+ */
+void SipSession::removeSessionController_async(const AsteriskSCF::SessionCommunications::V1::AMD_Session_removeSessionControllerPtr& cb,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& controller,
+ const Ice::Current&)
+{
+ lg(Debug) << "queueing a removeSessionController operation";
+ enqueueSessionWork(new RemoveSessionControllerOperation(cb, controller, mImplPriv));
+}
+
class SetBridgeOperation : public SuspendableWork
{
public:
@@ -1302,6 +1709,7 @@ pjmedia_sdp_session *SipSession::createSDP()
}
sdp->name = sdp->origin.user;
+
return sdp;
}
@@ -1381,21 +1789,21 @@ void SipSession::addFormatstoSDP(const FormatSeq& formats, pjmedia_sdp_media *me
}
/**
- * Internal function called to produce an SDP session structure using configuration.
+ * Internal function called to produce an SDP session structure using configuration and provided streams
*/
-pjmedia_sdp_session *SipSession::createSDPOffer()
+pjmedia_sdp_session *SipSession::createSDPOffer(const AsteriskSCF::Media::V1::StreamInformationDict& streams,
+ AsteriskSCF::Media::V1::StreamInformationDict& newStreams)
{
- // If SDP has already been produced then just return it, don't recreate it
- if (mImplPriv->mSDPFinalized == true)
+ StreamInformationDict requestedStreams = streams;
+
+ // If no streams have been provided use a generate topology from the endpoint based on configured formats
+ if (requestedStreams.empty())
{
- return mImplPriv->mSDP;
+ requestedStreams = mImplPriv->mEndpoint->getStreamTopology();
}
- // Retrieve the stream topology from the endpoint
- StreamTopologyMap streams = mImplPriv->mEndpoint->getStreamTopology();
-
- // If there are no streams then we can not create an SDP offer
- if (streams.empty())
+ // If we still have no streams we can not produce an SDP as it would be broken
+ if (requestedStreams.empty())
{
return 0;
}
@@ -1406,30 +1814,41 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
mImplPriv->mSDP = createSDP();
}
- SipEndpointConfig config = mImplPriv->mEndpoint->getConfig();
-
- // Iterate through each stream present in the topology
- for (StreamTopologyMap::const_iterator stream = streams.begin();
- stream != streams.end();
+ // Iterate through each requested stream
+ for (StreamInformationDict::const_iterator stream = requestedStreams.begin();
+ stream != requestedStreams.end();
++stream)
{
- RTPServiceLocatorParamsPtr params;
- if (mImplPriv->mNatOptions.enableICE)
+ // Remove any provided values that we will overwrite
+ stream->second->sources.clear();
+ stream->second->sinks.clear();
+
+ // Determine the actual formats we can handle
+ FormatSeq formats;
+
+ for (FormatSeq::const_iterator format = stream->second->formats.begin();
+ format != stream->second->formats.end();
+ ++format)
{
- AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
- new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
- params = iceParams;
- iceParams->enableRTPOverICE = true;
- iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
+ if (mImplPriv->mEndpoint->getDescriptor(*format) != 0)
+ {
+ formats.push_back(*format);
+ }
}
- else
+
+ // If no compatible formats were provided skip this stream
+ if (formats.empty())
{
- params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
+ continue;
}
+
+ // Update the stream with the actual formats
+ stream->second->formats = formats;
+
+ RTPServiceLocatorParamsPtr params = new RTPServiceLocatorParams();
params->category = "rtp";
- params->formats = stream->second;
- params->ipv6 = config.sessionConfig.rtpOverIPv6;
- params->srtpCapable = (!config.srtpConfig.cryptoKeys.empty());
+ 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));
@@ -1453,27 +1872,27 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
// 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);
// Update the SIP session with some RTP session details
mImplPriv->mRTPSessions.push_back(session);
// Add the stream to the SDP
pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
- mImplPriv->mSDP->media[mImplPriv->mSDP->media_count++] = media;
- pj_strdup2(mImplPriv->mDialog->pool, &media->desc.media, mImplPriv->mEndpoint->getDescriptor(stream->second.front())->type.c_str());
- if (config.srtpConfig.cryptoKeys.empty())
- {
- pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/AVP");
- }
- else
- {
- pj_strdup2(mImplPriv->mDialog->pool, &media->desc.transport, "RTP/SAVP");
- }
+ // 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());
+
+ // 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);
@@ -1502,31 +1921,33 @@ pjmedia_sdp_session *SipSession::createSDPOffer()
PayloadMap payloads;
// Add all of the formats to the SDP
- addFormatstoSDP(stream->second, media, payloads);
+ addFormatstoSDP(stream->second->formats, media, payloads);
// Push the payload mapping to the RTP session so it'll correctly map things
session->associatePayloads(payloads);
- addKeys(mImplPriv->mEndpoint->getConfig().srtpConfig, media);
+ // Make the caller aware of this new stream
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), stream->second));
+
+ // Since this is a newly added stream record it as such until the remote party accepts or declines it
+ mImplPriv->mNewStreams.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), stream->second));
+
+ // Create a mapping so if we need to respond to an addStreams request they will get their own identifier back
+ mImplPriv->mAddStreamsMapping.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count), stream->first));
- // The SDP has been finalized enough
- mImplPriv->mSDPFinalized = true;
+ // Now that all is done we can add this stream in
+ mImplPriv->mStreams.insert(make_pair(boost::lexical_cast<std::string>(mImplPriv->mSDP->media_count++), stream->second));
}
- return mImplPriv->mSDPFinalized == true ? mImplPriv->mSDP : 0;
+ return mImplPriv->mSDP;
}
/**
* Internal function called to produce an SDP session structure using configuration and an SDP offer.
*/
-pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offer)
+pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offer,
+ AsteriskSCF::Media::V1::StreamInformationDict& newStreams)
{
- // If SDP has already been produced then just return it, don't recreate it
- if (mImplPriv->mSDPFinalized == true)
- {
- return mImplPriv->mSDP;
- }
-
// Create the most common part of the SDP if not already done
if (!mImplPriv->mSDP)
{
@@ -1536,9 +1957,54 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
// Get the non-stream level connection information in case there is no connection level one
std::string destination(pj_strbuf(&offer->conn->addr), pj_strlen(&offer->conn->addr));
+ // A dictionary containing streams that have been added to the session
+ StreamInformationDict streamsAdded;
+
+ // A dictionary containing streams that have been removed from the session
+ StreamInformationDict streamsRemoved;
+
+ // A dictionary containing streams and their new state
+ StreamStateDict streamsChanged;
+
// Iterate through each stream seeing if we are configured to support at least one format they have
for (unsigned int stream = 0; stream < offer->media_count; stream++)
{
+ // Determine if this is a new stream or an existing stream
+ StreamInformationDict::iterator existingStream = mImplPriv->mStreams.find(boost::lexical_cast<std::string>(stream));
+ StreamInformationPtr ourStream;
+
+ if (existingStream == mImplPriv->mStreams.end())
+ {
+ // This follows an optimistic approach where it is believed that any offered stream will be accepted
+ ourStream = new StreamInformation();
+ mImplPriv->mStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ newStreams.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ }
+ else
+ {
+ ourStream = existingStream->second;
+ }
+
+ // Examine the port number to determine if this stream has been removed
+ if (!offer->media[stream]->desc.port)
+ {
+ ourStream->state = Removed;
+ streamsRemoved.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream));
+ continue;
+ }
+
+ // If this is a newly added stream we may need to notify a session controller that it was accepted
+ if (mImplPriv->mNewStreams.find(boost::lexical_cast<std::string>(stream)) != mImplPriv->mNewStreams.end())
+ {
+ // We need to return a StreamInformationDict with their identifier so they can correctly associate it
+ std::map<std::string, std::string>::const_iterator mapping = mImplPriv->mAddStreamsMapping.find(
+ boost::lexical_cast<std::string>(stream));
+ if (mapping != mImplPriv->mAddStreamsMapping.end())
+ {
+ streamsAdded.insert(make_pair(mapping->second, ourStream));
+ }
+ }
+
// If a format is actually found we add it to this sequence so we can create an RTP session
FormatSeq formats;
@@ -1629,9 +2095,16 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
// If no formats were found on this stream that we are configured with then move on to the next one
if (formats.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;
}
+ // Update the stream with the formats
+ ourStream->formats = formats;
+
// Assume that no connection level details exist until proven otherwise
std::string connection = destination;
if (offer->media[stream]->conn)
@@ -1640,100 +2113,225 @@ pjmedia_sdp_session *SipSession::createSDPAnswer(const pjmedia_sdp_session* offe
pj_strlen(&offer->media[stream]->conn->addr));
}
- RTPServiceLocatorParamsPtr params;
- if (mImplPriv->mNatOptions.enableICE)
+ // 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
+ {
+ 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
+ RTPSessionPrx session = factory->allocate(params);
+
+ // 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;
+ }
+
+ // 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.push_back(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;
+
+ // 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);
+ }
+
+ // 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))
{
- AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParamsPtr iceParams =
- new AsteriskSCF::Media::RTP::V1::RTPOverICEServiceLocatorParams;
- params = iceParams;
- iceParams->enableRTPOverICE = true;
- iceParams->enableTURN = mImplPriv->mNatOptions.enableTURN;
+ ourStream->state = SendOnly;
}
- else
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "recvonly", NULL))
{
- params = new AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParams;
+ ourStream->state = ReceiveOnly;
}
- 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)
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "inactive", NULL))
{
- params->ipv6 = true;
+ ourStream->state = Inactive;
}
- else
+ else if (pjmedia_sdp_media_find_attr2(offer->media[stream], "sendrecv", NULL))
{
- params->ipv6 = false;
+ ourStream->state = SendAndReceive;
}
- // 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)
+ // If the state changed we need to notify the controller if one is around
+ if (oldState != ourStream->state)
{
- continue;
+ streamsChanged.insert(make_pair(boost::lexical_cast<std::string>(stream), ourStream->state));
}
- // Allocate a new RTP session to carry the media formats we have in common
- RTPSessionPrx session = factory->allocate(params);
+ // 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
{
- continue;
+ sink->setRemoteDetails(connection, offer->media[stream]->desc.port);
+ }
+ catch (const 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;
}
+ }
- // 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());
- sink->setRemoteDetails(connection, offer->media[stream]->desc.port);
- mImplPriv->mSinks.push_back(sink);
+ if (mImplPriv->mSessionController)
+ {
+ if (!streamsRemoved.empty())
+ {
+ mImplPriv->mSessionController->removeStreams(streamsRemoved);
+ }
+ if (!streamsChanged.empty())
+ {
+ mImplPriv->mSessionController->changeStreamStates(streamsChanged);
+ }
+ }
- // Ditto goes for source
- StreamSourceRTPPrx source = StreamSourceRTPPrx::uncheckedCast(session->getSources().front());
- mImplPriv->mSources.push_back(source);
+ if (mImplPriv->mAddStreamsCb)
+ {
+ mImplPriv->mAddStreamsCb->ice_response(streamsAdded);
+ mImplPriv->mAddStreamsCb = 0;
+ }
- // Update the SIP session with some RTP session details
- mImplPriv->mRTPSessions.push_back(session);
+ startMedia(mImplPriv->mSDP, offer);
- // Add a new stream to the answer SDP
- pjmedia_sdp_media *media = allocate_from_pool<pjmedia_sdp_media>(mImplPriv->mDialog->pool);
- mImplPriv->mSDP->media[mImplPriv->mSDP->media_count++] = media;
+ mImplPriv->mNewStreams.clear();
+ mImplPriv->mAddStreamsMapping.clear();
- // 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;
+ return mImplPriv->mSDP;
+}
- // 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());
+/**
+ * Internal function which modifies our SDP.
+ */
+pjmedia_sdp_session *SipSession::modifySDP(const AsteriskSCF::Media::V1::StreamInformationDict& toRemove)
+{
+ // In order to modify SDP you have to have SDP
+ if (!mImplPriv->mSDP)
+ {
+ return 0;
+ }
- // If session level connection information has not yet been set then set it to us
- if (!mImplPriv->mSDP->conn)
+ // Iterate through each stream to remove so we can change the port number and make it go bye bye
+ for (AsteriskSCF::Media::V1::StreamInformationDict::const_iterator stream = toRemove.begin();
+ stream != toRemove.end();
+ ++stream)
+ {
+ AsteriskSCF::Media::V1::StreamInformationDict::iterator ourStream = mImplPriv->mStreams.find(stream->first);
+
+ // If we don't have a stream stored locally then they gave us a stream that we really know nothing about it
+ if (ourStream == mImplPriv->mStreams.end())
{
- mImplPriv->mSDP->conn = media->conn;
+ continue;
}
- // Add port information so they can talk to us
- media->desc.port = (pj_uint16_t) source->getLocalPort();
- media->desc.port_count = 1;
+ // If the stream has already been removed doing it again is silllly
+ if (ourStream->second->state == Removed)
+ {
+ continue;
+ }
- PayloadMap payloads;
+ ourStream->second->state = Removed;
- addFormatstoSDP(formats, media, payloads);
- addKeys(mImplPriv->mEndpoint->getConfig().srtpConfig, media);
+ // Due to our usage of the pjmedia SDP API if we have a stream on our side there *will* be a media
+ // line in the SDP
+ pjmedia_sdp_media *media = mImplPriv->mSDP->media[boost::lexical_cast<int>(stream->first)];
- // Push the payload mapping to the RTP session so it'll correctly map things
- session->associatePayloads(payloads);
+ // Per the RFC removing the stream is accomplished by setting the port to 0
+ media->desc.port = 0;
+ media->desc.port_count = 0;
- // The SDP has been finalized enough
- mImplPriv->mSDPFinalized = true;
+ // The RFC states that an implementation MAY choose to remove all formats but one and all attributes
+ // but at this point in time we choose not to do this
}
- return mImplPriv->mSDPFinalized == true ? mImplPriv->mSDP : 0;
+ return mImplPriv->mSDP;
}
/**
@@ -1881,6 +2479,14 @@ void SipSession::startMedia(const pjmedia_sdp_session*, const pjmedia_sdp_sessio
}
/**
+ * Internal function which gets the streams on this session.
+ */
+AsteriskSCF::Media::V1::StreamInformationDict& SipSession::getStreams()
+{
+ return mImplPriv->mStreams;
+}
+
+/**
* Internal function which gets the endpoint associated with the session.
*/
SipEndpointPtr SipSession::getEndpoint()
@@ -1909,6 +2515,22 @@ AsteriskSCF::Media::V1::SessionPrx& SipSession::getMediaSessionProxy()
}
/**
+ * Internal function which gets the proxy to our session controller.
+ */
+AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& SipSession::getOurSessionControllerProxy()
+{
+ return mImplPriv->mOurSessionControllerProxy;
+}
+
+/**
+ * Internal function which gets the proxy to the remote session controller.
+ */
+AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& SipSession::getSessionControllerProxy()
+{
+ return mImplPriv->mSessionController;
+}
+
+/**
* Internal function which sets the listeners explicitly.
*/
void SipSession::setListeners(const SessionListenerSeq& listeners)
@@ -1924,6 +2546,14 @@ RTPMediaSessionSeq SipSession::getRTPMediaSessions()
return mImplPriv->mRTPSessions;
}
+/**
+ * Internal function which sets the streams explicitly.
+ */
+void SipSession::setStreams(const AsteriskSCF::Media::V1::StreamInformationDict& streams)
+{
+ mImplPriv->mStreams = streams;
+}
+
bool SipSession::operator==(const SipSession &other) const {
return (this->mImplPriv->mInviteSession == other.mImplPriv->mInviteSession);
}
diff --git a/src/SipSession.h b/src/SipSession.h
index 165c411..fa89ad0 100644
--- a/src/SipSession.h
+++ b/src/SipSession.h
@@ -111,7 +111,7 @@ public:
const AsteriskSCF::System::Component::V1::ReplicaPtr& replica,
bool ipv6, bool isUAC, const NATEndpointOptions& natOptions);
- SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&,
+ SipSession(const Ice::ObjectAdapterPtr&, const SipEndpointPtr&, const std::string&, const Ice::Identity&, const Ice::Identity&,
const Ice::Identity&, const AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq&,
const AsteriskSCF::Media::V1::StreamSourceSeq&, const AsteriskSCF::Media::V1::StreamSinkSeq&,
const PJSipManagerPtr& manager, const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& serviceLocator,
@@ -182,6 +182,19 @@ public:
AsteriskSCF::SessionCommunications::V1::SessionCookies getCookies();
AsteriskSCF::SessionCommunications::V1::SessionCookieDict getAllCookies();
+ void getStreams_async(
+ const AsteriskSCF::SessionCommunications::V1::AMD_Session_getStreamsPtr&,
+ const Ice::Current&);
+
+ void setAndGetSessionController_async(
+ const AsteriskSCF::SessionCommunications::V1::AMD_Session_setAndGetSessionControllerPtr&,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx&,
+ const Ice::Current&);
+
+ void removeSessionController_async(const AsteriskSCF::SessionCommunications::V1::AMD_Session_removeSessionControllerPtr&,
+ const AsteriskSCF::SessionCommunications::V1::SessionControllerPrx&,
+ const Ice::Current&);
+
/**
* Implementation specific functions.
*/
@@ -197,9 +210,13 @@ public:
void addKeys(const SipEndpointMediaSRTPConfig& config, pjmedia_sdp_media* mediaSDP);
- pjmedia_sdp_session *createSDPOffer();
+ pjmedia_sdp_session *createSDPOffer(const AsteriskSCF::Media::V1::StreamInformationDict&,
+ AsteriskSCF::Media::V1::StreamInformationDict&);
+
+ pjmedia_sdp_session *createSDPAnswer(const pjmedia_sdp_session*,
+ AsteriskSCF::Media::V1::StreamInformationDict&);
- pjmedia_sdp_session *createSDPAnswer(const pjmedia_sdp_session*);
+ pjmedia_sdp_session *modifySDP(const AsteriskSCF::Media::V1::StreamInformationDict&);
void setDialog(pjsip_dialog *dialog);
@@ -224,14 +241,22 @@ public:
//
void startMedia(const pjmedia_sdp_session* local, const pjmedia_sdp_session* remote);
+ AsteriskSCF::Media::V1::StreamInformationDict& getStreams();
+
SipEndpointPtr getEndpoint();
AsteriskSCF::SessionCommunications::V1::SessionPrx& getSessionProxy();
AsteriskSCF::Media::V1::SessionPrx& getMediaSessionProxy();
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& getOurSessionControllerProxy();
+
+ AsteriskSCF::SessionCommunications::V1::SessionControllerPrx& getSessionControllerProxy();
+
void setListeners(const AsteriskSCF::Replication::SipSessionManager::V1::SessionListenerSeq&);
+ void setStreams(const AsteriskSCF::Media::V1::StreamInformationDict& streams);
+
AsteriskSCF::Replication::SipSessionManager::V1::RTPMediaSessionSeq getRTPMediaSessions();
void enqueueSessionWork(const AsteriskSCF::System::WorkQueue::V1::SuspendableWorkPtr&);
diff --git a/src/SipStateReplicatorListener.cpp b/src/SipStateReplicatorListener.cpp
index ed9fd83..d2097f2 100644
--- a/src/SipStateReplicatorListener.cpp
+++ b/src/SipStateReplicatorListener.cpp
@@ -261,6 +261,7 @@ public:
// Now that all is well we can create an actual session
SipSessionPtr localSession = endpoint->createSession("", session->mSessionObjectId,
+ session->mSessionControllerObjectId,
session->mMediaSessionObjectId, session->mRTPMediaSessions, session->mSources, session->mSinks);
localitem->setSession(localSession);
}
@@ -272,6 +273,7 @@ public:
localitem->getSession()->setListeners(session->mListeners);
localitem->getSession()->setBridge(session->mBridge);
localitem->getSession()->setCookies(session->mCookies);
+ localitem->getSession()->setStreams(session->mStreams);
}
else if ((dialog = SipDialogStateItemPtr::dynamicCast((*item))))
{
-----------------------------------------------------------------------
--
asterisk-scf/release/sip.git
More information about the asterisk-scf-commits
mailing list