[asterisk-scf-commits] asterisk-scf/integration/media_rtp_pjmedia.git branch "nat-support" created.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Wed Jun 29 12:06:28 CDT 2011
branch "nat-support" has been created
at 34121936d15aed3224d09748e00aba0480d8c619 (commit)
- Log -----------------------------------------------------------------
commit 34121936d15aed3224d09748e00aba0480d8c619
Author: Brent Eagles <beagles at digium.com>
Date: Wed Jun 29 13:22:05 2011 -0230
- Added an "environment class" that contains accessors to feature
specific configuration classes and instance wide pjmedia/pjlib
constructs.
- Created a base class, PJMediaTransport, to wrap/provide common functionality.
- Moved UDP specific code to be provided by the PJMediaTransport base class,
UDPTransport. Amongst other things, it provides support for adding
transport specific facets to the related session object.
- Added another subclass of the PJMediaTransport based on instantiating
a pjmedia provide ICE transport. This overrides the localAddress accessor
of the base class to return the result of the STUN binding request
performed by the ICE transport.
- Added another subclass of PJMediaTransport for instantiating the
pjmedia provided SRTP transport (placeholder). This transport
basically is a "wrapper" around the actual implementation transport.
- Added an implementation of InteractiveConnectionAgent that is
added as a facet when the the related RTPSession servant is activated.
- Added support for generating AsteriskSCF::System::NAT::Candidate instances
from the candidate data provided by the ICE session. These are
made available through the InteractiveConnectionAgent facet.
NOTE: there are a lot of details in the various RFCs that may require
modification not just the generation of these objects, but when they
can be properly created. It may also require a listener to notify
"users" of the media session of changes to the candidate list, etc.
- Added "adapter" interfaces to break the physical dependency between
the RTPSession implementation and the related sources and sinks as
well as the replication listener.
- Added new configuration elements for the ICE transport.
- Added a short test suite (incomplete) that directly manipulates some
of the ICE related functionality... much more is necessary really.
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/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice b/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
index 7f41167..6341639 100644
--- a/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
@@ -16,7 +16,6 @@
#pragma once
-#include <Ice/BuiltinSequences.ice>
#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.ice>
#include <AsteriskSCF/System/Component/ConfigurationIf.ice>
@@ -32,145 +31,225 @@ module MediaRTPPJMedia
["suppress"]
module V1
{
- /**
- * Service locator category for finding the configuration service
- */
- const string ConfigurationDiscoveryCategory = "RtpConfiguration";
-
- /**
- * Service locator parameters class for discovering the configuration service
- */
- unsliceable class RtpConfigurationParams extends AsteriskSCF::Core::Discovery::V1::ServiceLocatorParams
- {
- /**
- * Unique name for the configuration service
- */
- string name;
- };
-
- /**
- * Local visitor class for visiting RTP configuration groups
- */
- local class RtpConfigurationGroupVisitor extends AsteriskSCF::System::Configuration::V1::ConfigurationGroupVisitor
- {
- };
-
- /**
- * Generic RTP configuration group
- */
- ["visitor:RtpConfigurationGroupVisitor"] class RtpConfigurationGroup extends AsteriskSCF::System::Configuration::V1::ConfigurationGroup
- {
- };
-
- /**
- * General RTP configuration group that contains general items related to the RTP component as a whole
- */
- class RtpGeneralGroup extends RtpConfigurationGroup
- {
- };
-
- /**
- * Local visitor class for visiting RTP configuration items
- */
- local class RtpConfigurationItemVisitor extends AsteriskSCF::System::Configuration::V1::ConfigurationItemVisitor
- {
- };
-
- /**
- * Generic RTP configuration item
- */
- ["visitor:RtpConfigurationItemVisitor"] class RtpConfigurationItem extends AsteriskSCF::System::Configuration::V1::ConfigurationItem
- {
- };
-
- /**
- * Name that the port ranges configuration item should be inserted as
- */
- const string PortRangesItemName = "ports";
-
- /**
- * Port ranges configuration item
- *
- * This must be added to the general configuration group using the constant string
- * in PortRangesItemName
- *
- */
- class PortRangesItem extends RtpConfigurationItem
- {
- /**
- * Start port for RTP and RTCP sockets.
- *
- * Default value is 10000.
- *
- */
- int startPort = 10000;
-
- /**
- * End port for RTP and RTCP sockets.
- *
- * Default value is 20000.
- *
- */
- int endPort = 20000;
- };
-
- /**
- * Name that the worker thread count configuration item should be inserted as
- */
- const string WorkerThreadCountItemName = "workerThreadCount";
-
- /**
- * Worker thread count for incoming media configuration item
- *
- * This must be added to the general configuration group using the constant string
- * in WorkerThreadCountItemName
- *
- */
- class WorkerThreadCountItem extends RtpConfigurationItem
- {
- /**
- * Number of threads that should handle incoming media.
- *
- * Default value is 4.
- */
- int count = 4;
- };
-
- /**
- * Name that the IPv4 binding configuration item should be inserted as
- */
- const string BindingIPv4AddressItemName = "bindingIPv4";
-
- /**
- * Binding address for IPv4 traffic
- */
- class BindingIPv4Item extends RtpConfigurationItem
- {
- /**
- * Address that IPv4 sessions should be binded to.
- *
- * Default value is all.
- */
- string address;
- };
-
- /**
- * Name that the IPv6 binding configuration item should be inserted as
- */
- const string BindingIPv6AddressItemName = "bindingIPv6";
-
- /**
- * Binding address for IPv6 traffic
- */
- class BindingIPv6Item extends RtpConfigurationItem
- {
- /**
- * Address that IPv6 sessions should be binded to.
- *
- * Default value is all.
- */
- string address;
- };
+ /**
+ * Service locator category for finding the configuration service
+ */
+ const string ConfigurationDiscoveryCategory = "RtpConfiguration";
+
+ /**
+ * Service locator parameters class for discovering the configuration service
+ */
+ unsliceable class RtpConfigurationParams extends AsteriskSCF::Core::Discovery::V1::ServiceLocatorParams
+ {
+ /**
+ * Unique name for the configuration service
+ */
+ string name;
+ };
+
+ /**
+ * Local visitor class for visiting RTP configuration groups
+ */
+ local class RtpConfigurationGroupVisitor extends AsteriskSCF::System::Configuration::V1::ConfigurationGroupVisitor
+ {
+ };
+
+ /**
+ * Generic RTP configuration group
+ */
+ ["visitor:RtpConfigurationGroupVisitor"] class RtpConfigurationGroup extends AsteriskSCF::System::Configuration::V1::ConfigurationGroup
+ {
+ };
+
+ /**
+ * General RTP configuration group that contains general items related to the RTP component as a whole
+ */
+ class RtpGeneralGroup extends RtpConfigurationGroup
+ {
+ };
+
+ /**
+ * Local visitor class for visiting RTP configuration items
+ */
+ local class RtpConfigurationItemVisitor extends AsteriskSCF::System::Configuration::V1::ConfigurationItemVisitor
+ {
+ };
+
+ /**
+ * Generic RTP configuration item
+ */
+ ["visitor:RtpConfigurationItemVisitor"] class RtpConfigurationItem extends AsteriskSCF::System::Configuration::V1::ConfigurationItem
+ {
+ };
+
+ /**
+ * Name that the port ranges configuration item should be inserted as
+ */
+ const string PortRangesItemName = "ports";
+
+ /**
+ * Port ranges configuration item
+ *
+ * This must be added to the general configuration group using the constant string
+ * in PortRangesItemName
+ *
+ */
+ class PortRangesItem extends RtpConfigurationItem
+ {
+ /**
+ * Start port for RTP and RTCP sockets.
+ *
+ * Default value is 10000.
+ *
+ */
+ int startPort = 10000;
+
+ /**
+ * End port for RTP and RTCP sockets.
+ *
+ * Default value is 20000.
+ *
+ */
+ int endPort = 20000;
+ };
+
+ /**
+ * Name that the worker thread count configuration item should be inserted as
+ */
+ const string WorkerThreadCountItemName = "workerThreadCount";
+
+ /**
+ * Worker thread count for incoming media configuration item
+ *
+ * This must be added to the general configuration group using the constant string
+ * in WorkerThreadCountItemName
+ *
+ */
+ class WorkerThreadCountItem extends RtpConfigurationItem
+ {
+ /**
+ * Number of threads that should handle incoming media.
+ *
+ * Default value is 4.
+ */
+ int count = 4;
+ };
+
+ /**
+ * Name that the IPv4 binding configuration item should be inserted as
+ */
+ const string BindingIPv4AddressItemName = "bindingIPv4";
+
+ /**
+ * Binding address for IPv4 traffic
+ */
+ class BindingIPv4Item extends RtpConfigurationItem
+ {
+ /**
+ * Address that IPv4 sessions should be binded to.
+ *
+ * Default value is all.
+ */
+ string address;
+ };
+
+ /**
+ * Name that the IPv6 binding configuration item should be inserted as
+ */
+ const string BindingIPv6AddressItemName = "bindingIPv6";
+
+ /**
+ * Binding address for IPv6 traffic
+ */
+ class BindingIPv6Item extends RtpConfigurationItem
+ {
+ /**
+ * Address that IPv6 sessions should be binded to.
+ *
+ * Default value is all.
+ */
+ string address;
+ };
+
+ /*
+ * Configuration group for ICE enabled RTP.
+ */
+ class RTPICEConfigurationGroup extends RtpConfigurationGroup
+ {
+ };
+
+ /**
+ * Name that the STUN server configuration item should be inserted as.
+ */
+ const string STUNServerItemName = "stunServer";
+
+ /**
+ * Hostname for the STUN server.
+ */
+ ["visitor:RtpConfigurationItemVisitor"] class STUNServerItem extends RtpConfigurationItem
+ {
+ string address;
+ int port;
+ };
+
+ /**
+ * Name that the TURN server configuration item should be inserted as.
+ */
+ const string TURNServerItemName = "turnServer";
+
+ /**
+ * Hostname for the TURN server.
+ */
+ ["visitor:RtpConfigurationItemVisitor"] class TURNServerItem extends RtpConfigurationItem
+ {
+ string address;
+ int port;
+ };
+
+ /**
+ * Name that the ICE transport configuration flags item should be inserted as.
+ */
+ const string RTPICETransportFlagsItemName = "iceFlags";
+
+ /**
+ * Configuration item with option flags for the ICE transport.
+ */
+ ["visitor:RtpConfigurationItemVisitor"] class RTPICETransportFlagsItem extends RtpConfigurationItem
+ {
+ /**
+ * If the configuration option is present, it's most likely
+ * because we want to enable STUN and ICE
+ */
+ bool enableICE = true;
+
+ /**
+ * Using a TURN server as a candidate should be a selectable option
+ * since a TURN server isn't always available. Setting this to true
+ * while enableICE is false has no effect.
+ */
+ bool enableTURN = true;
+ };
+
+ /**
+ * Name that ICE option items should be inserted as.
+ */
+ const string RTPICELimitsItemName = "iceLimits";
+
+ /**
+ * Configuration item for configurable limits for the ICE transport.
+ */
+ ["visitor:RtpConfigurationItemVisitor"] class RTPICETransportLimitsItem extends RtpConfigurationItem
+ {
+ /**
+ * The maximum number of candidates to gather and publish.
+ */
+ int maxCandidates;
+
+ /**
+ * The maximum number of ICE negotiated flows to allow.
+ */
+ int maxCalls;
+ };
}; /* module V1 */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3909e11..13185bd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -13,12 +13,39 @@ astscf_component_add_files(media_rtp_pjmedia RtpStateReplicatorListener.cpp)
astscf_component_add_files(media_rtp_pjmedia RtpStateReplicator.h)
astscf_component_add_files(media_rtp_pjmedia RTPConfiguration.cpp)
astscf_component_add_files(media_rtp_pjmedia RTPConfiguration.h)
+astscf_component_add_files(media_rtp_pjmedia PJLibConfiguration.cpp)
+astscf_component_add_files(media_rtp_pjmedia PJLibConfiguration.h)
+astscf_component_add_files(media_rtp_pjmedia PJMediaEnvironment.cpp)
+astscf_component_add_files(media_rtp_pjmedia PJMediaEnvironment.h)
+astscf_component_add_files(media_rtp_pjmedia PJMediaTransport.cpp)
+astscf_component_add_files(media_rtp_pjmedia PJMediaTransport.h)
+astscf_component_add_files(media_rtp_pjmedia PJMediaEndpoint.cpp)
+astscf_component_add_files(media_rtp_pjmedia PJMediaEndpoint.h)
+astscf_component_add_files(media_rtp_pjmedia UDPTransport.cpp)
+astscf_component_add_files(media_rtp_pjmedia UDPTransport.h)
+astscf_component_add_files(media_rtp_pjmedia PJUtil.h)
+astscf_component_add_files(media_rtp_pjmedia ReplicationAdapter.h)
+astscf_component_add_files(media_rtp_pjmedia SessionAdapter.h)
+astscf_component_add_files(media_rtp_pjmedia Configuration.h)
+astscf_component_add_files(media_rtp_pjmedia NATConfig.cpp)
+astscf_component_add_files(media_rtp_pjmedia NATConfig.h)
+astscf_component_add_files(media_rtp_pjmedia NATModule.cpp)
+astscf_component_add_files(media_rtp_pjmedia NATModule.h)
+astscf_component_add_files(media_rtp_pjmedia ICEConfiguration.cpp)
+astscf_component_add_files(media_rtp_pjmedia ICEConfiguration.h)
+astscf_component_add_files(media_rtp_pjmedia ICETransport.cpp)
+astscf_component_add_files(media_rtp_pjmedia ICETransport.h)
+astscf_component_add_files(media_rtp_pjmedia SRTPConfiguration.cpp)
+astscf_component_add_files(media_rtp_pjmedia SRTPConfiguration.h)
+astscf_component_add_files(media_rtp_pjmedia SRTPTransport.cpp)
+astscf_component_add_files(media_rtp_pjmedia SRTPTransport.h)
astscf_component_add_slices(media_rtp_pjmedia PROJECT AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice)
astscf_component_add_slices(media_rtp_pjmedia PROJECT AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice)
astscf_component_add_boost_libraries(media_rtp_pjmedia core thread)
astscf_component_add_slice_collection_libraries(media_rtp_pjmedia ASTSCF)
astscf_component_build_icebox(media_rtp_pjmedia)
-target_link_libraries(media_rtp_pjmedia logging-client)
+target_link_libraries(media_rtp_pjmedia logging-client astscf-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/Configuration.h b/src/Configuration.h
new file mode 100755
index 0000000..dbe7f25
--- /dev/null
+++ b/src/Configuration.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 "PJLibConfiguration.h"
+#include "NATConfig.h"
+#include "ICEConfiguration.h"
+#include "SRTPConfiguration.h"
+
+#include <Ice/PropertiesF.h>
+#include <string>
+#include <IceUtil/Shared.h>
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+/**
+ * Base class for objects providing RTP service specific configuration data.
+ */
+
+class RTPConfiguration : public virtual IceUtil::Shared
+{
+public:
+ virtual ~RTPConfiguration() {}
+
+ virtual PJLibConfigurationPtr libConfig() const = 0;
+ virtual NATConfigPtr natConfig() const = 0;
+ virtual ICEConfigurationPtr ICEConfig() const = 0;
+ virtual SRTPConfigurationPtr srtpConfig() const = 0;
+
+ virtual int getStartPort() = 0;
+ virtual int getEndPort() = 0;
+ virtual int getWorkerThreadCount() = 0;
+ virtual std::string getBindIPv4Address() = 0;
+ virtual std::string getBindIPv6Address() = 0;
+};
+
+typedef IceUtil::Handle<RTPConfiguration> RTPConfigurationPtr;
+
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/ICEConfiguration.cpp b/src/ICEConfiguration.cpp
new file mode 100644
index 0000000..4ea0aaf
--- /dev/null
+++ b/src/ICEConfiguration.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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(int maxCand, int maxClls)
+{
+ return ICEConfigurationPtr(new ICEConfiguration(maxCand, maxClls));
+}
+
+ICEConfiguration::ICEConfiguration(int maxCand, int maxClls) :
+ mMaxCandidates(maxCand),
+ mMaxCalls(maxClls)
+{
+}
diff --git a/src/ICEConfiguration.h b/src/ICEConfiguration.h
new file mode 100644
index 0000000..450d4df
--- /dev/null
+++ b/src/ICEConfiguration.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ **/
+class ICEConfiguration
+{
+public:
+
+ int maxCandidates() const
+ {
+ return mMaxCandidates;
+ }
+
+ int maxCalls() const
+ {
+ return mMaxCalls;
+ }
+
+ /**
+ * Create configuration instance!
+ **/
+ static ICEConfigurationPtr create(int maxCand, int maxClls);
+
+private:
+ int mMaxCandidates;
+ int mMaxCalls;
+
+ ICEConfiguration(int maxCandidates, int maxCalls);
+
+ //
+ // Hidden and not implemented.
+ //
+ ICEConfiguration(const ICEConfiguration&);
+ void operator=(const ICEConfiguration&);
+};
+
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/ICETransport.cpp b/src/ICETransport.cpp
new file mode 100644
index 0000000..16ab255
--- /dev/null
+++ b/src/ICETransport.cpp
@@ -0,0 +1,605 @@
+/*
+ * 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 "ICETransport.h"
+#include "PJUtil.h"
+
+#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>
+#include <sstream>
+#include <AsteriskSCF/logger.h>
+#include <IceUtil/UUID.h>
+
+using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::PJUtil;
+using namespace std;
+using namespace AsteriskSCF::Helpers;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::NAT::V1;
+
+namespace
+{
+Logger logger = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
+}
+
+namespace
+{
+
+class ICEAgentImpl : public InteractiveConnectionAgent
+{
+public:
+
+ ICEAgentImpl(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id) :
+ mAdapter(adapter),
+ mId(id),
+ mShuttingDown(false),
+ mNATType(AsteriskSCF::System::NAT::V1::Unknown),
+ mRole(UndefinedRole)
+ {
+ }
+
+ AgentType getAgentType(const Ice::Current&)
+ {
+ return Full;
+ }
+
+ DetectedNATType getNATType(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ stateCheck();
+ return mNATType;
+ }
+
+ Role getRole(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ stateCheck();
+ return mRole;
+ }
+
+ CandidatePtr negotiate(const CandidateSeq&,
+ const Ice::Current&)
+ {
+ //
+ // TODO: implement.
+ //
+ return 0;
+ }
+
+ CandidateSeq getCandidates(const Ice::Current&)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ return 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(Controlling);
+ }
+ else
+ {
+ setRole(Controlled);
+ }
+
+ //
+ // Ok, so the pjmedia ice transport won't let use get at the actual
+ // candidate structures, so what we have to do is get the SDP from
+ // the transport and convert what we find there to our Ice structures.
+ //
+ pjmedia_sdp_session* sdpSession;
+ //
+ // TODO: We are setting the transport size at 1, but I'm not sure that will always be the case.
+ //
+ pjmedia_endpt_create_sdp(mEndpoint->endpoint(), mEnv->memoryPool(), 1, &info.sock_info, &sdpSession);
+ for (size_t i = 0; i < sdpSession->media_count; ++i)
+ {
+ const string candidateName("candidate");
+ pjmedia_sdp_media* media = sdpSession->media[i];
+ for (size_t j = 0; j < media->attr_count; ++j)
+ {
+ pjmedia_sdp_attr* attr = media->attr[j];
+ if (string(attr->name.ptr, attr->name.slen) == candidateName)
+ {
+ //
+ // Now we get to parse a candidate string!
+ //
+ string value(attr->value.ptr, attr->value.slen);
+ istringstream is(value);
+ string foundation;
+ if (!(is >> foundation))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (foundation) : " << value;
+ break;
+ }
+
+ int componentId;
+ if (!(is >> componentId))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (component id) : " << value;
+ break;
+ }
+
+ //
+ // We don't care about the transport right now.. we are assuming UDP.
+ //
+ string transportDummy;
+ if (!(is >> transportDummy))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (transport) : " << value;
+ break;
+ }
+
+ int priority;
+ if (!(is >> priority))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (priority) : " << value;
+ break;
+ }
+
+ string connectionAddress;
+ if (!(is >> connectionAddress))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (connection address) : " << value;
+ break;
+ }
+
+ unsigned port;
+ if (!(is >> port))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (connection port) : " << value;
+ break;
+ }
+
+ string candidateTypePrefix;
+ if (!(is >> candidateTypePrefix))
+ {
+ logger(Error) << "Unable to parse ICE candidate constant (typ) : " << value;
+ break;
+ }
+
+ string candidateType;
+ if (!(is >> candidateType))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (candidate type) : " << value;
+ break;
+ }
+
+ CandidatePtr candidateObj = new Candidate;
+ candidateObj->sessionId = IceUtil::generateUUID(); // this should be the object id.
+ candidateObj->componentId = 1; // At least until we implement RTCP.
+ candidateObj->priority = priority;
+ candidateObj->baseAddress = connectionAddress;
+ candidateObj->basePort = port;
+ candidateObj->transport = UDP;
+
+ if (candidateType == "host")
+ {
+ candidateObj->type = Host;
+ }
+ else if (candidateType == "srflx")
+ {
+ candidateObj->type = ServerReflexive;
+ }
+ else if (candidateType == "prflx")
+ {
+ candidateObj->type = PeerReflexive;
+ }
+ else if (candidateType == "relay")
+ {
+ candidateObj->type = Relayed;
+ }
+ else
+ {
+ logger(Error) << "Unable to determine the candidate type, skipping : " << value;
+ }
+
+ if (candidateType != "host")
+ {
+ string dummy;
+ if (!(is >> dummy))
+ {
+ logger(Error) << "Unable to parse ICE candidate constant (raddr) : " << value;
+ break;
+ }
+
+ string baseAddress;
+ if (!(is >> baseAddress))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (rel-addr) : " << value;
+ break;
+ }
+
+ if (!(is >> dummy))
+ {
+ logger(Error) << "Unable to parse ICE candidate constant (rport) : " << value;
+ break;
+ }
+
+ unsigned basePort;
+ if (!(is >> basePort))
+ {
+ logger(Error) << "Unable to parse ICE candidate value (rel-port) : " << value;
+ break;
+ }
+ candidateObj->baseAddress = baseAddress;
+ candidateObj->basePort = basePort;
+ }
+ else
+ {
+ candidateObj->baseAddress = candidateObj->mappedAddress;
+ candidateObj->basePort = candidateObj->mappedPort;
+ }
+ //
+ // And we ignore the rest.
+ //
+ mCandidates.push_back(candidateObj);
+ }
+ }
+ }
+ }
+ }
+
+ void shutdown()
+ {
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ if (mShuttingDown)
+ {
+ return;
+ }
+ mShuttingDown = true;
+ }
+ mAdapter->removeFacet(mId, "ICEAgent");
+ }
+
+ void setNATType(DetectedNATType natType)
+ {
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ mNATType = natType;
+ }
+
+ void setRole(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;
+ DetectedNATType mNATType;
+ Role mRole;
+ CandidateSeq mCandidates;
+ PJMediaEnvironmentPtr mEnv;
+ PJMediaEndpointPtr mEndpoint;
+
+ 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;
+
+private:
+ static TransportMap mTransportMap;
+ static boost::shared_mutex mLock;
+};
+
+//
+// Static member initializations.
+//
+ICECallbackAdapter::TransportMap ICECallbackAdapter::mTransportMap;
+boost::shared_mutex ICECallbackAdapter::mLock;
+
+//
+// For some reason the ICE media transport doesn't have the concept of associating user data with a transport, so we
+// have to map it "out of band". The problem is, there is a race condition in that the ICE completion callack could be
+// invoked before we get a chance to add the transport. The solution to that is to allow an entry to be created when
+// 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.
+//
+void ICECallbackAdapter::addEntry(pjmedia_transport* transport, const ICETransportPtr& callback)
+{
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ TransportMap::iterator i = mTransportMap.find(transport);
+ if (i != mTransportMap.end())
+ {
+ i->second.transport = callback;
+ callback->onSetupComplete(transport, PJ_SUCCESS);
+ }
+ else
+ {
+ CallbackRecord r;
+ r.connected = false;
+ r.transport = callback;
+ mTransportMap.insert(make_pair(transport, r));
+ }
+}
+
+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)
+{
+ //
+ // AFAICT, only PJ_ICE_STRANS_OP_NEGOTIATION should get here.
+ //
+ switch (operation)
+ {
+ case PJ_ICE_STRANS_OP_INIT:
+ //
+ // 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())
+ {
+ 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.
+ //
+ }
+ }
+ break;
+ case PJ_ICE_STRANS_OP_KEEP_ALIVE:
+ //
+ // Keep alive has successfully completed. FWICT this should not get here.
+ //
+ break;
+ };
+}
+
+}
+
+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)
+{
+ 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);
+ }
+ }
+
+ if (iceInfo != 0 && iceInfo->role == PJ_ICE_SESS_ROLE_CONTROLLING)
+ {
+ if (mLastKnownAddr && pj_sockaddr_cmp(&info.sock_info.rtp_addr_name, mLastKnownAddr.get()))
+ {
+ //
+ // Address has changed! We need to let Session listeners know!
+ // TODO!
+ //
+ pj_memcpy(mLastKnownAddr.get(), &info.sock_info.rtp_addr_name, sizeof(pj_sockaddr));
+ }
+ }
+ boost::unique_lock<boost::mutex> lock(mLock);
+ mLocalAddress = fromInfo(info);
+ mMonitor.notify_one();
+}
+
+AddressPtr ICETransport::localAddress()
+{
+ boost::unique_lock<boost::mutex> lock(mLock);
+ if (mLocalAddress)
+ {
+ return mLocalAddress;
+ }
+ for (size_t i = 0; i < 5 && !mLocalAddress; ++i)
+ {
+ mMonitor.wait(lock);
+ }
+ return mLocalAddress;
+}
+
+AddressPtr ICETransport::remoteAddress()
+{
+ boost::unique_lock<boost::mutex> lock(mLock);
+ 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, InteractiveConnectionAgentFacetName);
+}
+
+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(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");
+ }
+ ICECallbackAdapter::addEntry(t, shared_from_this());
+ mTransport = t;
+ mCallback = callback;
+ mNATModule = natModule;
+}
diff --git a/src/ICETransport.h b/src/ICETransport.h
new file mode 100644
index 0000000..678a830
--- /dev/null
+++ b/src/ICETransport.h
@@ -0,0 +1,90 @@
+/*
+ * 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 "PJMediaTransport.h"
+#include "PJMediaEndpoint.h"
+#include "PJMediaEnvironment.h"
+#include <Ice/PropertiesF.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include "NATModule.h"
+
+//
+// Forward declarations.
+//
+struct pjmedia_transport;
+union pj_sockaddr;
+struct pjmedia_ice_cb;
+
+namespace AsteriskSCF
+{
+namespace PJMediaRTP
+{
+
+class ICETransport;
+typedef boost::shared_ptr<ICETransport> ICETransportPtr;
+typedef boost::shared_ptr<pjmedia_ice_cb> PJICECallbackPtr;
+typedef boost::shared_ptr<pj_sockaddr> PJSockAddrPtr;
+
+class ICETransport : public boost::enable_shared_from_this<ICETransport>, public PJMediaTransport
+{
+public:
+
+ ~ICETransport();
+ void onSetupComplete(pjmedia_transport* transport, int status);
+
+ //
+ // Overrides of PJMediaTransport
+ //
+ AsteriskSCF::Helpers::AddressPtr localAddress();
+ AsteriskSCF::Helpers::AddressPtr remoteAddress();
+ void addFacets(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id);
+
+ /**
+ * The Microsoft VS 2010 C++ compiler doesn't like the forward declaration of ICETransport
+ * before the enable_shared_from_this<> base class/template instantiation.
+ **/
+ static ICETransportPtr
+ create(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& configObject);
+
+private:
+ boost::mutex mLock;
+ boost::condition_variable mMonitor;
+ AsteriskSCF::Helpers::AddressPtr mLocalAddress;
+ AsteriskSCF::Helpers::AddressPtr mRemoteAddress;
+ PJICECallbackPtr mCallback;
+ PJSockAddrPtr mLastKnownAddr;
+ NATModulePtr mNATModule;
+ PJMediaEndpointPtr mEndpoint;
+ PJMediaEnvironmentPtr mConfig;
+ bool mEnableRTCP;
+
+ ICETransport(const PJMediaEndpointPtr& ep, const PJMediaEnvironmentPtr& configObject);
+
+ void start();
+
+ //
+ // Hidden and unimplemented.
+ //
+ ICETransport(const ICETransport&);
+ void operator=(const ICETransport&);
+};
+
+
+} /* End of namespace PJMediaRTP */
+} /* End of namespace AsteriskSCF */
diff --git a/src/MediaRTPpjmedia.cpp b/src/MediaRTPpjmedia.cpp
index 6f59f07..ab26e67 100644
--- a/src/MediaRTPpjmedia.cpp
+++ b/src/MediaRTPpjmedia.cpp
@@ -40,6 +40,8 @@
#include "RTPConfiguration.h"
#include "RtpConfigurationIf.h"
+#include "PJMediaEnvironment.h"
+
using namespace std;
using namespace AsteriskSCF::Core::Discovery::V1;
using namespace AsteriskSCF::Media::V1;
@@ -50,6 +52,7 @@ using namespace AsteriskSCF::System::Configuration::V1;
using namespace AsteriskSCF::System::Component::V1;
using namespace AsteriskSCF::System::Logging;
using namespace AsteriskSCF::Discovery;
+using namespace AsteriskSCF::PJMediaRTP;
namespace
{
@@ -66,11 +69,17 @@ static const string MediaComparatorServiceId("RTPMediaServiceComparator");
class RTPMediaServiceImpl : public RTPMediaService
{
public:
- RTPMediaServiceImpl(const Ice::ObjectAdapterPtr&, const ReplicaPtr&,
+ RTPMediaServiceImpl(const Ice::ObjectAdapterPtr&, const ReplicaPrx&,
const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>&,
const ConfigurationServiceImplPtr&);
RTPSessionPrx allocate(const RTPServiceLocatorParamsPtr&, const Ice::Current&);
- pj_pool_factory *getPoolFactory() { return &mCachingPool.factory; };
+ pj_pool_factory *getPoolFactory() { return mEnvironment->poolFactory(); };
+
+ PJMediaEnvironmentPtr getEnvironment()
+ {
+ return mEnvironment;
+ }
+
private:
/**
* A pointer to the object adapter that objects should be added to.
@@ -78,19 +87,14 @@ private:
Ice::ObjectAdapterPtr mAdapter;
/**
- * Memory caching pool.
+ * The media environment object.
*/
- pj_caching_pool mCachingPool;
+ PJMediaEnvironmentPtr mEnvironment;
/**
- * Memory pool.
+ * A proxy for the replica service
*/
- pj_pool_t* mMemoryPool;
-
- /**
- * A pointer to the replica service.
- */
- ReplicaPtr mReplicaService;
+ ReplicaPrx mReplicaServicePrx;
/**
* A pointer to the configuration service.
@@ -101,6 +105,10 @@ private:
* A proxy to the state replicator.
*/
AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
+
+#if CONTROL_POINTS_ENABLED
+ AsteriskSCF::PJMediaRTPTesting mMediaServiceSwitchBoard;
+#endif
};
/**
@@ -179,6 +187,11 @@ private:
class RTPMediaServiceCompareServiceImpl : public ServiceLocatorParamsCompare
{
public:
+ RTPMediaServiceCompareServiceImpl(const ConfigurationServiceImplPtr& config) :
+ mConfig(config)
+ {
+ }
+
bool isSupported(const ServiceLocatorParamsPtr& locatorParams, const Ice::Current&)
{
RTPServiceLocatorParamsPtr params;
@@ -199,9 +212,45 @@ public:
result = false;
#endif
}
+ if (!result)
+ {
+ return false;
+ }
+
+ RTPOverICEServiceLocatorParamsPtr iceParams = RTPOverICEServiceLocatorParamsPtr::dynamicCast(locatorParams);
+ if (iceParams)
+ {
+ if (iceParams->enableRTPOverICE)
+ {
+ NATConfigPtr natConfig = mConfig->natConfig();
+
+ if (natConfig && natConfig->isSTUNEnabled())
+ {
+ if (iceParams->enableTURN)
+ {
+ if (!natConfig->isTURNEnabled())
+ {
+ result = false;
+ }
+ }
+ }
+ else
+ {
+ result = false;
+ }
+ }
+ //
+ // We ignore the else case because we can definitely do non-ICE related stuff... its not clear
+ // that negative matches in this case should be exclusionary. Actual ICE usage will be specified
+ // when the RTP session is allocated.
+ //
+ }
return result;
};
+
+private:
+ ConfigurationServiceImplPtr mConfig;
};
/**
@@ -246,6 +295,11 @@ private:
ReplicaPtr mReplicaService;
/**
+ * A proxy to the replica control object.
+ */
+ ReplicaPrx mReplicaServicePrx;
+
+ /**
* Instance of our configuration service implementation.
*/
ConfigurationServiceImplPtr mConfigurationService;
@@ -420,17 +474,15 @@ typedef IceUtil::Handle<RtpConfigurationCompare> RtpConfigurationComparePtr;
/**
* Constructor for the RTPMediaServiceImpl class.
*/
-RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, const ReplicaPtr& replicaService,
+RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, const ReplicaPrx& replicaService,
const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator,
const ConfigurationServiceImplPtr& configurationService) :
- mAdapter(adapter), mReplicaService(replicaService), mConfigurationService(configurationService),
+ mAdapter(adapter),
+ mEnvironment(PJMediaEnvironment::create(adapter->getCommunicator()->getProperties(), configurationService)),
+ mReplicaServicePrx(replicaService),
+ mConfigurationService(configurationService),
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", 1000, 1000, NULL);
}
/**
@@ -438,10 +490,8 @@ RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, c
*/
RTPSessionPrx RTPMediaServiceImpl::allocate(const RTPServiceLocatorParamsPtr& params, const Ice::Current&)
{
- RTPSessionImplPtr session =
- new RTPSessionImpl(mAdapter, params, &mCachingPool.factory, mReplicaService, mStateReplicator,
- mConfigurationService);
- return session->getProxy();
+ return AsteriskSCF::PJMediaRTP::RTPSession::create(mAdapter, IceUtil::generateUUID(), params, mEnvironment,
+ mReplicaServicePrx, mStateReplicator, mConfigurationService);
}
/**
@@ -482,12 +532,10 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
mLocalAdapter = mCommunicator->createObjectAdapter("MediaRTPpjmediaAdapterLocal");
mReplicaService = new ReplicaImpl(mLocalAdapter);
- mLocalAdapter->add(mReplicaService, mCommunicator->stringToIdentity(ReplicaServiceId));
-
- mConfigurationService = new ConfigurationServiceImpl();
- ConfigurationServicePrx mConfigurationServiceProxy = ConfigurationServicePrx::uncheckedCast(
- mLocalAdapter->addWithUUID(mConfigurationService));
+ mReplicaServicePrx = ReplicaPrx::uncheckedCast(mLocalAdapter->add(mReplicaService, mCommunicator->stringToIdentity(ReplicaServiceId)));
+ mConfigurationService = ConfigurationServiceImpl::create();
+ ConfigurationServicePrx mConfigurationServiceProxy = mConfigurationService->activate(mLocalAdapter, IceUtil::generateUUID());
mLocalAdapter->activate();
mGlobalAdapter = mCommunicator->createObjectAdapter("MediaRTPpjmediaAdapter");
@@ -505,7 +553,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
RtpStateReplicatorParamsPtr replicatorParams = new RtpStateReplicatorParams();
replicatorParams->category = StateReplicatorDiscoveryCategory;
replicatorParams->mName =
- mCommunicator->getProperties()->getPropertyWithDefault("Sip.StateReplicatorName", "default");
+ mCommunicator->getProperties()->getPropertyWithDefault("Rtp.StateReplicatorName", "default");
try
{
@@ -518,7 +566,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
}
RTPMediaServiceImplPtr rtpmediaservice =
- new RTPMediaServiceImpl(mGlobalAdapter, mReplicaService, mStateReplicator, mConfigurationService);
+ new RTPMediaServiceImpl(mGlobalAdapter, mReplicaServicePrx, mStateReplicator, mConfigurationService);
if (mCommunicator->getProperties()->getPropertyWithDefault("Rtp.Standalone", "false") == "true")
{
@@ -550,7 +598,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
if (mStateReplicator)
{
mReplicatorListener =
- new RtpStateReplicatorListenerI(mGlobalAdapter, rtpmediaservice->getPoolFactory(), mGeneralState,
+ new RtpStateReplicatorListenerI(mGlobalAdapter, rtpmediaservice->getEnvironment(), mGeneralState,
mConfigurationService);
mReplicatorListenerProxy =
RtpStateReplicatorListenerPrx::uncheckedCast(mLocalAdapter->addWithUUID(mReplicatorListener));
@@ -567,7 +615,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
}
}
- ServiceLocatorParamsComparePtr rtpmediacomparatorservice = new RTPMediaServiceCompareServiceImpl();
+ ServiceLocatorParamsComparePtr rtpmediacomparatorservice = new RTPMediaServiceCompareServiceImpl(mConfigurationService);
ServiceLocatorParamsComparePrx RTPMediaComparatorServiceProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
mGlobalAdapter->add(rtpmediacomparatorservice, mCommunicator->stringToIdentity(MediaComparatorServiceId)));
@@ -581,14 +629,31 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
RTPMediaServicePrx RTPMediaServiceProxy = RTPMediaServicePrx::uncheckedCast(mGlobalAdapter->add(rtpmediaservice,
mCommunicator->stringToIdentity(MediaServiceId)));
- RTPServiceLocatorParamsPtr rtpparams = new RTPServiceLocatorParams();
+ RTPOverICEServiceLocatorParamsPtr rtpparams = new RTPOverICEServiceLocatorParams;
+ rtpparams->category = "rtp";
+ PJMediaEnvironmentPtr mediaEnvironment = rtpmediaservice->getEnvironment();
+
+ //
+ // Service wide configuration is done through properties allowing certain features
+ // to be completely disabled.
+ //
+ NATConfigPtr natConfig = mediaEnvironment->natConfig();
+ if (natConfig && natConfig->isSTUNEnabled())
+ {
+ rtpparams->enableRTPOverICE = true;
+ rtpparams->enableTURN = natConfig->isTURNEnabled();
+ }
+ else
+ {
+ rtpparams->enableRTPOverICE = false;
+ rtpparams->enableTURN = false;
+ }
if (mReplicaService->isActive() == true)
{
mGeneralState->mServiceManagement = ServiceManagementPrx::uncheckedCast(
mManagement->addService(RTPMediaServiceProxy, "media_rtp_pjmedia"));
/* Now we can add some parameters to help find us. */
- rtpparams->category = "rtp";
mGeneralState->mServiceManagement->addLocatorParams(rtpparams, mGeneralState->mComparatorId);
}
@@ -601,7 +666,7 @@ void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& c
/* Let's add the component service to the service locator first */
mComponentServiceManagement =
- ServiceManagementPrx::uncheckedCast(mManagement->addService(ComponentServiceProxy, "media_rtp_pjmedia"));
+ ServiceManagementPrx::uncheckedCast(mManagement->addService(ComponentServiceProxy, "media_rtp_pjmedia.component"));
genericparams->category = "Component/media_rtp_pjmedia";
mComponentServiceManagement->addLocatorParams(genericparams, "");
diff --git a/src/NATConfig.cpp b/src/NATConfig.cpp
new file mode 100644
index 0000000..d31656d
--- /dev/null
+++ b/src/NATConfig.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 NATConfig::create(const AsteriskSCF::Helpers::AddressPtr& stunSrv, bool enableSTUN,
+ const AsteriskSCF::Helpers::AddressPtr& turnSrv, bool enableTURN)
+{
+ return NATConfigPtr(new NATConfig(stunSrv, turnSrv, enableSTUN, enableTURN));
+}
+
+NATConfig::NATConfig(const AddressPtr& stun, const AddressPtr& turn,
+ bool enableSTUN, bool enableTURN) :
+ mSTUNServer(stun),
+ mTURNServer(turn),
+ mSTUNEnabled(enableSTUN),
+ mTURNEnabled(enableTURN)
+{
+ std::cerr << "creating a NATConfig object with " << (mSTUNServer ? mSTUNServer->toString() : "<no stun>") << " and " <<
+ (mTURNServer ? mTURNServer->toString() : "<no turn>") << std::endl;
+}
diff --git a/src/NATConfig.h b/src/NATConfig.h
new file mode 100644
index 0000000..ac87662
--- /dev/null
+++ b/src/NATConfig.h
@@ -0,0 +1,76 @@
+/*
+ * 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 AsteriskSCF::Helpers::AddressPtr& stunSrv, bool enableSTUN,
+ const AsteriskSCF::Helpers::AddressPtr& turnSrv, bool enableTURN);
+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..3b5636f
--- /dev/null
+++ b/src/NATModule.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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& env,
+ const PJMediaEndpointPtr& endpoint)
+{
+ 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, env->poolFactory(), 0,
+ pjmedia_endpt_get_ioqueue(endpoint->endpoint()), 0);
+ pj_status_t result = pj_timer_heap_create(env->memoryPool(), env->libConfig()->timerHeapSize(),
+ &transcfg->stun_cfg.timer_heap);
+ if (fail(result))
+ {
+ throw InternalInitializationException("Unable to initialize tier heap.");
+ }
+
+ pj_strdup2(env->memoryPool(), &transcfg->stun.server, env->natConfig()->stunServer()->hostname().c_str());
+ transcfg->stun.port = static_cast<pj_uint16_t>(env->natConfig()->stunServer()->port());
+ ICEConfigurationPtr iceConfig = env->ICEConfig();
+ if (iceConfig)
+ {
+ transcfg->stun.max_host_cands = env->ICEConfig()->maxCandidates();
+ }
+ else
+ {
+ transcfg->stun.max_host_cands = 5; // XX arbitrary.
+ }
+ if (env->natConfig()->isTURNEnabled())
+ {
+ if (env->natConfig()->turnServer())
+ {
+ pj_strdup2(env->memoryPool(), &transcfg->turn.server, env->natConfig()->turnServer()->hostname().c_str());
+ transcfg->turn.port = static_cast<pj_uint16_t>(env->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..fa834ef
--- /dev/null
+++ b/src/NATModule.h
@@ -0,0 +1,63 @@
+/*
+ * 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 "PJMediaEndpoint.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();
+
+ pj_ice_strans_cfg* configuration()
+ {
+ return mTransactionConfig.get();
+ }
+
+ static NATModulePtr create(const PJMediaEnvironmentPtr& environ, const PJMediaEndpointPtr& endpoint);
+
+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&);
... 4092 lines suppressed ...
--
asterisk-scf/integration/media_rtp_pjmedia.git
More information about the asterisk-scf-commits
mailing list