[asterisk-scf-commits] asterisk-scf/integration/media_rtp_pjmedia.git branch "nat-traversal" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon May 16 14:08:16 CDT 2011


branch "nat-traversal" has been updated
       via  063e9b5292bd991bebe02973acdaf2e78aa167fa (commit)
       via  d02e5d1a88c30417aac41b2ee76c4a58dce6abc8 (commit)
       via  d3030cb2eb13578921d5c4087d05e758aa47c842 (commit)
       via  531ffcae24172273c8952b97d2360e4097992268 (commit)
      from  d129982f703ddde8692228e71454c6cc94b443d9 (commit)

Summary of changes:
 CMakeLists.txt                     |   37 ---
 src/CMakeLists.txt                 |   56 ++---
 src/ICEConfiguration.cpp           |   40 +++
 src/ICEConfiguration.h             |   71 +++++
 src/MediaRTPpjmedia.cpp            |   40 ++--
 src/NATConfig.cpp                  |  102 +++++++
 src/NATConfig.h                    |   75 ++++++
 src/NATModule.cpp                  |   72 +++++
 src/NATModule.h                    |   57 ++++
 src/PJLibConfiguration.cpp         |   38 +++
 src/PJLibConfiguration.h           |   64 +++++
 src/PJMediaEnvironment.cpp         |   58 ++++
 src/PJMediaEnvironment.h           |   96 +++++++
 src/{ServiceConfig.h => PJUtil.h}  |   25 +-
 src/RTPICESession.cpp              |  517 +++++++++++++++---------------------
 src/RTPICESession.h                |   31 +++
 src/RTPSession.cpp                 |   36 ++--
 src/RTPSession.h                   |   34 +--
 src/RTPSink.cpp                    |   16 +-
 src/RTPSink.h                      |    8 +
 src/RTPSource.cpp                  |   12 +-
 src/RTPSource.h                    |    6 +
 src/RtpStateReplicator.h           |   25 +-
 src/RtpStateReplicatorListener.cpp |   12 +-
 test/CMakeLists.txt                |   13 +-
 25 files changed, 1047 insertions(+), 494 deletions(-)
 create mode 100644 src/ICEConfiguration.cpp
 create mode 100644 src/ICEConfiguration.h
 create mode 100644 src/NATConfig.cpp
 create mode 100644 src/NATConfig.h
 create mode 100644 src/NATModule.cpp
 create mode 100644 src/NATModule.h
 create mode 100644 src/PJLibConfiguration.cpp
 create mode 100644 src/PJLibConfiguration.h
 create mode 100644 src/PJMediaEnvironment.cpp
 create mode 100644 src/PJMediaEnvironment.h
 copy src/{ServiceConfig.h => PJUtil.h} (63%)


- Log -----------------------------------------------------------------
commit 063e9b5292bd991bebe02973acdaf2e78aa167fa
Author: Brent Eagles <beagles at digium.com>
Date:   Mon May 16 15:56:05 2011 -0230

    Commit in progress changes.
    - pull out support classes into separate files
    - fix renaming
    - move pjmedia initialization into a class and have the existing construction work off of it

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 046cc47..ad6dc88 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,4 @@
-include_directories(${utils_dir}/StateReplicator/include)
-include_directories(${utils_dir}/SmartProxy/include)
+include_directories(${utils_dir}/include)
 include_directories(${API_INCLUDE_DIR})
 if(NOT logger_dir)
   message(FATAL_ERROR "The logger directory could not be found ${logger_dir}")
@@ -18,6 +17,19 @@ asterisk_scf_component_add_file(media_rtp_pjmedia RTPSource.h)
 asterisk_scf_component_add_file(media_rtp_pjmedia RTPSink.h)
 asterisk_scf_component_add_file(media_rtp_pjmedia RTPICESession.cpp)
 asterisk_scf_component_add_file(media_rtp_pjmedia RTPICESession.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia NATModule.cpp)
+asterisk_scf_component_add_file(media_rtp_pjmedia NATModule.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia NATConfig.cpp)
+asterisk_scf_component_add_file(media_rtp_pjmedia NATConfig.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia ICEConfiguration.cpp)
+asterisk_scf_component_add_file(media_rtp_pjmedia ICEConfiguration.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia PJMediaEnvironment.cpp)
+asterisk_scf_component_add_file(media_rtp_pjmedia PJMediaEnvironment.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia PJLibConfiguration.cpp)
+asterisk_scf_component_add_file(media_rtp_pjmedia PJLibConfiguration.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia PJUtil.h)
+asterisk_scf_component_add_file(media_rtp_pjmedia ServiceConfig.h)
+
 asterisk_scf_component_add_file(media_rtp_pjmedia RtpStateReplicatorListener.cpp)
 asterisk_scf_component_add_file(media_rtp_pjmedia RtpStateReplicator.h)
 asterisk_scf_component_add_slice(media_rtp_pjmedia ../local-slice/RtpStateReplicationIf.ice)
@@ -25,6 +37,7 @@ asterisk_scf_component_add_boost_libraries(media_rtp_pjmedia core thread)
 asterisk_scf_component_build_icebox(media_rtp_pjmedia)
 target_link_libraries(media_rtp_pjmedia logging-client)
 target_link_libraries(media_rtp_pjmedia asterisk-scf-api)
+target_link_libraries(media_rtp_pjmedia ice-util-cpp)
 pjproject_link(media_rtp_pjmedia pjlib)
 pjproject_link(media_rtp_pjmedia pjlib-util)
 pjproject_link(media_rtp_pjmedia pjmedia)
diff --git a/src/ICEConfiguration.cpp b/src/ICEConfiguration.cpp
new file mode 100644
index 0000000..2cdc1c7
--- /dev/null
+++ b/src/ICEConfiguration.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "ICEConfiguration.h"
+#include <Ice/Properties.h>
+
+using namespace std;
+using namespace AsteriskSCF::PJMediaRTP;
+
+ICEConfigurationPtr AsteriskSCF::PJMediaRTP::ICEConfiguration::create(const Ice::PropertiesPtr& props,
+        const string& propertyPrefix)
+{
+    string prefix(propertyPrefix);
+    if (!prefix.empty() && prefix.back() != '.')
+    {
+        prefix += '.';
+    }
+    int maxCandidates = props->getPropertyAsIntWithDefault(prefix + "ICE.MaxCandidates", 2);
+    int maxCalls = props->getPropertyAsIntWithDefault(prefix + "ICE.MaxCalls", 2);
+    return ICEConfigurationPtr(new ICEConfiguration(maxCandidates, maxCalls));
+}
+
+ICEConfiguration::ICEConfiguration(int maxCandidates, int maxCalls) :
+    mMaxCandidates(maxCandidates),
+    mMaxCalls(maxCalls)
+{
+}
diff --git a/src/ICEConfiguration.h b/src/ICEConfiguration.h
new file mode 100644
index 0000000..31c265a
--- /dev/null
+++ b/src/ICEConfiguration.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <Ice/PropertiesF.h>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+class ICEConfiguration;
+typedef boost::shared_ptr<ICEConfiguration> ICEConfigurationPtr;
+
+/**
+ * ICEConfiguration is fairly minimal at the moment, but may grow in the future. The intent is to reduce code
+ * duplication when dealing with pjproject related configuration. This is also an immutable object, so locking is not an
+ * issue.
+ **/
+class ICEConfiguration
+{
+public:
+
+    int maxCandidates() const
+    {
+        return mMaxCandidates;
+    }
+
+    int maxCalls() const
+    {
+        return mMaxCalls;
+    }
+    
+    /**
+     * Create configuration instance from Ice properties.  TODO: This could be extended by adding additional factory
+     * overrides.
+     **/
+    static ICEConfigurationPtr create(const Ice::PropertiesPtr& props,
+            const std::string& propertyPrefix);
+    
+private:
+    int mMaxCandidates;
+    int mMaxCalls;
+
+    ICEConfiguration(int maxCandidates, int maxCalls);
+
+    //
+    // Hidden and not implemented.
+    //
+    ICEConfiguration(const ICEConfiguration&);
+    void operator=(const ICEConfiguration&);
+};
+
+} /* End of namespace ICEMediaSession */
+} /* End of namespace AsteriskSCF */
diff --git a/src/MediaRTPpjmedia.cpp b/src/MediaRTPpjmedia.cpp
index 247a5af..fe5954c 100644
--- a/src/MediaRTPpjmedia.cpp
+++ b/src/MediaRTPpjmedia.cpp
@@ -30,20 +30,23 @@
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
 #include <AsteriskSCF/Logger/IceLogger.h>
 #include <AsteriskSCF/logger.h>
