[asterisk-scf-commits] asterisk-scf/integration/media_rtp_pjmedia.git branch "modular-transport-refactor" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Fri Jun 24 09:22:30 CDT 2011
branch "modular-transport-refactor" has been updated
via fe117c790109f77d0325caf620bb4b0898bbc3a6 (commit)
via 0284c56aee59386402cdd4f095aa4c8c50dbf429 (commit)
via d16e77793a39b233c40e0ef742d73d9764fb5d20 (commit)
from e1bee9143c559f83db106cedee3551aee38ca56b (commit)
Summary of changes:
.../{test_component.config => test_rtp_ice.config} | 24 +-
src/ICETransport.cpp | 381 ++++++++++++++++++--
src/ICETransport.h | 10 +-
src/NATModule.cpp | 2 +-
src/PJMediaTransport.h | 11 +
src/RTPSession.cpp | 5 +-
test/TestRTPICE.cpp | 366 +++++++++++++++++++
7 files changed, 757 insertions(+), 42 deletions(-)
copy config/{test_component.config => test_rtp_ice.config} (71%)
create mode 100644 test/TestRTPICE.cpp
- Log -----------------------------------------------------------------
commit fe117c790109f77d0325caf620bb4b0898bbc3a6
Author: Brent Eagles <beagles at digium.com>
Date: Fri Jun 24 11:52:09 2011 -0230
Register facet by using the slice defined constant.
diff --git a/src/ICETransport.cpp b/src/ICETransport.cpp
index f04198c..d37517c 100644
--- a/src/ICETransport.cpp
+++ b/src/ICETransport.cpp
@@ -490,7 +490,7 @@ void ICETransport::addFacets(const Ice::ObjectAdapterPtr& adapter, const Ice::Id
{
ICEAgentImplPtr agent = new ICEAgentImpl(adapter, id);
ICECallbackAdapter::addAgent(mTransport, agent);
- adapter->addFacet(agent, id, "ICEAgent");
+ adapter->addFacet(agent, id, AsteriskSCF::System::NAT::V1::InteractiveConnectionAgentFacetName);
}
ICETransportPtr ICETransport::create(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& config)
commit 0284c56aee59386402cdd4f095aa4c8c50dbf429
Author: Brent Eagles <beagles at digium.com>
Date: Tue Jun 21 21:13:38 2011 -0230
Capture broken candidate code in case I can find a way to use it afterwards.
diff --git a/src/ICETransport.cpp b/src/ICETransport.cpp
index afd9e1e..f04198c 100644
--- a/src/ICETransport.cpp
+++ b/src/ICETransport.cpp
@@ -19,12 +19,16 @@
#include <pjmedia.h>
#include <pjlib.h>
+#include <pjnath.h>
#include <AsteriskSCF/System/ExceptionsIf.h>
#include <map>
#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>
+#include <AsteriskSCF/System/NAT/NATTraversalIf.h>
+#include <Ice/Ice.h>
+
using namespace AsteriskSCF::PJMediaRTP;
using namespace AsteriskSCF::System::V1;
using namespace AsteriskSCF::PJUtil;
@@ -33,16 +37,259 @@ using namespace AsteriskSCF::Helpers;
namespace
{
+
+class CandidateRecord
+{
+public:
+ CandidateRecord(const pj_ice_sess_cand& pjCandidate) :
+ mCandidate(new AsteriskSCF::System::NAT::V1::Candidate),
+ mTransportId(pjCandidate.transport_id),
+ mPreference(pjCandidate.local_pref)
+ {
+ mCandidate->componentId = pjCandidate.comp_id;
+ mCandidate->priority = pjCandidate.prio;
+ mCandidate->foundation = string(pj_strbuf(&pjCandidate.foundation), pj_strlen(&pjCandidate.foundation));
+ char addrBuffer[PJ_INET6_ADDRSTRLEN];
+ pj_sockaddr_print(&pjCandidate.addr, addrBuffer, sizeof(addrBuffer), 0);
+ mCandidate->mappedAddress = addrBuffer;
+ mCandidate->mappedPort = pj_sockaddr_get_port(&pjCandidate.addr);
+ pj_sockaddr_print(&pjCandidate.base_addr, addrBuffer, sizeof(addrBuffer), 0);
+ mCandidate->baseAddress = addrBuffer;
+ mCandidate->basePort = pj_sockaddr_get_port(&pjCandidate.base_addr);
+
+ switch (pjCandidate.type)
+ {
+ case PJ_ICE_CAND_TYPE_HOST:
+ mCandidate->type = AsteriskSCF::System::NAT::V1::Host;
+ break;
+ case PJ_ICE_CAND_TYPE_SRFLX:
+ mCandidate->type = AsteriskSCF::System::NAT::V1::ServerReflexive;
+ break;
+ case PJ_ICE_CAND_TYPE_PRFLX:
+ mCandidate->type = AsteriskSCF::System::NAT::V1::PeerReflexive;
+ break;
+ case PJ_ICE_CAND_TYPE_RELAYED:
+ mCandidate->type = AsteriskSCF::System::NAT::V1::Relayed;
+ break;
+ default:
+ assert("Unknown candidate type" == 0);
+ }
+ }
+
+ AsteriskSCF::System::NAT::V1::CandidatePtr getCandidate()
+ {
+ return mCandidate;
+ }
+
+ unsigned transportId()
+ {
+ return mTransportId;
+ }
+
+ unsigned localPreferenceRating()
+ {
+ return mPreference;
+ }
+
+private:
+
+ AsteriskSCF::System::NAT::V1::CandidatePtr mCandidate;
+ pj_uint8_t mTransportId;
+ pj_uint16_t mPreference;
+};
+
+typedef boost::shared_ptr<CandidateRecord> CandidateRecordPtr;
+typedef vector<CandidateRecordPtr> CandidateRecordSeq;
+
+AsteriskSCF::System::NAT::V1::CandidateSeq convert(const CandidateRecordSeq& candidateRecords)
+{
+ AsteriskSCF::System::NAT::V1::CandidateSeq result;
+ result.reserve(candidateRecords.size());
+ for (CandidateRecordSeq::const_iterator i = candidateRecords.begin(); i != candidateRecords.end(); ++i)
+ {
+ result.push_back((*i)->getCandidate());
+ }
+ return result;
+}
+
+class ICEAgentImpl : public AsteriskSCF::System::NAT::V1::InteractiveConnectionAgent
+{
+public:
+
+ ICEAgentImpl(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id) :
+ mAdapter(adapter),
+ mId(id),
+ mShuttingDown(false),
+ mNATType(AsteriskSCF::System::NAT::V1::Unknown),
+ mRole(AsteriskSCF::System::NAT::V1::UndefinedRole)
+ {
+ }
+
+ AsteriskSCF::System::NAT::V1::AgentType getAgentType(const Ice::Current&)
+ {
+ return AsteriskSCF::System::NAT::V1::Full;
+ }
+
+ AsteriskSCF::System::NAT::V1::DetectedNATType getNATType(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ stateCheck();
+ return mNATType;
+ }
+
+ AsteriskSCF::System::NAT::V1::Role getRole(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ stateCheck();
+ return mRole;
+ }
+
+ AsteriskSCF::System::NAT::V1::CandidatePtr negotiate(const AsteriskSCF::System::NAT::V1::CandidateSeq&,
+ const Ice::Current&)
+ {
+ //
+ // TODO: implement.
+ //
+ return 0;
+ }
+
+ AsteriskSCF::System::NAT::V1::CandidateSeq getCandidates(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ return convert(mCandidates);
+ }
+
+ void onSetupComplete(pjmedia_transport* transport, pj_status_t status)
+ {
+ if (fail(status))
+ {
+ //
+ // TODO!
+ //
+ return;
+ }
+
+ pjmedia_transport_info info;
+ pjmedia_transport_info_init(&info);
+ pjmedia_transport_get_info(transport, &info);
+
+ pjmedia_ice_transport_info* iceInfo = 0;
+ for (unsigned i = 0; i < info.specific_info_cnt; ++i)
+ {
+ if (info.spc_info[i].type == PJMEDIA_TRANSPORT_TYPE_ICE)
+ {
+ iceInfo = (pjmedia_ice_transport_info*)(info.spc_info[i].buffer);
+ }
+ }
+
+ assert(iceInfo != 0);
+
+ //
+ // While we just did the assert, we use an if statement as well to
+ // prevent crashing in release builds.
+ //
+ if (iceInfo)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ if (iceInfo->role == PJ_ICE_SESS_ROLE_CONTROLLING)
+ {
+ setRole(AsteriskSCF::System::NAT::V1::Controlling);
+ }
+ else
+ {
+ setRole(AsteriskSCF::System::NAT::V1::Controlled);
+ }
+
+ //
+ // TODO: We need do different things depending on the actual
+ // session state at this moment in time.
+ //
+#if 0
+ //
+ // We have access to a lot of things, unfortunately the actual
+ // pjnath ICE transport is not one of them.!!! So I have to abandon this approach.
+ //
+ for (size_t component = 0; component < iceInfo->comp_cnt; ++component)
+ {
+ size_t candidateCount = 0;
+ pj_ice_sess_cand candidates[PJ_ICE_ST_MAX_CAND];
+ pj_status_t enumStatus = pj_ice_strans_enum_cands(iceInfo->ice_st, component + 1,
+ &candidateCount, candidates);
+ if (fail(enumStatus))
+ {
+ //
+ // TODO: this is unlikely to happen, but if it did, it's
+ // not entirely clear whether its terminal or if it could
+ // "clear up"
+ //
+ }
+ for (size_t i = 0; i < candidateCount; ++i)
+ {
+ mCandidates.push_back(new CandidateRecord(candidates[i]));
+ }
+ }
+#endif
+ }
+ }
+
+ void shutdown()
+ {
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ if (mShuttingDown)
+ {
+ return;
+ }
+ mShuttingDown = true;
+ }
+ mAdapter->removeFacet(mId, "ICEAgent");
+ }
+
+ void setNATType(AsteriskSCF::System::NAT::V1::DetectedNATType natType)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ mNATType = natType;
+ }
+
+ void setRole(AsteriskSCF::System::NAT::V1::Role role)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ mRole = role;
+ }
+
+private:
+ boost::shared_mutex mLock;
+ Ice::ObjectAdapterPtr mAdapter;
+ Ice::Identity mId;
+ bool mShuttingDown;
+ AsteriskSCF::System::NAT::V1::DetectedNATType mNATType;
+ AsteriskSCF::System::NAT::V1::Role mRole;
+ CandidateRecordSeq mCandidates;
+
+ void stateCheck()
+ {
+ if (mShuttingDown)
+ {
+ throw Ice::ObjectNotExistException(__FILE__, __LINE__);
+ }
+ }
+};
+
+typedef IceUtil::Handle<ICEAgentImpl> ICEAgentImplPtr;
+
class ICECallbackAdapter
{
public:
static void addEntry(pjmedia_transport* transport, const ICETransportPtr& callback);
+ static void addAgent(pjmedia_transport* transport, const ICEAgentImplPtr& agent);
+ static void removeEntry(pjmedia_transport* transport);
static void onICEComplete(pjmedia_transport* transport, pj_ice_strans_op operation, pj_status_t status);
struct CallbackRecord
{
bool connected;
ICETransportPtr transport;
+ ICEAgentImplPtr agent;
};
typedef std::map<pjmedia_transport*, CallbackRecord> TransportMap;
@@ -71,6 +318,7 @@ void ICECallbackAdapter::addEntry(pjmedia_transport* transport, const ICETranspo
if (i != mTransportMap.end())
{
i->second.transport = callback;
+ callback->onSetupComplete(transport, PJ_SUCCESS);
}
else
{
@@ -81,6 +329,40 @@ void ICECallbackAdapter::addEntry(pjmedia_transport* transport, const ICETranspo
}
}
+void ICECallbackAdapter::addAgent(pjmedia_transport* transport, const ICEAgentImplPtr& agent)
+{
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ TransportMap::iterator i = mTransportMap.find(transport);
+
+ if (i != mTransportMap.end())
+ {
+ i->second.agent = agent;
+ if (i->second.connected)
+ {
+ agent->onSetupComplete(transport, PJ_SUCCESS);
+ }
+ }
+ //
+ // The entry really should always be found, but there could be a race
+ // condition if things are shutting down before everything was cleanly
+ // activated.
+ //
+}
+
+void ICECallbackAdapter::removeEntry(pjmedia_transport* t)
+{
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ TransportMap::iterator i = mTransportMap.find(t);
+ if (i != mTransportMap.end())
+ {
+ if (i->second.agent)
+ {
+ i->second.agent->shutdown();
+ }
+ mTransportMap.erase(i);
+ }
+}
+
void ICECallbackAdapter::onICEComplete(pjmedia_transport* transport, pj_ice_strans_op operation, pj_status_t status)
{
//
@@ -90,28 +372,51 @@ void ICECallbackAdapter::onICEComplete(pjmedia_transport* transport, pj_ice_stra
{
case PJ_ICE_STRANS_OP_INIT:
//
- // Initialization is complete. FWICT, this should not get here.
+ // Initialization is complete. At this point we know what candidates we can offer.
//
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ TransportMap::iterator i = mTransportMap.find(transport);
+ if (i == mTransportMap.end())
+ {
+ CallbackRecord r;
+ r.connected = success(status);
+ mTransportMap.insert(make_pair(transport, r));
+ }
+ else
+ {
+ i->second.connected = success(status);
+ i->second.transport->onSetupComplete(transport, status);
+ if (i->second.agent)
+ {
+ i->second.agent->onSetupComplete(transport, status);
+ }
+ }
+ }
break;
case PJ_ICE_STRANS_OP_NEGOTIATION:
//
// Negotiation is complete.
//
- {
- boost::unique_lock<boost::shared_mutex> lock(mLock);
- TransportMap::iterator i = mTransportMap.find(transport);
- if (i == mTransportMap.end())
{
- CallbackRecord r;
- r.connected = true;
- mTransportMap.insert(make_pair(transport, r));
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ TransportMap::iterator i = mTransportMap.find(transport);
+ if (i == mTransportMap.end())
+ {
+ assert(false);
+ //
+ // This is a problem, it is very unlikely that this should
+ // happen when things are working as they should.
+ //
+ }
+ else
+ {
+ //
+ // We've negotiated a valid flow with on this leg. We should query every
+ // detail of relevance from the current media session.
+ //
+ }
}
- else
- {
- i->second.connected = true;
- i->second.transport->onSetupComplete(transport, status);
- }
- }
break;
case PJ_ICE_STRANS_OP_KEEP_ALIVE:
//
@@ -128,6 +433,7 @@ ICETransport::~ICETransport()
//
// TODO : cleanup ICE transport, the transport itself is closed by the parent class.
//
+ ICECallbackAdapter::removeEntry(mTransport);
}
void ICETransport::onSetupComplete(pjmedia_transport* transport, int status)
@@ -180,26 +486,47 @@ AddressPtr ICETransport::remoteAddress()
return mRemoteAddress;
}
+void ICETransport::addFacets(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id)
+{
+ ICEAgentImplPtr agent = new ICEAgentImpl(adapter, id);
+ ICECallbackAdapter::addAgent(mTransport, agent);
+ adapter->addFacet(agent, id, "ICEAgent");
+}
+
ICETransportPtr ICETransport::create(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& config)
{
+ ICETransportPtr transport(new ICETransport(ep, config));
+ transport->start();
+
+ //
+ // TODO: I need to temporarily insert a wait-until-fail loop for the ICE steps so the transport information
+ // is available when the transport create call returns. The source/sink's won't have valid information until then.
+ //
+ return transport;
+}
+
+ICETransport::ICETransport(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& configObject) :
+ PJMediaTransport(0),
+ mEndpoint(ep),
+ mConfig(configObject),
+ mEnableRTCP(false)
+{
+}
+
+void ICETransport::start()
+{
pjmedia_transport* t;
PJICECallbackPtr callback(new pjmedia_ice_cb);
callback->on_ice_complete = &ICECallbackAdapter::onICEComplete;
- NATModulePtr natModule = NATModule::create(config, ep);
- pj_status_t result = pjmedia_ice_create(ep->endpoint(), "ASCF_ICE_MEDIA", 2, natModule->configuration(), callback.get(),
- &t);
+ NATModulePtr natModule = NATModule::create(mConfig, mEndpoint);
+ pj_status_t result = pjmedia_ice_create(mEndpoint->endpoint(), "ASCF_ICE_MEDIA", (mEnableRTCP ? 2 : 1),
+ natModule->configuration(), callback.get(), &t);
if (fail(result))
{
throw InternalInitializationException("Unable to create new ICE media transport");
}
- ICETransportPtr transport(new ICETransport(t, callback, natModule));
- ICECallbackAdapter::addEntry(t, transport);
- return transport;
-}
-
-ICETransport::ICETransport(pjmedia_transport* t, const PJICECallbackPtr& cb, const NATModulePtr& natModule) :
- PJMediaTransport(t),
- mCallback(cb),
- mNATModule(natModule)
-{
+ ICECallbackAdapter::addEntry(t, shared_from_this());
+ mTransport = t;
+ mCallback = callback;
+ mNATModule = natModule;
}
diff --git a/src/ICETransport.h b/src/ICETransport.h
index 301f083..939f4e1 100644
--- a/src/ICETransport.h
+++ b/src/ICETransport.h
@@ -40,7 +40,7 @@ typedef boost::shared_ptr<ICETransport> ICETransportPtr;
typedef boost::shared_ptr<pjmedia_ice_cb> PJICECallbackPtr;
typedef boost::shared_ptr<pj_sockaddr> PJSockAddrPtr;
-class ICETransport : public PJMediaTransport
+class ICETransport : public PJMediaTransport, public boost::enable_shared_from_this<ICETransport>
{
public:
@@ -52,6 +52,7 @@ public:
//
AsteriskSCF::Helpers::AddressPtr localAddress();
AsteriskSCF::Helpers::AddressPtr remoteAddress();
+ void addFacets(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id);
static ICETransportPtr create(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& configObject);
@@ -62,8 +63,13 @@ private:
PJICECallbackPtr mCallback;
PJSockAddrPtr mLastKnownAddr;
NATModulePtr mNATModule;
+ PJMediaEndpointPtr mEndpoint;
+ PJMediaEnvironmentPtr mConfig;
+ bool mEnableRTCP;
- ICETransport(pjmedia_transport* t, const PJICECallbackPtr& cb, const NATModulePtr& natModule);
+ ICETransport(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& configObject);
+
+ void start();
//
// Hidden and unimplemented.
diff --git a/src/NATModule.cpp b/src/NATModule.cpp
index d20d83f..d6f3350 100644
--- a/src/NATModule.cpp
+++ b/src/NATModule.cpp
@@ -47,7 +47,7 @@ NATModulePtr AsteriskSCF::PJMediaRTP::NATModule::create(const PJMediaEnvironment
}
else
{
- transcfg->stun.max_host_cands = 2; // XX arbitrary.
+ transcfg->stun.max_host_cands = 5; // XX arbitrary.
}
if (env->natConfig()->isTURNEnabled())
{
diff --git a/src/PJMediaTransport.h b/src/PJMediaTransport.h
index 9de8f2f..ffaa5da 100644
--- a/src/PJMediaTransport.h
+++ b/src/PJMediaTransport.h
@@ -18,6 +18,8 @@
#include <AsteriskSCF/Helpers/Network.h>
#include <boost/shared_ptr.hpp>
+#include <Ice/ObjectAdapterF.h>
+#include <Ice/Identity.h>
//
// Forward declarations.
@@ -44,6 +46,15 @@ public:
virtual AsteriskSCF::Helpers::AddressPtr localAddress();
virtual AsteriskSCF::Helpers::AddressPtr remoteAddress();
+ /**
+ * Called as a mechanism to allow a transport to add facets to the
+ * associated session. This can be particularly handy since an RTP session
+ * might have multiple transport specializations associated with it. This
+ * allows extra functionality to be aggregated without having to weight
+ * down the objects with lots of unnecessary code.
+ **/
+ virtual void addFacets(const Ice::ObjectAdapterPtr&, const Ice::Identity&) {}
+
protected:
pjmedia_transport* mTransport;
diff --git a/src/RTPSession.cpp b/src/RTPSession.cpp
index af1cb58..5bc5d48 100644
--- a/src/RTPSession.cpp
+++ b/src/RTPSession.cpp
@@ -623,13 +623,16 @@ RTPSessionPrx RTPSessionImpl::activate(const Ice::Identity& id, const Ice::Ident
}
replicateState(mSessionStateItem, mStreamSink->getStateItem(), mStreamSource->getStateItem());
}
- return RTPSessionPrx::uncheckedCast(mAdapter->add(this, id));
+ RTPSessionPrx result = RTPSessionPrx::uncheckedCast(mAdapter->add(this, id));
+ mTransport->addFacets(mAdapter, id);
+ return result;
}
catch (...)
{
mSessionAdapter.reset();
throw;
}
+ return RTPSessionPrx(); // For compilers that complain about such things.
}
void RTPSessionImpl::destroy()
commit d16e77793a39b233c40e0ef742d73d9764fb5d20
Author: Brent Eagles <beagles at digium.com>
Date: Mon Jun 20 10:30:42 2011 -0230
Adding a couple of tests.
diff --git a/config/test_rtp_ice.config b/config/test_rtp_ice.config
new file mode 100644
index 0000000..adb150b
--- /dev/null
+++ b/config/test_rtp_ice.config
@@ -0,0 +1,74 @@
+# This is a configuration file used in conjunction with the media_rtp_pjmedia test driver
+
+#
+# Icebox Configuration
+#
+RtpConfiguration.Name=rtpoice
+IceBox.InheritProperties=1
+IceBox.LoadOrder=ServiceDiscovery,MediaRTPpjmedia,MediaRTPpjmediaTest
+
+# RtpStateReplicator Configuration
+
+# Adapter parameters for this component
+RtpStateReplicator.Endpoints=tcp:udp
+
+# A proxy to the service locator management service
+LocatorServiceManagement.Proxy=LocatorServiceManagement:tcp -p 4422
+
+# A proxy to the service locator service
+LocatorService.Proxy=LocatorService:tcp -p 4411
+
+#
+# media_rtp_pjmedia Configuration
+#
+
+IceBox.Service.MediaRTPpjmedia=media_rtp_pjmedia:create
+
+# Adapter parameters for this component
+MediaRTPpjmediaAdapter.Endpoints=default
+MediaRTPpjmediaAdapterLocal.Endpoints=default
+MediaRTPpjmediaAdapterLogger.Endpoints=default
+
+# A proxy to the service locator management service
+ServiceLocatorManagementProxy=LocatorServiceManagement:tcp -p 4422
+
+# A proxy to the service locator service
+ServiceLocatorProxy=LocatorService:tcp -p 4411
+
+#
+# media_rtp_pjmedia_test Configuration
+#
+
+IceBox.Service.MediaRTPpjmediaTest=media_rtp_pjmedia_ice_test:create
+
+#
+# Service Locator Configuration
+#
+
+IceBox.Service.ServiceDiscovery=service_locator:create
+
+AsteriskSCFIceStorm.InstanceName=AsteriskSCFIceStorm
+AsteriskSCFIceStorm.TopicManager.Endpoints=default -p 10000
+AsteriskSCFIceStorm.Publish.Endpoints=tcp -p 10001:udp -p 10001
+AsteriskSCFIceStorm.Trace.TopicManager=2
+AsteriskSCFIceStorm.Transient=1
+AsteriskSCFIceStorm.Flush.Timeout=2000
+TopicManager.Proxy=AsteriskSCFIceStorm/TopicManager:default -p 10000
+
+#RtpStateReplicatorIceStorm.InstanceName=RtpStateReplicatorIceStorm
+#RtpStateReplicatorIceStorm.TopicManager.Endpoints=default -p 10005
+#RtpStateReplicatorIceStorm.Publish.Endpoints=default -p 10006
+#RtpStateReplicatorIceStorm.Trace.TopicManager=2
+#RtpStateReplicatorIceStorm.Transient=1
+#RtpStateReplicatorIceStorm.Flush.Timeout=2000
+#RtpStateReplicatorTopicManager.Proxy=RtpStateReplicatorIceStorm/TopicManager:default -p 10005
+
+ServiceLocatorManagementAdapter.Endpoints=tcp -p 4422
+ServiceLocatorAdapter.Endpoints=tcp -p 4411
+ServiceLocatorLocalAdapter.Endpoints=tcp -p 4412
+LocatorService.Proxy=LocatorService:tcp -p 4411
+
+LoggerAdapter.Endpoints=default
+Ice.ThreadPool.Client.Size=4
+Ice.ThreadPool.Server.Size=4
+Rtp.Standalone=true
diff --git a/test/TestRTPICE.cpp b/test/TestRTPICE.cpp
new file mode 100644
index 0000000..057b7eb
--- /dev/null
+++ b/test/TestRTPICE.cpp
@@ -0,0 +1,366 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+
+#define BOOST_TEST_MODULE RtpICETestModule
+#define BOOST_TEST_NO_MAIN
+
+#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+
+#include "RtpConfigurationIf.h"
+#include "RtpStateReplicationIf.h"
+
+#include <boost/test/debug.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <Ice/Ice.h>
+#include <Ice/BuiltinSequences.h>
+
+#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
+#include <AsteriskSCF/Media/MediaIf.h>
+#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
+
+//
+// An attempt to get some reasonable code coverage and verify that the basic *premise* of the functionality works as
+// expected. HOWEVER, nothing beats live testing. Due the the dependency on external agencies (STUN server, TURN server,
+// NAT firewall, etc) there isn't much in the way of real functional testing that we can drive from a single icebox
+// instance. A HOW_TO_TEST document would be a good idea and is a major TODO.
+//
+
+using namespace std;
+using namespace AsteriskSCF::Core::Discovery::V1;
+using namespace AsteriskSCF::Media::V1;
+using namespace AsteriskSCF::Media::RTP::V1;
+using namespace AsteriskSCF::System::Configuration::V1;
+
+namespace
+{
+
+class TestReplicatorListener : public RtpStateReplicatorListener
+{
+public:
+ void stateRemoved(const Ice::StringSeq&, const Ice::Current&)
+ {
+ }
+
+ void stateSet(const RtpStateItemSeq&, const Ice::Current&)
+ {
+ }
+
+private:
+
+};
+
+class IceEnvironment
+{
+public:
+ IceEnvironment()
+ {
+ Ice::InitializationData data;
+ data.properties = IceBoxTestEnv.communicator->getProperties();
+ mCommunicator = Ice::initialize(IceBoxTestEnv.argc, IceBoxTestEnv.argv, data);
+ mAdapter = mCommunicator->createObjectAdapterWithEndpoints("TestAdapter", "default");
+
+ //
+ // We will be making calls on proxies instantiated on this adapter, so we should activated here.
+ //
+ mAdapter->activate();
+ }
+
+ ~IceEnvironment()
+ {
+ if (mCommunicator)
+ {
+ mCommunicator->shutdown();
+ }
+ }
+
+ Ice::CommunicatorPtr getCommunicator()
+ {
+ return mCommunicator;
+ }
+
+ Ice::ObjectAdapterPtr getObjectAdapter()
+ {
+ return mAdapter;
+ }
+
+private:
+ Ice::CommunicatorPtr mCommunicator;
+ Ice::ObjectAdapterPtr mAdapter;
+};
+
+class TestFixture
+{
+public:
+ TestFixture()
+ {
+ BOOST_TEST_MESSAGE("Creating test fixture");
+ ::boost::debug::detect_memory_leaks(false);
+ ::boost::unit_test::unit_test_log.set_stream(cout);
+ }
+
+ ~TestFixture()
+ {
+ BOOST_TEST_MESSAGE("Destroying test fixture");
+ }
+};
+
+BOOST_GLOBAL_FIXTURE(TestFixture);
+
+RTPMediaServicePrx locateMediaService(const ServiceLocatorPrx& locator)
+{
+ RTPOverICEServiceLocatorParamsPtr query = new RTPOverICEServiceLocatorParams;
+ query->category = "rtp";
+ query->enableRTPOverICE = true;
+ query->enableTURN = false;
+ return RTPMediaServicePrx::checkedCast(locator->locate(query));
+}
+
+ConfigurationServicePrx locateConfigurationService(const string& name, const ServiceLocatorPrx& locator)
+{
+ RtpConfigurationParamsPtr query = new RtpConfigurationParams;
+ query->category = ConfigurationDiscoveryCategory;
+ query->name = name;
+ cout << "using name " << name << endl;
+ return ConfigurationServicePrx::checkedCast(locator->locate(query));
+}
+
+ServiceLocatorPrx getLocator(const Ice::CommunicatorPtr& comm)
+{
+ return ServiceLocatorPrx::checkedCast(comm->propertyToProxy("LocatorService.Proxy"));
+}
+
+BOOST_AUTO_TEST_CASE(RtpSessionWithICEEnabled)
+{
+ IceEnvironment iceEnv;
+ bool testResult = false;
+ try
+ {
+ ServiceLocatorPrx locator;
+ BOOST_REQUIRE_NO_THROW(locator = getLocator(iceEnv.getCommunicator()));
+ BOOST_REQUIRE(locator != 0);
+
+ //
+ // It's actually pretty handy that this icebox test suite probably
+ // shares the configuration file that hosts the media service!
+ //
+ ConfigurationServicePrx configPrx;
+ BOOST_REQUIRE_NO_THROW(
+ configPrx = locateConfigurationService(
+ iceEnv.getCommunicator()->getProperties()->getPropertyWithDefault("RtpConfiguration.Name", ""),
+ locator));
+ BOOST_REQUIRE(configPrx != 0);
+ RTPICEConfigurationGroupPtr iceGroup = new RTPICEConfigurationGroup;
+
+ STUNServerItemPtr stunServerCfg = new STUNServerItem;
+ stunServerCfg->address = "stun.ekiga.net";
+ stunServerCfg->port = 3478;
+ iceGroup->configurationItems[STUNServerItemName] = stunServerCfg;
+
+ RTPICETransportFlagsItemPtr iceFlags = new RTPICETransportFlagsItem;
+ iceFlags->enableICE = true;
+ iceFlags->enableTURN = false;
+ iceGroup->configurationItems[RTPICETransportFlagsItemName] = iceFlags;
+
+ ConfigurationGroupSeq s;
+ s.push_back(iceGroup);
+ configPrx->setConfiguration(s);
+
+ RTPMediaServicePrx servicePrx;
+ {
+ RTPOverICEServiceLocatorParamsPtr query = new RTPOverICEServiceLocatorParams;
+ query->category = "rtp";
+ query->enableRTPOverICE = true;
+ query->enableTURN = false;
+ servicePrx = RTPMediaServicePrx::checkedCast(locator->locate(query));
+ }
+ BOOST_REQUIRE(servicePrx);
+ try
+ {
+ RTPOverICEServiceLocatorParamsPtr query = new RTPOverICEServiceLocatorParams;
+ query->category = "rtp";
+ query->enableRTPOverICE = true;
+ query->enableTURN = false;
+ RTPSessionPrx sessionPrx;
+ BOOST_REQUIRE_NO_THROW(sessionPrx = servicePrx->allocate(query));
+ BOOST_REQUIRE(sessionPrx != 0);
+ sessionPrx->ice_ping(); // To silence unused arg warning.
+ sessionPrx->release();
+ testResult = true;
+ }
+ catch (const SessionAllocationFailure& ex)
+ {
+ BOOST_TEST_MESSAGE(ex.what());
+ }
+ }
+ catch (const Ice::Exception& ex)
+ {
+ BOOST_FAIL(ex.what());
+ }
+ BOOST_CHECK(testResult);
+}
+
+BOOST_AUTO_TEST_CASE(RtpSessionAllocationFailure)
+{
+ IceEnvironment iceEnv;
+ bool testResult = false;
+ try
+ {
+ ServiceLocatorPrx locator;
+ BOOST_REQUIRE_NO_THROW(locator = getLocator(iceEnv.getCommunicator()));
+ BOOST_REQUIRE(locator != 0);
+ RTPMediaServicePrx servicePrx;
+ BOOST_REQUIRE_NO_THROW(servicePrx = locateMediaService(locator));
+ BOOST_REQUIRE(servicePrx);
+
+ //
+ // It's actually pretty handy that this icebox test suite probably
+ // shares the configuration file that hosts the media service!
+ //
+ ConfigurationServicePrx configPrx;
+ BOOST_REQUIRE_NO_THROW(
+ configPrx = locateConfigurationService(
+ iceEnv.getCommunicator()->getProperties()->getPropertyWithDefault("RtpConfiguration.Name", ""),
+ locator));
+ RTPICEConfigurationGroupPtr iceGroup = new RTPICEConfigurationGroup;
+ RTPICETransportFlagsItemPtr iceFlags = new RTPICETransportFlagsItem;
+ iceFlags->enableICE = false;
+ iceFlags->enableTURN = false;
+ iceGroup->configurationItems[RTPICETransportFlagsItemName] = iceFlags;
+ ConfigurationGroupSeq s;
+ s.push_back(iceGroup);
+ BOOST_REQUIRE_NO_THROW(configPrx->setConfiguration(s));
+ try
+ {
+ RTPOverICEServiceLocatorParamsPtr query = new RTPOverICEServiceLocatorParams;
+ query->category = "rtp";
+ query->enableRTPOverICE = true;
+ query->enableTURN = true;
+ RTPSessionPrx sessionPrx = servicePrx->allocate(query);
+ sessionPrx->ice_ping();
+ }
+ catch (const SessionAllocationFailure& ex)
+ {
+ testResult = true;
+ BOOST_TEST_MESSAGE(ex.what());
+ }
+ }
+ catch (const Ice::Exception& ex)
+ {
+ BOOST_TEST_MESSAGE(ex.what());
+ }
+ BOOST_CHECK(testResult);
+}
+#if 0
+BOOST_AUTO_TEST_CASE(RtpSessionWithICEDisabled)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(RtpSessionWithICEAndTURN)
+{
+ //
+ // Requires a test TURN server.
+ //
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(RtpSessionWOICEButTURNEnabled)
+{
+ //
+ // Enabling ICE should be ignored in this case.
+ //
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(MultipleConcurrentConnections)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(Configure)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(ConcurrentConfigure)
+{
+ BOOST_FAIL("Test not ready yet");
+
+}
+
+BOOST_AUTO_TEST_CASE(Replication)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(ConcurrentReplication)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(InvalidReplication)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(InvalidConfiguration)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(InvalidDiscoveryParams)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(ExceedsMaxCalls)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(NoCandidates)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(TURNServerFailure)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(HairPinning)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+
+BOOST_AUTO_TEST_CASE(SymmetricRTP)
+{
+ BOOST_FAIL("Test not ready yet");
+}
+#endif
+
+//
+// TODO: and many many more test cases.
+//
+
+}
+
+
+
+
-----------------------------------------------------------------------
--
asterisk-scf/integration/media_rtp_pjmedia.git
More information about the asterisk-scf-commits
mailing list