[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