-#include <AsteriskSCF/SmartProxy.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
 
 #include "RtpStateReplicationIf.h"
 
 #include "RTPSession.h"
 #include "RtpStateReplicator.h"
 
+#include "PJMediaEnvironment.h"
+
 using namespace std;
 using namespace AsteriskSCF::Core::Discovery::V1;
 using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media::RTP::V1;
 using namespace AsteriskSCF::System::Component::V1;
 using namespace AsteriskSCF::System::Logging;
-using namespace AsteriskSCF::SmartProxy;
+using namespace AsteriskSCF::Discovery;
+using namespace AsteriskSCF::PJMediaRTP;
 
 namespace
 {
@@ -60,24 +63,16 @@ class RTPMediaServiceImpl : public RTPMediaService
 {
 public:
     RTPMediaServiceImpl(const Ice::ObjectAdapterPtr&, const ReplicaPtr&,
-            const AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>&);
+            const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>&);
     RTPSessionPrx allocate(const FormatSeq&, const Ice::Current&);
-    pj_pool_factory *getPoolFactory() { return &mCachingPool.factory; };
+    pj_pool_factory *getPoolFactory() { return mEnvironment->poolFactory(); };
 private:
     /**
      * A pointer to the object adapter that objects should be added to.
      */
     Ice::ObjectAdapterPtr mAdapter;
 
-    /**
-     * Memory caching pool.
-     */
-    pj_caching_pool mCachingPool;
-
-    /**
-     * Memory pool.
-     */
-    pj_pool_t* mMemoryPool;
+    PJMediaEnvironmentPtr mEnvironment;
 
     /**
      * A pointer to the replica service.
@@ -87,7 +82,7 @@ private:
     /**
      * A proxy to the state replicator.
      */
-    AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
+    AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
 };
 
 /**
@@ -214,7 +209,7 @@ private:
     /**
      * A proxy to the state replicator.
      */
-    AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
+    AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
 
     /**
      * An instance of the general state information class.
@@ -328,14 +323,11 @@ private:
  * Constructor for the RTPMediaServiceImpl class.
  */
 RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, const ReplicaPtr& replicaService,
-        const AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) :
-    mAdapter(adapter), mReplicaService(replicaService), mStateReplicator(stateReplicator)
+        const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) :
+    mAdapter(adapter), mEnvironment(PJMediaEnvironment::create(adapter->getCommunicator()->getProperties(), "")), 
+        mReplicaService(replicaService), mStateReplicator(stateReplicator)
+        
 {
-    /* Initialize the memory caching pool using default policy as specified by pjlib. */
-    pj_caching_pool_init(&mCachingPool, &pj_pool_factory_default_policy, 0);
-
-    /* Initialize the memory pool that pjmedia will draw from. */
-    mMemoryPool = pj_pool_create(&mCachingPool.factory, "media_rtp_pjmedia", 1024, 1024, 0);
 }
 
 /**
@@ -344,7 +336,7 @@ RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, c
 RTPSessionPrx RTPMediaServiceImpl::allocate(const FormatSeq& formats, const Ice::Current&)
 {
     RTPSessionImplPtr session =
-        new RTPSessionImpl(mAdapter, formats, &mCachingPool.factory, mReplicaService, mStateReplicator);
+        new RTPSessionImpl(mAdapter, formats, mEnvironment->poolFactory(), mReplicaService, mStateReplicator);
     return session->getProxy();
 }
 
@@ -410,7 +402,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
 
     try
     {  
-	AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx> pw(locator, replicatorParams, lg);
+	AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> pw(locator, replicatorParams, lg);
         mStateReplicator = pw;
     }
     catch (...)
diff --git a/src/NATConfig.cpp b/src/NATConfig.cpp
new file mode 100644
index 0000000..750118a
--- /dev/null
+++ b/src/NATConfig.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#include "NATConfig.h"
+
+#include <Ice/Properties.h>
+#include <AsteriskSCF/System/ExceptionsIf.h>
+#include <pjnath.h>
+#include <AsteriskSCF/logger.h>
+
+using namespace std;
+using namespace AsteriskSCF::Helpers;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+Logger logger = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
+}
+
+NATConfigPtr AsteriskSCF::PJMediaRTP::NATConfig::create(const Ice::PropertiesPtr& props,
+        const string& propertyPrefix)
+{
+    string prefix(propertyPrefix);
+    if (!prefix.empty() && prefix.back() != '.')
+    {
+        prefix += '.';
+    }
+
+    string hostname = props->getProperty(prefix + "Media.STUN.Server");
+    //
+    // XXX:
+    // This actually isn't necessarily an error, the STUN server can be determined from
+    // DNS records. Let's leave it for now.
+    //
+    //
+    if (hostname.empty())
+    {
+        throw InternalInitializationException("No STUN server configured");
+    }
+    
+    bool hasSTUN = true;
+    Ice::Int portProperty = props->getPropertyAsIntWithDefault(prefix + "Media.STUN.Port", PJ_STUN_PORT);
+    if (portProperty > UINT_MAX)
+    {
+        logger(Warning) << "Property `Media.STUN.Port' is out of range for IP port numbers, defaulting to "
+                        << PJ_STUN_PORT;
+        portProperty = PJ_STUN_PORT;
+    }
+
+    AddressSeq candidates(DNSQuery::create(hostname, portProperty)->execute());
+    if (candidates.empty())
+    {
+        throw InternalInitializationException("Unable to resolve configured STUN server");
+    }
+    AddressPtr stunAddress = candidates.front();
+        
+    //
+    // We read the properties even if TURN isn't enabled since we might make this runtime 
+    // switchable at some point and there is no harm in avoiding extra obstacles.
+    //
+    hostname = props->getProperty(prefix + "Media.TURN.Server.Hostname");
+    bool hasTURN = false;
+    AddressPtr turnAddress;
+    if (!hostname.empty())
+    {
+        portProperty = props->getPropertyAsIntWithDefault(prefix + "Media.TURN.Server.Port", 3479);
+        candidates = DNSQuery::create(hostname, portProperty)->execute();
+        if (!candidates.empty())
+        {
+            if (props->getPropertyAsIntWithDefault(prefix + "Media.TURN.Enable", 0) > 0)
+            {
+                hasTURN = true;
+            }
+            turnAddress = candidates.front();
+        }
+    }
+    return NATConfigPtr(new NATConfig(stunAddress, turnAddress, hasSTUN, hasTURN));
+}
+
+NATConfig::NATConfig(const AddressPtr& stunServer, const AddressPtr& turnServer,
+        bool enableSTUN, bool enableTURN) :
+    mSTUNServer(stunServer),
+    mTURNServer(turnServer),
+    mSTUNEnabled(enableSTUN),
+    mTURNEnabled(enableTURN)
+{
+}
diff --git a/src/NATConfig.h b/src/NATConfig.h
new file mode 100644
index 0000000..df86342
--- /dev/null
+++ b/src/NATConfig.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <AsteriskSCF/Helpers/Network.h>
+#include <Ice/PropertiesF.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+class NATConfig;
+typedef boost::shared_ptr<NATConfig> NATConfigPtr;
+
+class NATConfig
+{
+public:
+
+    AsteriskSCF::Helpers::AddressPtr stunServer() const
+    {
+        return mSTUNServer;
+    }
+    
+    bool isSTUNEnabled() const
+    {
+        return mSTUNEnabled;
+    }
+    
+    AsteriskSCF::Helpers::AddressPtr turnServer() const
+    {
+        return mTURNServer;
+    }
+    
+    bool isTURNEnabled() const
+    {
+        return mTURNEnabled;
+    }
+    
+    static NATConfigPtr create(const Ice::PropertiesPtr& properties, const std::string& prefix);
+private:
+    AsteriskSCF::Helpers::AddressPtr mSTUNServer;
+    AsteriskSCF::Helpers::AddressPtr mTURNServer;
+    bool mSTUNEnabled;
+    bool mTURNEnabled;
+
+    NATConfig(const AsteriskSCF::Helpers::AddressPtr& stunServer,
+            const AsteriskSCF::Helpers::AddressPtr& turnServer,
+            bool stunEnabled,
+            bool turnEnabled);
+
+    //
+    // Hidden and unimplemented.
+    //
+    NATConfig(const NATConfig&);
+    void operator=(const NATConfig&);
+};
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/NATModule.cpp b/src/NATModule.cpp
new file mode 100644
index 0000000..d788709
--- /dev/null
+++ b/src/NATModule.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "NATModule.h"
+#include <pjmedia.h>
+#include <pjnath.h>
+#include "PJUtil.h"
+#include <AsteriskSCF/System/ExceptionsIf.h>
+
+using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::PJUtil;
+
+NATModulePtr AsteriskSCF::PJMediaRTP::NATModule::create(const PJMediaEnvironmentPtr& environ)
+{
+    boost::shared_ptr<pj_ice_strans_cfg> transcfg(new pj_ice_strans_cfg);
+    pj_ice_strans_cfg_default(transcfg.get());
+    pj_stun_config_init(&transcfg->stun_cfg, environ->poolFactory(), 0,
+            pjmedia_endpt_get_ioqueue(environ->endpoint()), 0);
+    pj_status_t result = pj_timer_heap_create(environ->memoryPool(), environ->libConfig()->timerHeapSize(),
+            &transcfg->stun_cfg.timer_heap);
+    if (fail(result))
+    {
+        throw InternalInitializationException("Unable to initialize tier heap.");
+    }
+
+    pj_strdup2(environ->memoryPool(), &transcfg->stun.server, environ->natConfig()->stunServer()->hostname().c_str());
+    transcfg->stun.port = environ->natConfig()->stunServer()->port();
+    transcfg->stun.max_host_cands = environ->ICEConfig()->maxCandidates();
+    if (environ->natConfig()->isTURNEnabled())
+    {
+        pj_strdup2(environ->memoryPool(), &transcfg->turn.server, environ->natConfig()->turnServer()->hostname().c_str());
+        transcfg->turn.port = environ->natConfig()->turnServer()->port();
+    }
+
+    NATModulePtr moduleObj(new NATModule(transcfg));
+    moduleObj->startImpl();
+    return moduleObj;
+}
+
+NATModule::NATModule(const boost::shared_ptr<pj_ice_strans_cfg>& transConfig) :
+    mTransactionConfig(transConfig)
+{
+}
+
+NATModule::~NATModule()
+{
+    destroyImpl();
+}
+
+void NATModule::destroyImpl()
+{
+    pj_timer_heap_destroy(mTransactionConfig->stun_cfg.timer_heap);
+}
+
+void NATModule::startImpl()
+{
+}
+
diff --git a/src/NATModule.h b/src/NATModule.h
new file mode 100644
index 0000000..9b4c4bd
--- /dev/null
+++ b/src/NATModule.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "PJMediaEnvironment.h"
+#include <boost/shared_ptr.hpp>
+
+//
+// Forward declarations.
+//
+struct pj_ice_strans_cfg;
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+class NATModule;
+typedef boost::shared_ptr<NATModule> NATModulePtr;
+
+class NATModule
+{
+public:
+    ~NATModule();
+
+    static NATModulePtr create(const PJMediaEnvironmentPtr& environ);
+
+private:
+    boost::shared_ptr<pj_ice_strans_cfg> mTransactionConfig;
+
+    NATModule(const boost::shared_ptr<pj_ice_strans_cfg>& transactionConfig);
+
+    void destroyImpl();
+    void startImpl();
+
+    //
+    // Hidden and unimplemented.
+    //
+    NATModule(const NATModule&);
+    void operator=(const NATModule&);
+};
+
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/PJLibConfiguration.cpp b/src/PJLibConfiguration.cpp
new file mode 100644
index 0000000..62018ff
--- /dev/null
+++ b/src/PJLibConfiguration.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include "PJLibConfiguration.h"
+#include <Ice/Properties.h>
+
+using namespace std;
+using namespace AsteriskSCF::PJMediaRTP;
+
+PJLibConfigurationPtr AsteriskSCF::PJMediaRTP::PJLibConfiguration::create(const Ice::PropertiesPtr& props,
+        const string& propertyPrefix)
+{
+    string prefix(propertyPrefix);
+    if (!prefix.empty() && prefix.back() != '.')
+    {
+        prefix  += '.';
+    }
+    int timerHeapSize = props->getPropertyAsIntWithDefault(prefix + "TimerHeap.Size", 1000); 
+    return PJLibConfigurationPtr(new PJLibConfiguration(timerHeapSize));
+}
+
+PJLibConfiguration::PJLibConfiguration(int timerHeapSize) :
+    mTimerHeapSize(timerHeapSize)
+{
+}
diff --git a/src/PJLibConfiguration.h b/src/PJLibConfiguration.h
new file mode 100644
index 0000000..d0cc641
--- /dev/null
+++ b/src/PJLibConfiguration.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <Ice/PropertiesF.h>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+/**
+ * PJLibConfiguration is fairly minimal at the moment, but may grow in the future. The intent is to reduce code
+ * duplication when dealing with pjproject related configuration. This is also an immutable object, so locking is not an
+ * issue.
+ **/
+class PJLibConfiguration
+{
+public:
+
+    int timerHeapSize() const
+    {
+        return mTimerHeapSize;
+    }
+
+    /**
+     * Create configuration instance from Ice properties.  TODO: This could be extended by adding additional factory
+     * overrides.
+     **/
+    static boost::shared_ptr<PJLibConfiguration> create(const Ice::PropertiesPtr& props,
+            const std::string& propertyPrefix);
+
+private:
+    int mTimerHeapSize;
+
+    PJLibConfiguration(int timerHeapSize);
+
+    //
+    // Hidden, not implemented.
+    //
+    PJLibConfiguration(const PJLibConfiguration&);
+    void operator=(const PJLibConfiguration&);
+};
+
+typedef boost::shared_ptr<PJLibConfiguration> PJLibConfigurationPtr;
+
+} /* end of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/PJMediaEnvironment.cpp b/src/PJMediaEnvironment.cpp
new file mode 100644
index 0000000..12975d9
--- /dev/null
+++ b/src/PJMediaEnvironment.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "PJMediaEnvironment.h"
+#include <ICE/Properties.h>
+#include <pjlib.h>
+#include <pjmedia.h>
+#include <pjnath.h>
+#include "PJUtil.h"
+#include <AsteriskSCF/System/ExceptionsIf.h>
+
+using namespace std;
+using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::PJUtil;
+
+PJMediaEnvironmentPtr AsteriskSCF::PJMediaRTP::PJMediaEnvironment::create(const Ice::PropertiesPtr& props, const string& propertyPrefix)
+{
+    return PJMediaEnvironmentPtr(
+        new PJMediaEnvironment(PJLibConfiguration::create(props, propertyPrefix),
+                ICEConfiguration::create(props, propertyPrefix),
+                NATConfig::create(props, propertyPrefix)));
+}
+
+PJMediaEnvironment::PJMediaEnvironment(const PJLibConfigurationPtr& libConfig,
+        const ICEConfigurationPtr& iceConfig,
+        const NATConfigPtr& natConfig) :
+    mPJLibConfig(libConfig),
+    mICEConfig(iceConfig),
+    mNATConfig(natConfig),
+    mCachingPool(new pj_caching_pool)
+{
+    pj_caching_pool_init(mCachingPool.get(), & pj_pool_factory_default_policy, 0);
+    mPoolFactory = &(mCachingPool->factory);
+    
+    //
+    // TODO: should these values come from configuration.
+    //
+    mMemoryPool = pj_pool_create(mPoolFactory, "media_rtp_pjmedia", 1024, 1024, 0);
+    pj_status_t result = pjmedia_endpt_create(mPoolFactory, 0, 1, &mEndpoint);
+    if (fail(result))
+    {
+        throw InternalInitializationException("Unable to create PJMEDIA endpoint.");
+    }
+}
diff --git a/src/PJMediaEnvironment.h b/src/PJMediaEnvironment.h
new file mode 100644
index 0000000..d1dc494
--- /dev/null
+++ b/src/PJMediaEnvironment.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "PJLibConfiguration.h"
+#include "NATConfig.h"
+#include "ICEConfiguration.h"
+
+#include <Ice/PropertiesF.h>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+//
+// Forward declarations.
+//
+struct pj_pool_factory;
+struct pjmedia_endpt;
+struct pj_pool_t;
+struct pj_caching_pool;
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+class PJMediaEnvironment;
+typedef boost::shared_ptr<PJMediaEnvironment> PJMediaEnvironmentPtr;
+
+class PJMediaEnvironment
+{
+public:
+
+    PJLibConfigurationPtr libConfig() const
+    {
+        return mPJLibConfig;
+    }
+
+    NATConfigPtr natConfig() const
+    {
+        return mNATConfig;
+    }
+
+    ICEConfigurationPtr ICEConfig() const
+    {
+        return mICEConfig;
+    }
+
+    pj_pool_factory* poolFactory() const
+    {
+        return mPoolFactory;
+    }
+
+    pjmedia_endpt* endpoint() const
+    {
+        return mEndpoint;
+    }
+
+    pj_pool_t* memoryPool() const
+    {
+        return mMemoryPool;
+    }
+
+    static PJMediaEnvironmentPtr create(const Ice::PropertiesPtr& props, const std::string& prefix);
+
+private:
+
+    PJLibConfigurationPtr mPJLibConfig;
+    ICEConfigurationPtr mICEConfig;
+    NATConfigPtr mNATConfig;
+
+    pj_pool_factory* mPoolFactory;
+    pjmedia_endpt* mEndpoint;
+    pj_pool_t* mMemoryPool;
+    boost::shared_ptr<pj_caching_pool> mCachingPool;
+
+    PJMediaEnvironment(const PJLibConfigurationPtr& libConfig,
+            const ICEConfigurationPtr& iceConfig,
+            const NATConfigPtr& natconfig);
+};
+
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/PJUtil.h b/src/PJUtil.h
new file mode 100644
index 0000000..e2383ec
--- /dev/null
+++ b/src/PJUtil.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <pjlib.h>
+
+namespace AsteriskSCF
+{
+namespace PJUtil
+{
+
+/**
+ * Simple result checking functions overloaded on pj_status_t result type.
+ **/
+inline bool success(pj_status_t r)
+{
+    return r == PJ_SUCCESS;
+}
+
+inline bool fail(pj_status_t r)
+{
+    return !success(r);
+}
+
+} /* End of namespace PJUtil */
+} /* End of namespace AsteriskSCF */
diff --git a/src/RTPICESession.cpp b/src/RTPICESession.cpp
index e141a8f..fc3035b 100644
--- a/src/RTPICESession.cpp
+++ b/src/RTPICESession.cpp
@@ -15,330 +15,46 @@
  */
 
 #include "RTPICESession.h"
-
-#include <pjlib.h>
-#include <Ice/Ice.h>
-#include <IceUtil/UUID.h>
-
-#include <pjmedia.h>
-#include <pjnath.h>
-
-#include <AsteriskSCF/System/ExceptionsIf.h>
+#include "PJUtil.h"
 
 #include "RtpStateReplicationIf.h"
 
 #include "RTPSource.h"
 #include "RTPSink.h"
-
 #include "ServiceConfig.h"
+#include "NATConfig.h"
 
-#include <boost/bind.hpp>
+#include <pjlib.h>
+#include <pjmedia.h>
+#include <pjnath.h>
 
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
+#include <AsteriskSCF/System/ExceptionsIf.h>
+#include <AsteriskSCF/logger.h>
 #include <AsteriskSCF/Helpers/Network.h>
 
 using namespace std;
 using namespace AsteriskSCF::System::V1;
 using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media::RTP::V1;
-using namespace AsteriskSCF::RTPMedia;
 using namespace AsteriskSCF::Helpers;
 using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::PJUtil;
 
-//
-// Ideally this would be an anonymous namespace, but some compilers seem to have an issue with them
-//
-namespace ICEMediaSession
-{
-//
-// TODO: Move into header file.
-//
-static bool success(pj_status_t r)
-{
-    return r == PJ_SUCCESS;
-}
-
-static bool fail(pj_status_t r)
+namespace
 {
-    return !success(r);
+Logger logger = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
 }
 
-typedef AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx> StateReplicatorPrx;
-
 //
-// NOTE: This is a bit of a placeholder for a configuration abstraction. It makes a bit more sense
-// than inlining with initialization logic since config might come from anywhere.
-// 
-class NATConfig: public IceUtil::Shared
-{
-public:
-    NATConfig(const Ice::PropertiesPtr& props) :
-        mHasSTUNSettings(false),
-        mHasTURNSettings(false)
-    {
-        string hostname = props->getProperty("Media.STUN.Server");
-        //
-        // XXX:
-        // This actually isn't necessarily an error, the STUN server can be determined from
-        // DNS records. Let's leave it for now.
-        //
-        //
-        if (hostname.empty())
-        {
-            throw InternalInitializationException("No STUN server configured");
-        }
-
-        mHasSTUNSettings = true;
-        Ice::Int portProperty = props->getPropertyAsIntWithDefault("Media.STUN.Port", PJ_STUN_PORT);
-        if (portProperty > UINT_MAX)
-        {
-            logger(Warning) << "Property `Media.STUN.Port' is out of range for IP port numbers, defaulting to "
-                            << PJ_STUN_PORT;
-            portProperty = PJ_STUN_PORT;
-        }
-
-        AddressSeq candidates(DNSQuery::create(hostname, portProperty)->execute());
-        if (candidates.empty())
-        {
-            throw InternalInitializationException("Unable to resolve configured STUN server");
-        }
-        mSTUNAddress = candidates.front();
-        
-        //
-        // We read the properties even if TURN isn't enabled since we might make this runtime 
-        // switchable at some point and there is no harm in avoiding extra obstacles.
-        //
-        hostname = props->getProperty("Media.TURN.Server.Hostname");
-        if (!hostname.empty())
-        {
-            portProperty = props->getPropertyAsIntWithDefault("Media.TURN.Server.Port", 3479);
-            candidates = DNSQuery::create(hostname, portProperty)->execute();
-            if (!candidates.empty())
-            {
-                if (props->getPropertyAsIntWithDefault("Media.TURN.Enable", 0) > 0)
-                {
-                    mHasTURNSettings = true;
-                }
-                mTURNAddress = candidates.front();
-            }
-        }
-    }
-    
-    AddressPtr stunServer()
-    {
-        return mSTUNAddress;
-    }
-
-    bool hasSTUN() const
-    {
-        //
-        // This will always return true at the moment because we throw an exception in the constructor
-        // if we don't have the settings. However, if that exception is removed for some reason, this
-        // should return the actual value.
-        //
-        return mHasSTUNSettings; 
-    }
-
-    AddressPtr turnServer()
-    {
-        return mTURNAddress;
-    }
-
-    bool hasTURN() const
-    {
-        return mHasTURNSettings;
-    }
-
-private:
-    AddressPtr mSTUNAddress;
-    AddressPtr mTURNAddress;
-    bool mHasSTUNSettings;
-    bool mHasTURNSettings;
-};
-typedef IceUtil::Handle<NATConfig> NATConfigPtr;
-
-class PjLibConfiguration : public IceUtil::Shared
-{
-public:
-    //
-    // prefix makes a local copy on purpose!
-    // 
-    PjLibConfiguration(const Ice::PropertiesPtr& p, std::string prefix)
-    {
-        if (!prefix.empty() && prefix.back() != '.')
-        {
-            prefix += '.';
-        }
-        mTimerHeapSize = p->getPropertyAsIntWithDefault(prefix + "TimerHeap.Size", 1000); 
-    }
-
-    int timerHeapSize() const
-    {
-        return mTimerHeapSize;
-    }
-
-private:
-
-    Ice::Int mTimerHeapSize;
-};
-typedef IceUtil::Handle<PjLibConfiguration> PjLibConfigurationPtr;
-
-class ICEConfiguration : public PjLibConfiguration
-{
-public:
-    ICEConfiguration(const Ice::PropertiesPtr& p, std::string prefix) :
-        PjLibConfiguration(p, prefix)
-    {
-        if (!prefix.empty() && prefix.back() != '.')
-        {
-            prefix += '.';
-        }
-        mMaxCandidates = p->getPropertyAsIntWithDefault(prefix + "ICE.MaxCandidates", 2);
-    }
-
-    int maxCandidates() const
-    {
-        return mMaxCandidates;
-    }
-
-    int maxCalls() const
-    {
-        return mMaxCalls;
-    }
-
-private:
-    Ice::Int mMaxCandidates;
-    Ice::Int mMaxCalls;
-};
-
-typedef IceUtil::Handle<ICEConfiguration> ICEConfigurationPtr;
-
+// Ideally this would be an anonymous namespace, but some compilers seem to have an issue with them
 //
-// The NATModule takes care of some initialization and configuration details.
-// 
-class NATModule : public IceUtil::Shared
+namespace ICEMediaSession
 {
-public:
-    NATModule(const PjlibEnvironmentPtr& environ, const Ice::PropertiesPtr& props, const Logger& logger) :
-        mConfig(new NATConfig(props)),
-        mICEConfig(new ICEConfiguration(props, "Media.PJMedia."))
-    {
-        pj_ice_strans_cfg_default(&mPjICECfg);
-        pj_stun_config_init(&mPjICECfg.stun_cfg, environ->getPoolFactory(), 0
-            pjmedia_endpoint_get_ioqueue(environ->getMediaEndpoint()), 0);
-        pj_status_t result = pj_timer_heap_create(environ->getPool(), mPjICEConfig->timerHeapSize(),
-             &mPjICECfg.stun_cfg.timer_heap);
-        if (fail(result))
-        {
-            throw InternalInitializationException("Unable to initialize timer heap.");
-        }
-        pj_strdup2(environ->getPool(), mPjICECfg.stun.server, mConfig->stunServer()->hostname().c_str());
-        mPjICECfg.stun.port = mConfig->stunServer()->port();
-
-        mPjICECfg.stun.max_host_cands = mICEConfig->maxCandidates(); 
-        if (mConfig->hasTURN())
-        {
-            pj_strdup2(environ->getPool(), mICE.turn.server, mConfig->turnServer()->hostname().c_str());
-            mICE.turn.server.port = mConfig->turnServer()->port();
-
-            //
-            // TODO: TURN QoS settings.
-            // 
-        }
-        //
-        // TODO: QoS.
-        //
-    }
 
-    void start()
-    {
-        //
-        // commence resolving STUN server, etc.
-        //
-    }
-
-protected:
-    ~NATModule()
-    {
-        pj_time_heap_destroy(&mPjICECfg.timer_heap);
-    }
-
-private:
-    NATConfigPtr mNATConfig;
-    ICEConfigPtr mICEConfig;
-    pj_ice_strans_cfg mPjICECfg;
-    size_t mMaxCalls;
-};
-
-typedef IceUtil::Handle<NATModule> NATModulePtr;
-
-class PjLibEnvironment : public IceUtil::Shared
-{
-public:
-    PjLibEnvironment(pj_pool_factory* poolFactory, const Ice::PropertiesPtr& props, const Logger& logger) :
-        mPoolFactory(poolFactory),
-        mProperties(props),
-        mMediaEndpoint(0),
-        mPool(0),
-        mLogger(logger)
-    {
-        pj_status_t result = pjmedia_endpt_create(mPjLib->getPoolFactory(), 0, 1, &mEndpoint);
-        if (fail(result))
-        {
-            throw InternalInitializationException("Unable to create PJMEDIA endpoint.");
-        }
-    }
-    
-    pj_pool_factory* getPoolFactory() const
-    {
-        boost::shared_lock<boost::shared_mutex> lock(mLock);
-        return mPoolFactory;
-    }
-
-    pjmedia_endpoint* getMediaEndpoint() const
-    {
-        boost::shared_lock<boost::shared_mutex> lock(mLock);
-        return mMediaEndpoint;
-    }
-
-    pj_pool_t* getPool() const
-    {
-        boost::unique_lock<boost::shared_mutex> lock(mLock);
-        if (!mPool)
-        {
-            pj_status_t result = pjmedia_endpt_create_pool(mMediaEndpoint, "SESSPOOL", 1024, 512);
-            if (fail(result))
-            {
-                throw InternalInitializationException("Unable to initialize pool.");
-            }
-        }
-        return mPool;
-    }
-
-    NATModulePtr getNATModule()
-    {
-        boost::unique_lock<boost::shared_mutex> lock(mLock);
-        if (!mNATModule)
-        {
-            mNATModule = new NATModule(this, mProperties, mLogger);
-        }
-    }
-
-    void destroy()
-    {
-        boost::unique_lock<boost::shared_mutex> lock(mLock);
-        mNATModule = 0;
-    }
-
-private:
-    mutable boost::shared_mutex mLock;
-    pj_pool_factory* mPoolFactory;
-    Ice::PropertiesPtr mProperties;
-    pjmedia_endpoint* mMediaEndpoint;
-    NATModulePtr mNATModule;
-    pj_pool_t* mPool;
-    Logger mLogger;
-};
-typedef IceUtil::Handle<PjLibEnvironment> PjLibEnvironmentPtr;
+typedef AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> StateReplicatorPrx;
 
 class RTPSessionImpl : public RTPSession
 {
@@ -349,8 +65,8 @@ public:
     // amongst constructor versions and avoid exception prone calls in
     // the constructor itself.
     //
-    RTPSessionImpl(const FormatSeq& formats, const PjLibEnvironmentPtr& pjLib,
-            const ReplicatorPtr& replicaService, const StateReplicatorPrx& replicator);
+    RTPSessionImpl(const FormatSeq& formats, const PJMediaEnvironmentPtr& pjLib,
+            const StateReplicatorPrx& replicator);
 
     void initialize();
 
@@ -370,32 +86,44 @@ public:
     //
     // RTPSession.
     //
-    void associatePayLoads(const PayLoadMap& mappings, const Ice::Current& current);
+    void associatePayloads(const AsteriskSCF::Media::RTP::V1::PayloadMap& mappings, const Ice::Current& current);
     void useRTCP(bool enable, const Ice::Current& current);
     RTCPSessionPrx getRTCPSession(const Ice::Current& current);
     void release(const Ice::Current& current);
 
+    void onComplete(pj_ice_strans_op operationStatus, pj_status_t status);
+
     //
     // Internal methods.
     //
 private:
     boost::shared_mutex mLock;
     FormatSeq mFormats;
-    PjLibEnvironmentPtr mPjLib;
-    ReplicatorPtr mReplicaControl;
+    PJMediaEnvironmentPtr mMediaEnvironment;
     StateReplicatorPrx mReplicator;
-
-    //
-    // TODO: Should the endpoint belong to a different object. Could a single endpoint
-    // have multiple transports?
-    //
-    pjmedia_endpt* mEndpoint;
-    pjmedia_transport* mTransport;
-    
 };
 
 typedef IceUtil::Handle<RTPSessionImpl> RTPSessionImplPtr;
 
+class ICECallbackAdapter
+{
+
+public:
+    static void addEntry(pjmedia_transport* transport, const RTPSessionImplPtr& callback);
+    static void onICEComplete(pjmedia_transport* transport, pj_ice_strans_op operation, pj_status_t status);
+
+    struct CallbackRecord
+    {
+        bool connected;
+        RTPSessionImplPtr session;
+    };
+    typedef std::map<pjmedia_transport*, CallbackRecord> TransportMap;
+private:
+
+    static TransportMap mTransportMap;
+    static boost::shared_mutex mLock;
+};
+
 class SinkImpl : public StreamSinkRTP
 {
 public:
@@ -452,46 +180,35 @@ public:
     void destroy();
 };
 
-/**
- *
- * Base class to allow some polymorphic behavior on different pjmedia based transports.
- *
- **/ 
-class PJMediaTransport : public IceUtil::Shared
+class PJMediaTransport
 {
 public:
-    
-    pjmedia_transport* getTransport()
-    {
-        boost::shared_lock<boost::shared_mutex> lock(mLock);
-        return mTransport;
-    }
+    virtual ~PJMediaTransport() {}
 
-    Ice::Int getPort()
+    pjmedia_transport* getTransport() const
     {
-        boost::shared_lock<boost::shared_mutex> lock(mLock);
-        return mPort;
-
-    void destroy()
-    {
-        boost::unique_locK<boost::shared_mutex> lock(mLock);
-        pjmedia_transport_close(mTransport);
-        mPort = 0;
-        mTransport = 0;
+        return mTransport;
     }
 
 protected:
-    boost::shared_mutex mLock;
+
     pjmedia_transport* mTransport;
-    Ice::Int mPort;
 
-    PJMediaTransport(pjmedia_transport* t, const Ice::Int p) :
-        mTransport(t),
-        mPort(p)
+    PJMediaTransport(pjmedia_transport* t) :
+         mTransport(t)
     {
     }
 };
 
+typedef boost::shared_ptr<PJMediaTransport> PJMediaTransportPtr;
+
+//
+// ICE transport implementation.
+//
+class ICETransport;
+typedef boost::shared_ptr<ICETransport> ICETransportPtr;
+typedef boost::shared_ptr<pjmedia_ice_cb> PJICECallbackPtr;
+
 class ICETransport : public PJMediaTransport
 {
     //
@@ -501,13 +218,34 @@ class ICETransport : public PJMediaTransport
     void operator=(const ICETransport&);
     
 public:
-    static IceUtil::Handle<ICETransport> create(const PjLibEnvironmentPtr& pjlib)
+    static ICETransportPtr create(const PJMediaEnvironmentPtr& environment)
     {
-        pjmedia_ice_create(mPjLib->getMediaEndpoint(), "ASCF_ICE_MEDIA", 10, 0, &ICECallbackAdapter::onIceComplete,
-                &mTransport);
+        pjmedia_transport* t;
+        PJICECallbackPtr callback(new pjmedia_ice_cb);
+        callback->on_ice_complete = &ICECallbackAdapter::onICEComplete;
+        pj_status_t result = pjmedia_ice_create(environment->endpoint(), "ASCF_ICE_MEDIA", 10, 0, callback.get(),
+                &t);
+        if (fail(result))
+        {
+            throw InternalInitializationException("Unable to create new ICE media transport");
+        }
     }
+
+    ICETransport(pjmedia_transport* t, const PJICECallbackPtr& cb) :
+        PJMediaTransport(t),
+        mCallback(cb)
+    {
+    }
+
+private:
+    PJICECallbackPtr mCallback;
 };
-typedef IceUtil::Handle<ICETransport> ICETransportPtr;
+
+//
+// UDP transport implementation.
+//
+class UDPTransport;
+typedef boost::shared_ptr<UDPTransport> UDPTransportPtr;
 
 class UDPTransport : public PJMediaTransport
 {
@@ -521,22 +259,22 @@ public:
     //
     // Replicant version.
     //
-    static IceUtil::Handle<UDPTransport> create(const PjLibEnvironmentPtr& pjlib, Ice::Int port)
+    static UDPTransportPtr create(const PJMediaEnvironmentPtr& environment, Ice::Int port)
     {
         pjmedia_transport* transport;
-        pj_status_t result = pjmedia_transport_udp_create2(pjlib->getMediaEndpoint(), "RTP", 0, port, transport);
+        pj_status_t result = pjmedia_transport_udp_create2(environment->endpoint(), "RTP", 0, port, 0, &transport);
         if (fail(result))
         {
             throw InternalInitializationException("Unable to initialize UDP media transport on "
                     "replicant, port conflict!");
         }
-        return new UDPTransport(transport, port);
+        return UDPTransportPtr(new UDPTransport(transport));
     }
     
     //
     // Primary version.
     //
-    static IceUtil::Handle<UDPTransport> create(const PjLibEnvironmentPtr& pjlib, Ice::Int port)
+    static UDPTransportPtr create(const PJMediaEnvironmentPtr& pjlib, const Ice::PropertiesPtr& properties)
     {
         const Ice::Int minPort =
             properties->getPropertyAsIntWithDefault("AsteriskSCF.Media.Transport.UDPTransport.MinPort",
@@ -552,28 +290,22 @@ public:
         for (Ice::Int port = minPort; port < maxPort && port <= USHRT_MAX ; port +=2)
         {
             pjmedia_transport* transport;
-            pj_result_t result = pjmedia_transport_udp_create2(pjlib->getMediaEndpoint(), "RTP", 0, port, 0, &transport);
+            pj_status_t result = pjmedia_transport_udp_create2(pjlib->endpoint(), "RTP", 0, port, 0, &transport);
             if (success(result))
             {
-                return new UDPTransport(transport, port);
+                return UDPTransportPtr(new UDPTransport(transport));
             }
         }
         throw InternalInitializationException("Unable to initialize UDP media transport");
     }
 
 private:
-    UDPTransport(pjmedia_transport* t, const Ice::Int port) :
-        PJMediaTransport(t, port)
+    UDPTransport(pjmedia_transport* t) :
+        PJMediaTransport(t)
     {
     }
 };
-typedef IceUtil::Handle<UDPTransport> UDPTransportPtr;
 
-pjmedia_transport* PJMediaTransport::getTransport()
-{
-    boost::shared_lock<boost::shared_mutex> lock(mLock);
-    return mTransport;
-}
 
 //
 // For some reason the ICE media transport doesn't have the concept of associating user data with a transport, so we
@@ -582,130 +314,138 @@ pjmedia_transport* PJMediaTransport::getTransport()
 // the ICE completion callback arrives and there isn't a table entry. When the addEntry runs, it will see the entry and
 // simply update the appropriate field.
 // 
-class ICECallbackAdapter
+void ICECallbackAdapter::addEntry(pjmedia_transport* transport, const RTPSessionImplPtr& callback)
 {
-public:
-    struct CallbackRecord
+    boost::unique_lock<boost::shared_mutex> lock(mLock);
+    TransportMap::iterator i = mTransportMap.find(transport);
+    if (i != mTransportMap.end())
     {
-        bool connected;
-        RTPSessionImplPtr session;
-    };
-    typedef std::map<pjmedia_transport*, CallbackRecord> TransportMap;
-
-    static void addEntry(pjmedia_transport* transport, const RTPSessionImplPtr& callback)
+        i->second.session = callback;
+    }
+    else
     {
-        boost::unique_lock<boost::shared_mutex> lock(mLock);
-        TransportMap::iterator i = mTransportMap.find(transport);
-        if (i != mTransportMap.end())
-        {
-            i->second.session = callback;
-        }
-        else
-        {
-            CallbackRecord r;
-            r.connected = false;
-            r.session = callback;
-            mTransportMap.insert(make_pair(transport, r));
-        }
-
+        CallbackRecord r;
+        r.connected = false;
+        r.session = callback;
+        mTransportMap.insert(make_pair(transport, r));
     }
 
-    static void onICEComplete(pjmedia_transport* transport, pj_ice_strans_op operation, pj_status_t status)
+}
+
+void ICECallbackAdapter::onICEComplete(pjmedia_transport* transport, pj_ice_strans_op operation, pj_status_t status)
+{
+    //
+    // AFAICT, only PJ_ICE_STRANS_OP_NEGOTIATION should get here.
+    // 
+    switch (operation)
     {
         //
-        // AFAICT, only PJ_ICE_STRANS_OP_NEGOTIATION should get here.
-        // 
-        switch (operation)
-        {
+        // TODO: Fill out.
+        //
+        case PJ_ICE_STRANS_OP_INIT:
             //
-            // TODO: Fill out.
+            // Initialization is complete. FWICT, this should not get here.
             //
-            case PJ_ICE_STRANS_OP_INIT:
-                //
-                // Initialization is complete. FWICT, this should not get here.
-                //
-                break;
-            case PJ_ICE_STRANS_OP_NEGOTIATION:
-                //
-                // Negotiation is complete.
-                //
+            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())
             {
-                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));
-                }
-                else
-                {
-                    i->second.connected = true;
-                    i->second.session->onComplete(operation, status);
-                }
+                CallbackRecord r;
+                r.connected = true;
+                mTransportMap.insert(make_pair(transport, r));
             }
-                break;
-            case PJ_ICE_STRANS_OP_KEEP_ALIVE:
-                //
-                // Keep alive has successfully completed. FWICT this should not get here.
-                // 
-                break;
-            default:
-        };
-    }
-
-private:
+            else
+            {
+                i->second.connected = true;
+                i->second.session->onComplete(operation, status);
+            }
+        }
+            break;
+        case PJ_ICE_STRANS_OP_KEEP_ALIVE:
+            //
+            // Keep alive has successfully completed. FWICT this should not get here.
+            // 
+            break;
+    };
+}
 
-    static TransportMap mTransportMap;
-    static boost::shared_mutex mLock;
-};
+}
 
 //
 // Static member initializations.
 //
-IceCallbackAdapter::TransportMap IceCallbackAdapter::mTransportMap;
-boost::shared_mutex IceCallbackAdapter::mLock;
+ICEMediaSession::ICECallbackAdapter::TransportMap ICEMediaSession::ICECallbackAdapter::mTransportMap;
+boost::shared_mutex ICEMediaSession::ICECallbackAdapter::mLock;
 
-}
 using namespace ICEMediaSession;
 
-RTPSessionImpl::RTPSessionImpl(const FormatSeq& formats, const PjLibEnvironmentPtr& pjLib,
-        const ReplicatorPtr& replicaService, const StateReplicatorPrx& replicator) :
+ICEMediaSession::RTPSessionImpl::RTPSessionImpl(const FormatSeq& formats, const PJMediaEnvironmentPtr& environment,
+    const StateReplicatorPrx& replicator) :
     mFormats(formats),
-    mPjLib(pjLib),
-    mReplicaControl(replicaService),
-    mReplicator(replicator),
-    mBasePort(0),
-    mInitialized(false)
+    mMediaEnvironment(environment),
+    mReplicator(replicator)
 {
 }
 
-void RTPSessionImpl::initialize(const Ice::PropertiesPtr& properties)
+void ICEMediaSession::RTPSessionImpl::initialize()
 {
-    boost::unique_lock<boost::shared_mutex> lock(mLock);
-    pjmedia_ice_create(mPjLib->getMediaEndpoint(), "ASCF_ICE_MEDIA", 10, 0, &ICECallbackAdapter::onIceComplete,
-            &mTransport);
-    mInitialized = true;
+
 }
 
-void RTPSessionImpl::destroy()
+void ICEMediaSession::RTPSessionImpl::destroy()
+{
+}
+
+StreamSourceSeq ICEMediaSession::RTPSessionImpl::getSources(const Ice::Current&)
+{
+    return StreamSourceSeq();
+}
+
+StreamSinkSeq ICEMediaSession::RTPSessionImpl::getSinks(const Ice::Current&)
+{
+    return StreamSinkSeq();
+}
+
+std::string ICEMediaSession::RTPSessionImpl::getId(const Ice::Current&)
+{
+    return "";
+}
+
+void ICEMediaSession::RTPSessionImpl::associatePayloads(const AsteriskSCF::Media::RTP::V1::PayloadMap& mappings,
+    const Ice::Current&)
+{
+}
+
+void ICEMediaSession::RTPSessionImpl::useRTCP(bool enable, const Ice::Current&)
+{
+}
+
+RTCPSessionPrx ICEMediaSession::RTPSessionImpl::getRTCPSession(const Ice::Current&)
+{
+    return 0;
+}
+
+void ICEMediaSession::RTPSessionImpl::release(const Ice::Current&)
+{
+}
+
+void ICEMediaSession::RTPSessionImpl::onComplete(pj_ice_strans_op operationStatus, pj_status_t status)
 {
-    boost::unique_lock<boost::shared_mutex> lock(mLock);
-    if (mInitialized)
-    {
-        pjmedia_transport_close(&mTransport);
-        mInitialized = false;
-    }
 }
 
-RTPSessionPrx AsteriskSCF::RTPMedia::RTPICESession::create(const Ice::ObjectAdapterPtr& adapter,
+RTPSessionPrx AsteriskSCF::PJMediaRTP::RTPICESession::create(const Ice::ObjectAdapterPtr& adapter,
         const Ice::Identity& id,
-        const FormatSeq& formats, pj_pool_factory* factory, const ReplicatPtr& replicaService,
-        const AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>& stateReplicator)
+        const FormatSeq& formats, const PJMediaEnvironmentPtr& environment, 
+        const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator)
 {
-    RTPSessionImplPtr servant(new RTPSessionImpl(formats, new PjLibEnvironment(factory), replicaService,
+    ICEMediaSession::RTPSessionImplPtr servant(new ICEMediaSession::RTPSessionImpl(formats, environment,
                     stateReplicator));
     assert(adapter);
-    servant->initialize(adapter->getCommunicator()->getProperties());
     return RTPSessionPrx::uncheckedCast(adapter->add(servant, id));
 }
diff --git a/src/RTPICESession.h b/src/RTPICESession.h
index 8fdb320..bf6e583 100644
--- a/src/RTPICESession.h
+++ b/src/RTPICESession.h
@@ -19,11 +19,18 @@
 #include <AsteriskSCF/Media/MediaIf.h>
 #include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
-#include <AsteriskSCF/SmartProxy/SmartProxy.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
+#include "RtpStateReplicationIf.h"
+#include "PJMediaEnvironment.h"
+
+//
+// Forward declarations.
+//
+struct pj_pool_factory;
 
 namespace AsteriskSCF
 {
-namespace RTPMedia
+namespace PJMediaRTP
 {
 
 class RTPICESession
@@ -32,9 +39,8 @@ public:
     static AsteriskSCF::Media::RTP::V1::RTPSessionPrx create(const Ice::ObjectAdapterPtr& objectAdapter,
             const Ice::Identity& id,
             const AsteriskSCF::Media::V1::FormatSeq& formats,
-            pj_pool_factory* factory,
-            const ReplicaPtr& replicaService,
-            const AsteriskSCF::SmartProxy::SmartProxy<
+            const PJMediaEnvironmentPtr& environment,
+            const AsteriskSCF::Discovery::SmartProxy<
                 AsteriskSCF::Media::RTP::V1::RtpStateReplicatorPrx>& stateReplicator
     );
 };
diff --git a/src/RTPSession.cpp b/src/RTPSession.cpp
index b9e6eea..ec6a746 100644
--- a/src/RTPSession.cpp
+++ b/src/RTPSession.cpp
@@ -14,32 +14,26 @@
  * at the top of the source tree.
  */
 
-#include <pjlib.h>
-#include <Ice/Ice.h>
-#include <IceUtil/UUID.h>
-
-#include <pjmedia.h>
-
-#include <AsteriskSCF/Media/MediaIf.h>
-#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
-#include <AsteriskSCF/System/Component/ReplicaIf.h>
-#include <AsteriskSCF/System/ExceptionsIf.h>
-#include <AsteriskSCF/SmartProxy.h>
-
 #include "RtpStateReplicationIf.h"
-
 #include "RTPSession.h"
 #include "RTPSource.h"
 #include "RTPSink.h"
 #include "ServiceConfig.h"
 
+#include <pjlib.h>
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
+#include <AsteriskSCF/System/ExceptionsIf.h>
+
+#include <pjmedia.h>
+
 using namespace std;
 using namespace AsteriskSCF::Core::Discovery::V1;
 using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media::RTP::V1;
 using namespace AsteriskSCF::System::Component::V1;
 using namespace AsteriskSCF::System::V1;
-using namespace AsteriskSCF::SmartProxy;
+using namespace AsteriskSCF::Discovery;
 
 /**
  * Private implementation details for the RTPSessionImpl class.
@@ -49,7 +43,7 @@ class RTPSessionImplPriv
 public:
     RTPSessionImplPriv(const Ice::ObjectAdapterPtr& adapter, const FormatSeq& formats,
             const ReplicaPtr& replicaService,
-            const AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) :
+            const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) :
 	mAdapter(adapter), mFormats(formats),
         mSessionStateItem(new RtpSessionStateItem()),
         mReplicaService(replicaService), mStateReplicator(stateReplicator) { };
@@ -118,7 +112,7 @@ public:
     /**
      * A proxy to the state replicator where we are sending updates to.
      */
-    AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
+    AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
 };
 
 
@@ -132,7 +126,7 @@ public:
  */
 RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter, const FormatSeq& formats,
         pj_pool_factory* factory, const ReplicaPtr& replicaService,
-        const AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) : 
+        const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator) : 
     mImpl(new RTPSessionImplPriv(adapter, formats, replicaService, stateReplicator))
 {
     /* Add ourselves to the ICE ASM so we can be used. */
@@ -156,7 +150,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter, const Forma
     //
     // The candidate ports increment by two to allow "room" for both a control and a data port.
     //
-    for (int port = DefaultRTPPortMinimum; port < DefaultRTPPortMaximum; port += 2)
+    for (int port = AsteriskSCF::PJMediaRTP::DefaultRTPPortMinimum; port < AsteriskSCF::PJMediaRTP::DefaultRTPPortMaximum; port += 2)
     {
         if ((status = pjmedia_transport_udp_create2(mImpl->mEndpoint, "RTP", NULL, port, 0, &mImpl->mTransport)) ==
                 PJ_SUCCESS)
@@ -191,7 +185,9 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter, const Forma
 RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter, pj_pool_factory* factory,
         const Ice::Identity& sessionIdentity, const Ice::Identity& sinkIdentity, const Ice::Identity& sourceIdentity,
         Ice::Int port, const FormatSeq& formats) :
-    mImpl(new RTPSessionImplPriv(adapter, formats, 0, *(new AsteriskSCF::SmartProxy::SmartProxy<RtpStateReplicatorPrx>)))
+///
+// MEMORY LEAK XXX->>>
+    mImpl(new RTPSessionImplPriv(adapter, formats, 0, *(new AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>)))
 {
     mImpl->mProxy = RTPSessionPrx::uncheckedCast(adapter->add(this, sessionIdentity));
 
@@ -392,7 +388,7 @@ int RTPSessionImpl::getPayload(const FormatPtr& mediaformat)
 /**
  * API call which returns a pointer to the source.
  */
-StreamSourceRTPImplPtr RTPSessionImpl::getSource()
+StreamSourceRTPPtr RTPSessionImpl::getSource()
 {
     return mImpl->mStreamSource;
 }
diff --git a/src/RTPSession.h b/src/RTPSession.h
index a8e4b7a..30127f9 100644
--- a/src/RTPSession.h
+++ b/src/RTPSession.h
@@ -8,6 +8,13 @@
 
 #pragma once
 
+#include <AsteriskSCF/System/Component/ComponentServiceIf.h>
+#include <AsteriskSCF/System/Component/ReplicaIf.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
+#include <AsteriskSCF/Media/MediaIf.h>
+#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
+#include "RtpStateReplicationIf.h"
+
 #include <boost/shared_ptr.hpp>
 
 /**
@@ -15,25 +22,12 @@
  */
 class RTPSessionImplPriv;
 
-/**
- * Forward definition for our private implementation of StreamSinkRTP.
- */
-class StreamSinkRTPImpl;
-
-/**
- * A typedef which creates a smart pointer type for StreamSinkRTPImpl.
- */
-typedef IceUtil::Handle<StreamSinkRTPImpl> StreamSinkRTPImplPtr;
+//
+// Forward declarations.
+//
 
-/**
- * Forward definition for our private implementation of StreamSourceRTP.
- */
-class StreamSourceRTPImpl;
-
-/**
- * A typedef which creates a smart pointer type for StreamSourceRTPImpl.
- */
-typedef IceUtil::Handle<StreamSourceRTPImpl> StreamSourceRTPImplPtr;
+struct pjmedia_transport;
+struct pj_pool_factory;
 
 /**
  * Implementation of the RTPSession interface as defined in MediaRTPIf.ice
@@ -43,7 +37,7 @@ class RTPSessionImpl : public AsteriskSCF::Media::RTP::V1::RTPSession
 public:
     RTPSessionImpl(const Ice::ObjectAdapterPtr&, const AsteriskSCF::Media::V1::FormatSeq&,
             pj_pool_factory*, const AsteriskSCF::System::Component::V1::ReplicaPtr&, 
-            const AsteriskSCF::SmartProxy::SmartProxy<AsteriskSCF::Media::RTP::V1::RtpStateReplicatorPrx>&);
+            const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::Media::RTP::V1::RtpStateReplicatorPrx>&);
     RTPSessionImpl(const Ice::ObjectAdapterPtr&, pj_pool_factory*, const Ice::Identity&, const Ice::Identity&,
             const Ice::Identity&, Ice::Int, const AsteriskSCF::Media::V1::FormatSeq&);
     AsteriskSCF::Media::V1::StreamSourceSeq getSources(const Ice::Current&);
@@ -59,7 +53,7 @@ public:
     void setRemoteDetails(const std::string& address, Ice::Int port);
     AsteriskSCF::Media::V1::FormatPtr getFormat(int payload);
     int getPayload(const AsteriskSCF::Media::V1::FormatPtr& mediaformat);
-    StreamSourceRTPImplPtr getSource();
+    AsteriskSCF::Media::RTP::V1::StreamSourceRTPPtr getSource();
... 939 lines suppressed ...


-- 
asterisk-scf/integration/media_rtp_pjmedia.git



More information about the asterisk-scf-commits mailing list