[asterisk-scf-commits] asterisk-scf/release/media_rtp_pjmedia.git branch "master" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Mon Aug 8 03:08:33 CDT 2011
branch "master" has been updated
via ba68890ab24ec2f71cac3236b1cbacb40ee400da (commit)
from 2c243e51b0c9f544fd44ecc83d7cc69ac1e98ebf (commit)
Summary of changes:
config/test_component.config | 2 +
config/test_component_v6.config | 2 +
.../MediaRTPPJMedia/RtpConfigurationIf.ice | 11 -
.../MediaRTPPJMedia/RtpStateReplicationIf.ice | 5 -
src/CMakeLists.txt | 3 +-
src/Component.cpp | 621 +++++++++++++++++
src/MediaRTPpjmedia.cpp | 716 --------------------
src/RTPConfiguration.h | 1 +
src/RTPSession.cpp | 79 +--
src/RTPSession.h | 6 +-
src/RTPSource.cpp | 4 +-
src/RtpReplicationContext.h | 78 +++
src/RtpStateReplicator.h | 5 +-
src/RtpStateReplicatorApp.cpp | 124 +---
src/RtpStateReplicatorListener.cpp | 153 +++--
test/TestRTPICE.cpp | 5 +-
test/TestRTPpjmedia.cpp | 161 +++---
17 files changed, 943 insertions(+), 1033 deletions(-)
create mode 100644 src/Component.cpp
delete mode 100644 src/MediaRTPpjmedia.cpp
create mode 100644 src/RtpReplicationContext.h
- Log -----------------------------------------------------------------
commit ba68890ab24ec2f71cac3236b1cbacb40ee400da
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Aug 8 03:08:11 2011 -0500
Refactored to use base Component class and expanded ServiceLocatorParams.
diff --git a/config/test_component.config b/config/test_component.config
index fb6e341..d507786 100644
--- a/config/test_component.config
+++ b/config/test_component.config
@@ -7,6 +7,8 @@
IceBox.InheritProperties=1
IceBox.LoadOrder=ServiceDiscovery,RtpStateReplicator,MediaRTPpjmedia,MediaRTPpjmediaTest
+Ice.Override.Timeout=5000
+
# RtpStateReplicator Configuration
IceBox.Service.RtpStateReplicator=RtpStateReplicator:create
diff --git a/config/test_component_v6.config b/config/test_component_v6.config
index 36021d4..7349902 100644
--- a/config/test_component_v6.config
+++ b/config/test_component_v6.config
@@ -7,6 +7,8 @@
IceBox.InheritProperties=1
IceBox.LoadOrder=ServiceDiscovery,RtpStateReplicator,MediaRTPpjmedia,MediaRTPpjmediaTest
+Ice.Override.Timeout=5000
+
# RtpStateReplicator Configuration
IceBox.Service.RtpStateReplicator=RtpStateReplicator:create
diff --git a/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice b/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
index 1198f65..7853123 100644
--- a/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/MediaRTPPJMedia/RtpConfigurationIf.ice
@@ -37,17 +37,6 @@ module V1
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
diff --git a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
index 4c44683..b6f49ad 100644
--- a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
@@ -39,11 +39,6 @@ module V1
const string StateReplicatorComponentCategory = "RtpStateReplicatorComponent";
const string StateReplicatorDiscoveryCategory = "RtpStateReplicator";
- unsliceable class RtpStateReplicatorParams extends AsteriskSCF::Core::Discovery::V1::ServiceLocatorParams
- {
- string name;
- };
-
["visitor"] local class RtpStateItemVisitor
{
};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 13185bd..28e729d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,13 +2,14 @@ include_directories(${astscf-ice-util-cpp_dir}/include)
include_directories(${logger_dir}/include)
astscf_component_init(media_rtp_pjmedia)
-astscf_component_add_files(media_rtp_pjmedia MediaRTPpjmedia.cpp)
+astscf_component_add_files(media_rtp_pjmedia Component.cpp)
astscf_component_add_files(media_rtp_pjmedia RTPSession.cpp)
astscf_component_add_files(media_rtp_pjmedia RTPSource.cpp)
astscf_component_add_files(media_rtp_pjmedia RTPSink.cpp)
astscf_component_add_files(media_rtp_pjmedia RTPSession.h)
astscf_component_add_files(media_rtp_pjmedia RTPSource.h)
astscf_component_add_files(media_rtp_pjmedia RTPSink.h)
+astscf_component_add_files(media_rtp_pjmedia RtpReplicationContext.h)
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)
diff --git a/src/Component.cpp b/src/Component.cpp
new file mode 100644
index 0000000..efee798
--- /dev/null
+++ b/src/Component.cpp
@@ -0,0 +1,621 @@
+/*
+ * 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 <pjlib.h>
+#include <pjmedia.h>
+
+#include <Ice/Ice.h>
+#include <IceBox/IceBox.h>
+#include <IceUtil/UUID.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
+#include <AsteriskSCF/Media/MediaIf.h>
+#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
+#include <AsteriskSCF/System/Component/ConfigurationIf.h>
+#include <AsteriskSCF/Logger/IceLogger.h>
+#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/Discovery/SmartProxy.h>
+#include <AsteriskSCF/Component/Component.h>
+
+#include "RtpReplicationContext.h"
+#include "RTPSession.h"
+#include "RtpStateReplicator.h"
+#include "RTPConfiguration.h"
+#include "RtpConfigurationIf.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::Replication::MediaRTPPJMedia::V1;
+using namespace AsteriskSCF::Configuration::MediaRTPPJMedia::V1;
+using namespace AsteriskSCF::System::Configuration::V1;
+using namespace AsteriskSCF::System::Component::V1;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::Discovery;
+using namespace AsteriskSCF::Replication;
+using namespace AsteriskSCF::PJMediaRTP;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
+}
+
+static const string ReplicaServiceId("MediaRtpReplica");
+static const string MediaServiceId("RTPMediaService");
+static const string MediaComparatorServiceId("RTPMediaServiceComparator");
+
+/**
+ * Implementation of the RTPMediaService interface as defined in MediaRTPIf.ice
+ */
+class RTPMediaServiceImpl : public RTPMediaService
+{
+public:
+ RTPMediaServiceImpl(const Ice::ObjectAdapterPtr&,
+ const RtpReplicationContextPtr& replicationContext,
+ const ConfigurationServiceImplPtr&);
+
+ RTPSessionPrx allocate(const RTPServiceLocatorParamsPtr&, const Ice::Current&);
+ pj_pool_factory *getPoolFactory() { return mEnvironment->poolFactory(); };
+
+ PJMediaEnvironmentPtr getEnvironment()
+ {
+ return mEnvironment;
+ }
+
+private:
+ Ice::ObjectAdapterPtr mAdapter;
+ PJMediaEnvironmentPtr mEnvironment;
+ RtpReplicationContextPtr mReplicationContext;
+ ConfigurationServiceImplPtr mConfigurationService;
+
+#if CONTROL_POINTS_ENABLED
+ AsteriskSCF::PJMediaRTPTesting mMediaServiceSwitchBoard;
+#endif
+};
+
+/**
+ * Typedef which gives us a smart pointer type for RTPMediaServiceImpl class.
+ */
+typedef IceUtil::Handle<RTPMediaServiceImpl> RTPMediaServiceImplPtr;
+
+/**
+ * Implementation of the ServiceLocatorParamsCompare class
+ */
+class RTPMediaServiceCompareServiceImpl : public ServiceLocatorParamsCompare
+{
+public:
+ RTPMediaServiceCompareServiceImpl(const ConfigurationServiceImplPtr& config) :
+ mConfig(config)
+ {
+ }
+
+ bool isSupported(const ServiceLocatorParamsPtr& locatorParams, const Ice::Current&)
+ {
+ RTPServiceLocatorParamsPtr params;
+
+ if (!(params = RTPServiceLocatorParamsPtr::dynamicCast(locatorParams)))
+ {
+ return false;
+ }
+
+ bool result = true;
+
+ // This is done on purpose for additional checks in the future
+ if (params->ipv6 == true)
+ {
+#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
+ result = true;
+#else
+ result = false;
+#endif
+ }
+ //
+ // We can ignore the SRTP criteria since we support it one way or the other.
+ //
+ 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;
+};
+
+/**
+ * Implementation of the Component class.
+ */
+class Component : public AsteriskSCF::Component::Component
+{
+public:
+ Component() :
+ AsteriskSCF::Component::Component(lg, AsteriskSCF::Media::RTP::V1::ComponentServiceDiscoveryCategory),
+ mListeningToReplicator(false), mGeneralState(new RtpGeneralStateItem()) { mGeneralState->key = IceUtil::generateUUID(); };
+
+private:
+ // Required base Component overrides
+ virtual void createPrimaryServices();
+ virtual void preparePrimaryServicesForDiscovery();
+ virtual void createReplicationStateListeners();
+ virtual void stopListeningToStateReplicators();
+ virtual void listenToStateReplicators();
+ virtual void findRemoteServices();
+ virtual void onRegisterPrimaryServices();
+
+ // Optional base Component notifcation overrides
+ virtual void onSuspend();
+ virtual void onResume();
+ virtual void onPreInitialize();
+ virtual void onStop();
+ virtual void onStart();
+
+ // Other base Component overrides
+ virtual void prepareBackplaneServicesForDiscovery();
+ ReplicationContextPtr createReplicationContext(ReplicationStateType state);
+
+ // A proxy to the service locator manager for the component service.
+ ServiceManagementPrx mComponentServiceManagement;
+
+ // State replicator listener.
+ RtpStateReplicatorListenerPtr mReplicatorListener;
+ RtpStateReplicatorListenerPrx mReplicatorListenerProxy;
+ bool mListeningToReplicator;
+
+ // An instance of the general state information class.
+ RtpGeneralStateItemPtr mGeneralState;
+
+ // Media service
+ RTPMediaServiceImplPtr mRtpMediaServicePtr;
+ RTPMediaServicePrx mRtpMediaServicePrx;
+ LocatorRegistrationWrapperPtr mRtpMediaServiceRegistration;
+
+ // Media comparator service
+ ServiceLocatorParamsComparePtr mRtpMediaComparatorService;
+ ServiceLocatorParamsComparePrx mRtpMediaComparatorServicePrx;
+ RTPOverICEServiceLocatorParamsPtr mRtpOverIceLocatorParams;
+
+ // Configuration state
+ ConfigurationServiceImplPtr mConfigurationService;
+ ConfigurationServicePrx mConfigurationServicePrx;
+ LocatorRegistrationWrapperPtr mConfigurationRegistration;
+};
+
+void Component::onSuspend()
+{
+ mGeneralState->serviceManagement->suspend();
+}
+
+void Component::onResume()
+{
+ mGeneralState->serviceManagement->unsuspend();
+}
+
+/**
+ * Wrapper class around pj_thread_desc.
+ */
+class ThreadDescWrapper
+{
+public:
+ /**
+ * pjthread thread description information, must persist for the life of the thread
+ */
+ pj_thread_desc mDesc;
+};
+
+/**
+ * Type definition used to create a smart pointer for the above.
+ */
+typedef boost::shared_ptr<ThreadDescWrapper> ThreadDescWrapperPtr;
+
+/**
+ * Implementation of the Ice::ThreadNotification class.
+ */
+class pjlibHook : public Ice::ThreadNotification
+{
+public:
+ /**
+ * Implementation of the start function which is called when a thread starts.
+ */
+ void start()
+ {
+ ThreadDescWrapperPtr wrapper = ThreadDescWrapperPtr(new ThreadDescWrapper());
+ pj_thread_t *thread;
+ pj_thread_register("ICE Thread", wrapper->mDesc, &thread);
+ boost::lock_guard<boost::mutex> lock(mLock);
+ pjThreads.insert(make_pair(thread, wrapper));
+ }
+
+ /**
+ * Implementation of the stop function which is called when a thread stops.
+ */
+ void stop()
+ {
+ if (pj_thread_is_registered())
+ {
+ boost::lock_guard<boost::mutex> lock(mLock);
+ pjThreads.erase(pj_thread_this());
+ }
+ }
+private:
+ /**
+ * A map containing thread lifetime persistent data.
+ */
+ map<pj_thread_t*, ThreadDescWrapperPtr> pjThreads;
+
+ /**
+ * Mutex to protect the map
+ */
+ boost::mutex mLock;
+};
+
+/**
+ * Constructor for the RTPMediaServiceImpl class.
+ */
+RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter,
+ const RtpReplicationContextPtr& replicationContext,
+ const ConfigurationServiceImplPtr& configurationService) :
+ mAdapter(adapter),
+ mEnvironment(PJMediaEnvironment::create(adapter->getCommunicator()->getProperties(), configurationService)),
+ mReplicationContext(replicationContext),
+ mConfigurationService(configurationService)
+{
+}
+
+/**
+ * Implementation of the allocate method as defined in MediaRTPIf.ice
+ */
+RTPSessionPrx RTPMediaServiceImpl::allocate(const RTPServiceLocatorParamsPtr& params, const Ice::Current&)
+{
+ return AsteriskSCF::PJMediaRTP::RTPSession::create(mAdapter, IceUtil::generateUUID(), params, mEnvironment,
+ mReplicationContext, mConfigurationService);
+}
+
+void Component::onPreInitialize()
+{
+ /* Initialize pjlib as pjmedia will be using it */
+ pj_status_t status = pj_init();
+ if (status != PJ_SUCCESS)
+ {
+ lg(Error) << "PJ library initialization failed.";
+ return;
+ }
+
+ if ((status = pjlib_util_init()) != PJ_SUCCESS)
+ {
+ lg(Error) << "PJ Utility library initialization failed.";
+ return;
+ }
+
+ lg(Info) << "Initializing pjmedia rtp component" << endl;
+
+ Ice::InitializationData id;
+ id.threadHook = new pjlibHook();
+ id.properties = getCommunicator()->getProperties();
+
+ // To use our thread-hook, we need to set an alternate
+ // communicator in our Component base.
+ setCommunicator(Ice::initialize(id));
+}
+
+/**
+ * Override of factory method to create our custom replication context.
+ */
+ReplicationContextPtr Component::createReplicationContext(ReplicationStateType state)
+{
+ RtpReplicationContextPtr context(new RtpReplicationContext(state));
+ return context;
+}
+
+/**
+ * Create the objects that implement the main services this component provides
+ * the system.
+ */
+void Component::createPrimaryServices()
+{
+ try
+ {
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ mConfigurationService = ConfigurationServiceImpl::create();
+ mConfigurationServicePrx = mConfigurationService->activate(getBackplaneAdapter(), IceUtil::generateUUID());
+
+ mRtpMediaServicePtr =
+ new RTPMediaServiceImpl(getServiceAdapter(), rtpReplicationContext, mConfigurationService);
+ mRtpMediaServicePrx = RTPMediaServicePrx::uncheckedCast(getServiceAdapter()->add(mRtpMediaServicePtr,
+ getCommunicator()->stringToIdentity(MediaServiceId)));
+
+ mRtpMediaComparatorService = new RTPMediaServiceCompareServiceImpl(mConfigurationService);
+ mRtpMediaComparatorServicePrx = ServiceLocatorParamsComparePrx::uncheckedCast(
+ getServiceAdapter()->add(mRtpMediaComparatorService,
+ getCommunicator()->stringToIdentity(MediaComparatorServiceId)));
+
+
+ mRtpOverIceLocatorParams = new RTPOverICEServiceLocatorParams;
+ mRtpOverIceLocatorParams->category = "rtp";
+ PJMediaEnvironmentPtr mediaEnvironment = mRtpMediaServicePtr->getEnvironment();
+
+ //
+ // Service wide configuration is done through properties allowing certain features
+ // to be completely disabled.
+ //
+ NATConfigPtr natConfig = mediaEnvironment->natConfig();
+ if (natConfig && natConfig->isSTUNEnabled())
+ {
+ mRtpOverIceLocatorParams->enableRTPOverICE = true;
+ mRtpOverIceLocatorParams->enableTURN = natConfig->isTURNEnabled();
+ }
+ else
+ {
+ mRtpOverIceLocatorParams->enableRTPOverICE = false;
+ mRtpOverIceLocatorParams->enableTURN = false;
+ }
+
+ if (rtpReplicationContext->isActive() == true)
+ {
+ mGeneralState->comparatorId = IceUtil::generateUUID();
+ getServiceLocatorManagement()->addCompare(mGeneralState->comparatorId, mRtpMediaComparatorServicePrx);
+ }
+
+ }
+ catch(const Ice::Exception& e)
+ {
+ lg(Critical) << getName() << " : " << BOOST_CURRENT_FUNCTION << " : " << e.what();
+ }
+}
+
+/**
+ * Prepare this component's backplane interfaces for the Service Locator.
+ * This enables other Asterisk SCF components to locate our interfaces.
+ */
+void Component::prepareBackplaneServicesForDiscovery()
+{
+ // Insure the default Component services are prepped.
+ AsteriskSCF::Component::Component::prepareBackplaneServicesForDiscovery();
+
+ try
+ {
+ // Register our configuration interface with the Service Locator.
+ mConfigurationRegistration = wrapServiceForRegistration(mConfigurationServicePrx,
+ ConfigurationDiscoveryCategory);
+ manageBackplaneService(mConfigurationRegistration);
+ }
+ catch(const std::exception& e)
+ {
+ lg(Error) << "Exception in " << getName() << ", " << BOOST_CURRENT_FUNCTION << " : " << e.what();
+ }
+}
+
+void Component::findRemoteServices()
+{
+ if (getReplicationContext()->getState() == ACTIVE_STANDALONE)
+ {
+ return;
+ }
+
+ // Look for the configured state replicator or default one
+ ServiceLocatorParamsPtr replicatorParams = new ServiceLocatorParams();
+ replicatorParams->category = StateReplicatorDiscoveryCategory;
+ replicatorParams->service =
+ getCommunicator()->getProperties()->getPropertyWithDefault("Rtp.StateReplicatorService", "default");
+
+ try
+ {
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> pw(getServiceLocator(), replicatorParams, lg);
+ rtpReplicationContext->setReplicator(pw);
+
+ // Since we're not in standalone mode, we'll get our configuration updates routed via the
+ // replicator service.
+ ConfigurationReplicatorPrx configurationReplicator = ConfigurationReplicatorPrx::checkedCast(
+ rtpReplicationContext->getReplicator().initialize(), ReplicatorFacet);
+ configurationReplicator->registerConfigurationService(mConfigurationServicePrx);
+
+ }
+ catch (const std::exception& e)
+ {
+ lg(Error) << getName() << ": " << BOOST_CURRENT_FUNCTION << " State replicator could not be found, operating without. " << e.what();
+ }
+}
+
+void Component::createReplicationStateListeners()
+{
+ try
+ {
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ // Create and publish our state replicator listener interface.
+ mReplicatorListener = new RtpStateReplicatorListenerI(getServiceAdapter(), mRtpMediaServicePtr->getEnvironment(),
+ mGeneralState, rtpReplicationContext, mConfigurationService);
+ RtpStateReplicatorListenerPrx replicatorListener = RtpStateReplicatorListenerPrx::uncheckedCast(
+ getBackplaneAdapter()->addWithUUID(mReplicatorListener));
+ mReplicatorListenerProxy = RtpStateReplicatorListenerPrx::uncheckedCast(replicatorListener->ice_oneway());
+
+ lg(Debug) << "Got proxy to RTP state replicator";
+ }
+ catch(const Ice::Exception &e)
+ {
+ lg(Error) << getName() << " in " << BOOST_CURRENT_FUNCTION << " : " << e.what();
+ throw;
+ }
+}
+
+void Component::listenToStateReplicators()
+{
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ if (mListeningToReplicator == true)
+ {
+ return;
+ }
+
+ if (!rtpReplicationContext->getReplicator().isInitialized())
+ {
+ lg(Error) << getName() << " : State replicator could not be found. Unable to listen for state updates!";
+ return;
+ }
+
+ try
+ {
+ // Are we in standby mode?
+ if (rtpReplicationContext->getState() == STANDBY_IN_REPLICA_GROUP)
+ {
+ rtpReplicationContext->getReplicator()->addListener(mReplicatorListenerProxy);
+ mListeningToReplicator = true;
+ }
+ }
+ catch (const Ice::Exception& e)
+ {
+ lg(Error) << e.what();
+ throw;
+ }
+}
+
+/**
+ * Unregister as a listener to our state replicator.
+ * A component in active mode doesn't neeed to listen to
+ * state replication data.
+ */
+void Component::stopListeningToStateReplicators()
+{
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ if ((!rtpReplicationContext->getReplicator().isInitialized()) || (mListeningToReplicator == false))
+ {
+ return;
+ }
+
+ try
+ {
+ rtpReplicationContext->getReplicator()->removeListener(mReplicatorListenerProxy);
+ mListeningToReplicator = false;
+ }
+ catch (const Ice::Exception& e)
+ {
+ lg(Error) << e.what();
+ throw;
+ }
+}
+
+/**
+ * Prepares this component's primary public interfaces for discovery via the Service Locator.
+ * This enables other Asterisk SCF components to locate the interfaces we are publishing.
+ */
+void Component::preparePrimaryServicesForDiscovery()
+{
+ try
+ {
+ mRtpMediaServiceRegistration = wrapServiceForRegistration(mRtpMediaServicePrx,
+ "rtp");
+ managePrimaryService(mRtpMediaServiceRegistration);
+ }
+ catch(const std::exception& e)
+ {
+ lg(Error) << "Unable to publish component interfaces in " << getName() << BOOST_CURRENT_FUNCTION <<
+ ". Exception: " << e.what();
+ throw; // rethrow
+ }
+}
+
+void Component::onRegisterPrimaryServices()
+{
+ if (getReplicationContext()->isActive() == false)
+ {
+ return;
+ }
+
+ mGeneralState->serviceManagement = mRtpMediaServiceRegistration->getServiceMangement();
+ mGeneralState->serviceManagement->addLocatorParams(mRtpOverIceLocatorParams, mGeneralState->comparatorId);
+}
+
+void Component::onStart()
+{
+ // Note: I don't think this is necessary. If we make the
+ // comparator computed from a "service" identifier (which could default
+ // to "default"), there's nothing replicated here that the standby component
+ // couldn't already determine itself.
+ if (getReplicationContext()->isReplicating() == true)
+ {
+ RtpReplicationContextPtr rtpReplicationContext =
+ static_pointer_cast<RtpReplicationContext>(getReplicationContext());
+
+ RtpStateItemSeq items;
+ items.push_back(mGeneralState);
+ RtpStateReplicatorPrx oneway = RtpStateReplicatorPrx::uncheckedCast(rtpReplicationContext->getReplicator()->ice_oneway());
+ oneway->setState(items);
+ }
+}
+
+void Component::onStop()
+{
+ if (getReplicationContext()->isActive() == true)
+ {
+ mGeneralState->serviceManagement->unregister();
+ }
+
+ if (!mGeneralState->comparatorId.empty())
+ {
+ getServiceLocatorManagement()->removeCompare(mGeneralState->comparatorId);
+ }
+}
+
+extern "C"
+{
+ASTSCF_DLL_EXPORT IceBox::Service* create(Ice::CommunicatorPtr)
+{
+ return new Component;
+}
+}
diff --git a/src/MediaRTPpjmedia.cpp b/src/MediaRTPpjmedia.cpp
deleted file mode 100644
index 9b2933f..0000000
--- a/src/MediaRTPpjmedia.cpp
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * 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 <pjlib.h>
-#include <pjmedia.h>
-
-#include <Ice/Ice.h>
-#include <IceBox/IceBox.h>
-#include <IceUtil/UUID.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
-#include <AsteriskSCF/Media/MediaIf.h>
-#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
-#include <AsteriskSCF/System/Component/ConfigurationIf.h>
-#include <AsteriskSCF/System/Component/ComponentServiceIf.h>
-#include <AsteriskSCF/System/Component/ReplicaIf.h>
-#include <AsteriskSCF/Logger/IceLogger.h>
-#include <AsteriskSCF/logger.h>
-#include <AsteriskSCF/Discovery/SmartProxy.h>
-
-#include "RtpStateReplicationIf.h"
-
-#include "RTPSession.h"
-#include "RtpStateReplicator.h"
-#include "RTPConfiguration.h"
-#include "RtpConfigurationIf.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::Replication::MediaRTPPJMedia::V1;
-using namespace AsteriskSCF::Configuration::MediaRTPPJMedia::V1;
-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
-{
-Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
-}
-
-static const string ReplicaServiceId("MediaRtpReplica");
-static const string MediaServiceId("RTPMediaService");
-static const string MediaComparatorServiceId("RTPMediaServiceComparator");
-
-/**
- * Implementation of the RTPMediaService interface as defined in MediaRTPIf.ice
- */
-class RTPMediaServiceImpl : public RTPMediaService
-{
-public:
- 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 mEnvironment->poolFactory(); };
-
- PJMediaEnvironmentPtr getEnvironment()
- {
- return mEnvironment;
- }
-
-private:
- /**
- * A pointer to the object adapter that objects should be added to.
- */
- Ice::ObjectAdapterPtr mAdapter;
-
- /**
- * The media environment object.
- */
- PJMediaEnvironmentPtr mEnvironment;
-
- /**
- * A proxy for the replica service
- */
- ReplicaPrx mReplicaServicePrx;
-
- /**
- * A pointer to the configuration service.
- */
- ConfigurationServiceImplPtr mConfigurationService;
-
- /**
- * A proxy to the state replicator.
- */
- AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
-
-#if CONTROL_POINTS_ENABLED
- AsteriskSCF::PJMediaRTPTesting mMediaServiceSwitchBoard;
-#endif
-};
-
-/**
- * Typedef which gives us a smart pointer type for RTPMediaServiceImpl class.
- */
-typedef IceUtil::Handle<RTPMediaServiceImpl> RTPMediaServiceImplPtr;
-
-/**
- * This class provides implementation for the Replica interface.
- */
-class ReplicaImpl : public Replica
-{
-public:
- ReplicaImpl(const Ice::ObjectAdapterPtr& adapter) : mAdapter(adapter), mPaused(false), mActive(true) { }
-
- bool isActive(const Ice::Current&)
- {
- return mActive;
- }
-
- bool activate(const Ice::Current&)
- {
- mActive = true;
-
- for (vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx>::const_iterator listener =
- mListeners.begin(); listener != mListeners.end(); ++listener)
- {
- (*listener)->activated(ReplicaPrx::uncheckedCast(
- mAdapter->createDirectProxy(mAdapter->getCommunicator()->stringToIdentity(ReplicaServiceId))));
- }
-
- return true;
- }
-
- void standby(const Ice::Current&)
- {
- mActive = false;
-
- for (vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx>::const_iterator listener =
- mListeners.begin(); listener != mListeners.end(); ++listener)
- {
- (*listener)->onStandby(ReplicaPrx::uncheckedCast(
- mAdapter->createDirectProxy(mAdapter->getCommunicator()->stringToIdentity(ReplicaServiceId))));
- }
- }
-
- void addListener(const AsteriskSCF::System::Component::V1::ReplicaListenerPrx& listener, const Ice::Current&)
- {
- mListeners.push_back(listener);
- }
-
- void removeListener(const AsteriskSCF::System::Component::V1::ReplicaListenerPrx& listener, const Ice::Current&)
- {
- mListeners.erase(std::remove(mListeners.begin(), mListeners.end(), listener), mListeners.end());
- }
-
-private:
- /**
- * Pointer to the object adapter we exist on.
- */
- Ice::ObjectAdapterPtr mAdapter;
-
- /**
- * Listeners that we need to push state change notifications out to.
- */
- vector<AsteriskSCF::System::Component::V1::ReplicaListenerPrx> mListeners;
-
- bool mPaused;
-
- bool mActive;
-};
-
-/**
- * Implementation of the ServiceLocatorParamsCompare class
- */
-class RTPMediaServiceCompareServiceImpl : public ServiceLocatorParamsCompare
-{
-public:
- RTPMediaServiceCompareServiceImpl(const ConfigurationServiceImplPtr& config) :
- mConfig(config)
- {
- }
-
- bool isSupported(const ServiceLocatorParamsPtr& locatorParams, const Ice::Current&)
- {
- RTPServiceLocatorParamsPtr params;
-
- if (!(params = RTPServiceLocatorParamsPtr::dynamicCast(locatorParams)))
- {
- return false;
- }
-
- bool result = true;
-
- // This is done on purpose for additional checks in the future
- if (params->ipv6 == true)
- {
-#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
- result = true;
-#else
- result = false;
-#endif
- }
- //
- // We can ignore the SRTP criteria since we support it one way or the other.
- //
- 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;
-};
-
-/**
- * Implementation of the IceBox::Service class
- */
-class MediaRTPpjmediaApp : public IceBox::Service
-{
-public:
- MediaRTPpjmediaApp() : mGeneralState(new RtpGeneralStateItem()) { mGeneralState->key = IceUtil::generateUUID(); };
- void start(const std::string&, const Ice::CommunicatorPtr&, const Ice::StringSeq&);
- void stop();
-
-private:
- /**
- * Ice Communicator used for this service.
- */
- Ice::CommunicatorPtr mCommunicator;
-
- /**
- * Object adapter that global stuff is associated with.
- */
- Ice::ObjectAdapterPtr mGlobalAdapter;
-
- /**
- * Object adapter that local stuff is associated with.
- */
- Ice::ObjectAdapterPtr mLocalAdapter;
-
- /**
- * The object adapter for the Logger.
- */
- Ice::ObjectAdapterPtr mLoggerAdapter;
-
- /**
- * A proxy to the service locator manager for the component service.
- */
- ServiceManagementPrx mComponentServiceManagement;
-
- /**
- * Instance of our replica implementation.
- */
- ReplicaPtr mReplicaService;
-
- /**
- * A proxy to the replica control object.
- */
- ReplicaPrx mReplicaServicePrx;
-
- /**
- * Instance of our configuration service implementation.
- */
- ConfigurationServiceImplPtr mConfigurationService;
-
- /**
- * Instance of our state replicator listener.
- */
- RtpStateReplicatorListenerPtr mReplicatorListener;
-
- /**
- * A proxy to our state replicator listener.
- */
- RtpStateReplicatorListenerPrx mReplicatorListenerProxy;
-
- /**
- * A proxy to the state replicator.
- */
- AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
-
- /**
- * An instance of the general state information class.
- */
- RtpGeneralStateItemPtr mGeneralState;
-
- /**
- * A proxy to the service locator management service.
- */
- ServiceLocatorManagementPrx mManagement;
-
- /**
- * A proxy to the service locator manager for the configuration service.
- */
- ServiceManagementPrx mConfigurationManagement;
-
- /**
- * Unique guid for configuration service name comparator.
- */
- std::string mConfigCompareGuid;
-};
-
-/**
- * Implementation of the ComponentService interface as defined in ComponentServiceIf.ice
- */
-class ComponentServicepjmediaImpl : public ComponentService
-{
-public:
- /**
- * A constructor for this implementation which just sets a few variables, nothing extreme.
- */
- ComponentServicepjmediaImpl(MediaRTPpjmediaApp& app, const RtpGeneralStateItemPtr& generalState) :
- mApplication(app), mGeneralState(generalState) { };
-
- /**
- * An implementation of the suspend method which actually suspends ourselves
- * from the service locator.
- */
- virtual void suspend(const ::Ice::Current&)
- {
- mGeneralState->serviceManagement->suspend();
- }
-
- /**
- * An implementation of the resume method which actually unsuspends ourselves
- * from the service locator.
- */
- virtual void resume(const ::Ice::Current&)
- {
- mGeneralState->serviceManagement->unsuspend();
- }
-
- /**
- * An implementation of the shutdown method which really does shut us down.
- * Goodbye cruel world.
- */
- virtual void shutdown(const ::Ice::Current&)
- {
- // TODO - Actually support this
- }
-
-private:
- /**
- * Our application instance, used for shutting the component down.
- */
- MediaRTPpjmediaApp& mApplication;
-
- /**
- * Pointer to general state information.
- */
- RtpGeneralStateItemPtr mGeneralState;
-};
-
-/**
- * Wrapper class around pj_thread_desc.
- */
-class ThreadDescWrapper
-{
-public:
- /**
- * pjthread thread description information, must persist for the life of the thread
- */
- pj_thread_desc mDesc;
-};
-
-/**
- * Type definition used to create a smart pointer for the above.
- */
-typedef boost::shared_ptr<ThreadDescWrapper> ThreadDescWrapperPtr;
-
-/**
- * Implementation of the Ice::ThreadNotification class.
- */
-class pjlibHook : public Ice::ThreadNotification
-{
-public:
- /**
- * Implementation of the start function which is called when a thread starts.
- */
- void start()
- {
- ThreadDescWrapperPtr wrapper = ThreadDescWrapperPtr(new ThreadDescWrapper());
- pj_thread_t *thread;
- pj_thread_register("ICE Thread", wrapper->mDesc, &thread);
- boost::lock_guard<boost::mutex> lock(mLock);
- pjThreads.insert(make_pair(thread, wrapper));
- }
-
- /**
- * Implementation of the stop function which is called when a thread stops.
- */
- void stop()
- {
- if (pj_thread_is_registered())
- {
- boost::lock_guard<boost::mutex> lock(mLock);
- pjThreads.erase(pj_thread_this());
- }
- }
-private:
- /**
- * A map containing thread lifetime persistent data.
- */
- map<pj_thread_t*, ThreadDescWrapperPtr> pjThreads;
-
- /**
- * Mutex to protect the map
- */
- boost::mutex mLock;
-};
-
-/**
- * Comparator implementation for name based configuration service locating
- */
-class RtpConfigurationCompare : public ServiceLocatorParamsCompare
-{
-public:
- RtpConfigurationCompare(const string& name) : mName(name) {}
- bool isSupported(const ServiceLocatorParamsPtr ¶ms, const Ice::Current &)
- {
- RtpConfigurationParamsPtr configParams = RtpConfigurationParamsPtr::dynamicCast(params);
- if (configParams->name == mName)
- {
- return true;
- }
- return false;
- }
-private:
- string mName;
-};
-
-typedef IceUtil::Handle<RtpConfigurationCompare> RtpConfigurationComparePtr;
-
-/**
- * Constructor for the RTPMediaServiceImpl class.
- */
-RTPMediaServiceImpl::RTPMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter, const ReplicaPrx& replicaService,
- const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator,
- const ConfigurationServiceImplPtr& configurationService) :
- mAdapter(adapter),
- mEnvironment(PJMediaEnvironment::create(adapter->getCommunicator()->getProperties(), configurationService)),
- mReplicaServicePrx(replicaService),
- mConfigurationService(configurationService),
- mStateReplicator(stateReplicator)
-{
-}
-
-/**
- * Implementation of the allocate method as defined in MediaRTPIf.ice
- */
-RTPSessionPrx RTPMediaServiceImpl::allocate(const RTPServiceLocatorParamsPtr& params, const Ice::Current&)
-{
- return AsteriskSCF::PJMediaRTP::RTPSession::create(mAdapter, IceUtil::generateUUID(), params, mEnvironment,
- mReplicaServicePrx, mStateReplicator, mConfigurationService);
-}
-
-/**
- * Implementation of the IceBox::Service::start method.
- */
-void MediaRTPpjmediaApp::start(const std::string&, const Ice::CommunicatorPtr& communicator,
- const Ice::StringSeq&)
-{
- // we need a logger before we're ready to build the real communicator.
- // use the one we're provided to create the IceLogger.
- mLoggerAdapter = communicator->createObjectAdapter("MediaRTPpjmediaAdapterLogger");
- ConfiguredIceLoggerPtr iceLogger = createIceLogger(mLoggerAdapter);
- getLoggerFactory().setLogOutput(iceLogger->getLogger());
- mLoggerAdapter->activate();
-
- /* Initialize pjlib as pjmedia will be using it */
- pj_status_t status = pj_init();
- if (status != PJ_SUCCESS)
- {
- lg(Error) << "PJ library initialization failed.";
- return;
- }
-
- if ((status = pjlib_util_init()) != PJ_SUCCESS)
- {
- lg(Error) << "PJ Utility library initialization failed.";
- return;
- }
-
- lg(Info) << "Initializing pjmedia rtp component" << endl;
-
- Ice::InitializationData id;
- id.threadHook = new pjlibHook();
- id.properties = communicator->getProperties();
-
- mCommunicator = Ice::initialize(id);
-
- mLocalAdapter = mCommunicator->createObjectAdapter("MediaRTPpjmediaAdapterLocal");
-
- mReplicaService = new ReplicaImpl(mLocalAdapter);
- 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");
-
- mGlobalAdapter->activate();
-
- lg(Info) << "Activated pjmedia rtp component media service." << endl;
-
- mManagement = ServiceLocatorManagementPrx::checkedCast(mCommunicator->propertyToProxy("ServiceLocatorManagementProxy"));
-
- // The service locator is required for state replicator operation, so go ahead and find it
- ServiceLocatorPrx locator = ServiceLocatorPrx::checkedCast(mCommunicator->propertyToProxy("LocatorService.Proxy"));
-
- // Look for the configured state replicator or default one
- RtpStateReplicatorParamsPtr replicatorParams = new RtpStateReplicatorParams();
- replicatorParams->category = StateReplicatorDiscoveryCategory;
- replicatorParams->name =
- mCommunicator->getProperties()->getPropertyWithDefault("Rtp.StateReplicatorName", "default");
-
- try
- {
- AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> pw(locator, replicatorParams, lg);
- mStateReplicator = pw;
- }
- catch (...)
- {
- lg(Error) << "State replicator could not be found, operating without.";
- }
-
- RTPMediaServiceImplPtr rtpmediaservice =
- new RTPMediaServiceImpl(mGlobalAdapter, mReplicaServicePrx, mStateReplicator, mConfigurationService);
-
- if (mCommunicator->getProperties()->getPropertyWithDefault("Rtp.Standalone", "false") == "true")
- {
- // Publish the configuration service IceStorm topic so everybody gets configuration
- mConfigurationManagement = ServiceManagementPrx::uncheckedCast(
- mManagement->addService(mConfigurationServiceProxy, ""));
-
- // Populate the configuration parameters with details so we can be found
- RtpConfigurationParamsPtr configurationParams = new RtpConfigurationParams();
- configurationParams->category = ConfigurationDiscoveryCategory;
- configurationParams->name = mCommunicator->getProperties()->getPropertyWithDefault("RtpConfiguration.Name", "");
-
- // Add our custom comparator so we can support multiple simultaneous configuration sinks
- RtpConfigurationComparePtr configNameCompare = new RtpConfigurationCompare(configurationParams->name);
- ServiceLocatorParamsComparePrx configCompareProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
- mLocalAdapter->addWithUUID(configNameCompare));
-
- mConfigCompareGuid = IceUtil::generateUUID();
- mManagement->addCompare(mConfigCompareGuid, configCompareProxy);
- mConfigurationManagement->addLocatorParams(configurationParams, mConfigCompareGuid);
- }
- else if (mStateReplicator)
- {
- ConfigurationReplicatorPrx configurationReplicator = ConfigurationReplicatorPrx::checkedCast(
- mStateReplicator.initialize(), ReplicatorFacet);
- configurationReplicator->registerConfigurationService(mConfigurationServiceProxy);
- }
-
- if (mStateReplicator)
- {
- mReplicatorListener =
- new RtpStateReplicatorListenerI(mGlobalAdapter, rtpmediaservice->getEnvironment(), mGeneralState,
- mConfigurationService);
- mReplicatorListenerProxy =
- RtpStateReplicatorListenerPrx::uncheckedCast(mLocalAdapter->addWithUUID(mReplicatorListener));
-
- if (mCommunicator->getProperties()->getPropertyWithDefault("Rtp.StateReplicatorListener", "no") == "yes")
- {
- mStateReplicator->addListener(mReplicatorListenerProxy);
- mReplicaService->standby();
- lg(Info) << "Operating as a standby replica." << endl;
- }
- else
- {
- lg(Info) << "Operating in an active state." << endl;
- }
- }
-
- ServiceLocatorParamsComparePtr rtpmediacomparatorservice = new RTPMediaServiceCompareServiceImpl(mConfigurationService);
- ServiceLocatorParamsComparePrx RTPMediaComparatorServiceProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
- mGlobalAdapter->add(rtpmediacomparatorservice, mCommunicator->stringToIdentity(MediaComparatorServiceId)));
-
- if (mReplicaService->isActive() == true)
- {
- mGeneralState->comparatorId = IceUtil::generateUUID();
- mManagement->addCompare(mGeneralState->comparatorId, RTPMediaComparatorServiceProxy);
- }
-
-
- RTPMediaServicePrx RTPMediaServiceProxy = RTPMediaServicePrx::uncheckedCast(mGlobalAdapter->add(rtpmediaservice,
- mCommunicator->stringToIdentity(MediaServiceId)));
-
- 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->serviceManagement = ServiceManagementPrx::uncheckedCast(
- mManagement->addService(RTPMediaServiceProxy, "media_rtp_pjmedia"));
- /* Now we can add some parameters to help find us. */
- mGeneralState->serviceManagement->addLocatorParams(rtpparams, mGeneralState->comparatorId);
- }
-
- ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
-
- /* One must provide a component service to manage us, if someone wants to */
- ComponentServicePtr ComponentService = new ComponentServicepjmediaImpl(*this, mGeneralState);
- ComponentServicePrx ComponentServiceProxy =
- ComponentServicePrx::uncheckedCast(mLocalAdapter->addWithUUID(ComponentService));
-
- /* Let's add the component service to the service locator first */
- mComponentServiceManagement =
- ServiceManagementPrx::uncheckedCast(mManagement->addService(ComponentServiceProxy, "media_rtp_pjmedia.component"));
- genericparams->category = "Component/media_rtp_pjmedia";
- mComponentServiceManagement->addLocatorParams(genericparams, "");
-
- // Replicate general state information so the backup is ready
- if (mStateReplicator && mReplicaService->isActive() == true)
- {
- RtpStateItemSeq items;
- items.push_back(mGeneralState);
- RtpStateReplicatorPrx oneway = RtpStateReplicatorPrx::uncheckedCast(mStateReplicator->ice_oneway());
- oneway->setState(items);
- }
-}
-
-/**
- * Implementation of the IceBox::Service::stop method.
- */
-void MediaRTPpjmediaApp::stop()
-{
- mComponentServiceManagement->unregister();
- if (mReplicaService->isActive() == true)
- {
- mGeneralState->serviceManagement->unregister();
- }
- if (mConfigurationManagement)
- {
- mConfigurationManagement->unregister();
- }
- if (!mConfigCompareGuid.empty())
- {
- mManagement->removeCompare(mConfigCompareGuid);
- ServiceLocatorManagementPrx management =
- ServiceLocatorManagementPrx::checkedCast(mCommunicator->propertyToProxy("ServiceLocatorManagementProxy"));
- management->removeCompare(mGeneralState->comparatorId);
- }
- mCommunicator->destroy();
-}
-
-extern "C"
-{
-ASTSCF_DLL_EXPORT IceBox::Service* create(Ice::CommunicatorPtr)
-{
- return new MediaRTPpjmediaApp;
-}
-}
diff --git a/src/RTPConfiguration.h b/src/RTPConfiguration.h
index 4ae017c..fcc6e68 100644
--- a/src/RTPConfiguration.h
+++ b/src/RTPConfiguration.h
@@ -42,3 +42,4 @@ protected:
* A typedef which creates a smart pointer type for ConfigurationServiceImpl.
*/
typedef IceUtil::Handle<ConfigurationServiceImpl> ConfigurationServiceImplPtr;
+
diff --git a/src/RTPSession.cpp b/src/RTPSession.cpp
index eb3bac8..0d87155 100644
--- a/src/RTPSession.cpp
+++ b/src/RTPSession.cpp
@@ -144,8 +144,7 @@ public:
const string& id,
const PJMediaEnvironmentPtr& env,
const AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr& params,
- const AsteriskSCF::System::Component::V1::ReplicaPrx& replicaControl,
- const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateReplicatorPrx>&,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr&);
RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
@@ -155,7 +154,7 @@ public:
const AsteriskSCF::Media::V1::FormatSeq& formats,
bool isIPv6,
bool srtp,
- const AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateReplicatorPrx>&,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configurationServant);
~RTPSessionImpl();
@@ -282,15 +281,8 @@ private:
*/
RtpSessionStateItemPtr mSessionStateItem;
- /**
- * A proxy to our related replica control object.
- */
- ReplicaPrx mReplicaService;
-
- /**
- * A proxy to the state replicator where we are sending updates to.
- */
- AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx> mStateReplicator;
+ // Context for state replication for this component.
+ RtpReplicationContextPtr mReplicationContext;
/**
* RTCP session for this RTP session.
@@ -433,8 +425,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
const string& id,
const PJMediaEnvironmentPtr& env,
const RTPServiceLocatorParamsPtr& params,
- const ReplicaPrx& replicaService,
- const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configurationService) :
mEnvironment(env),
mEndpoint(PJMediaEndpoint::create(env)),
@@ -442,8 +433,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
mAdapter(adapter),
mFormats(params->formats),
mSessionStateItem(new RtpSessionStateItem),
- mReplicaService(replicaService),
- mStateReplicator(stateReplicator)
+ mReplicationContext(replicationContext)
{
RTPOverICEServiceLocatorParamsPtr iceParams(RTPOverICEServiceLocatorParamsPtr::dynamicCast(params));
if (iceParams && iceParams->enableRTPOverICE)
@@ -485,7 +475,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
}
/**
- * Constructor for the RTPSessionImpl class (used by state replicator).
+ * Constructor for the RTPSessionImpl class (used by state replicator listener).
*/
RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
const string& sessionIdentity,
@@ -494,7 +484,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
const FormatSeq& formats,
bool ipv6,
bool srtp,
- const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& replicatorPrx,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configurationService) :
mEnvironment(env),
mEndpoint(PJMediaEndpoint::create(env)),
@@ -502,8 +492,7 @@ RTPSessionImpl::RTPSessionImpl(const Ice::ObjectAdapterPtr& adapter,
mAdapter(adapter),
mFormats(formats),
mSessionStateItem(0),
- mReplicaService(0),
- mStateReplicator(replicatorPrx)
+ mReplicationContext(replicationContext)
{
if (mEnvironment->natConfig() && mEnvironment->natConfig()->isSTUNEnabled())
{
@@ -759,42 +748,34 @@ void RTPSessionImpl::replicateState(const RtpSessionStateItemPtr& session, const
const RtpStreamSourceStateItemPtr& source)
{
// If state replication has been disabled do nothing
- if (!mStateReplicator || mReplicaService->isActive() == false)
+ if (mReplicationContext->isReplicating() == false)
{
- return;
+ return;
}
RtpStateItemSeq items;
if (session)
{
- items.push_back(session);
+ items.push_back(session);
}
if (sink)
{
- items.push_back(sink);
+ items.push_back(sink);
}
if (source)
{
- items.push_back(source);
+ items.push_back(source);
}
if (items.size() == 0)
{
- return;
+ return;
}
- try
- {
- RtpStateReplicatorPrx oneway = RtpStateReplicatorPrx::uncheckedCast(mStateReplicator->ice_oneway());
- oneway->setState(items);
- }
- catch (...)
- {
- mStateReplicator->setState(items);
- }
+ mReplicationContext->getReplicator().tryOneWay()->setState(items);
}
/**
@@ -804,7 +785,7 @@ void RTPSessionImpl::removeState(const RtpSessionStateItemPtr& session, const Rt
const RtpStreamSourceStateItemPtr& source)
{
// If state replication has been disabled do nothing
- if (!mStateReplicator || mReplicaService->isActive() == false)
+ if (mReplicationContext->isReplicating() == false)
{
return;
}
@@ -813,33 +794,25 @@ void RTPSessionImpl::removeState(const RtpSessionStateItemPtr& session, const Rt
if (session)
{
- items.push_back(session->key);
+ items.push_back(session->key);
}
if (sink)
{
- items.push_back(sink->key);
+ items.push_back(sink->key);
}
if (source)
{
- items.push_back(source->key);
+ items.push_back(source->key);
}
if (items.size() == 0)
{
- return;
+ return;
}
- try
- {
- RtpStateReplicatorPrx oneway = RtpStateReplicatorPrx::uncheckedCast(mStateReplicator->ice_oneway());
- oneway->removeState(items);
- }
- catch (...)
- {
- mStateReplicator->removeState(items);
- }
+ mReplicationContext->getReplicator().tryOneWay()->removeState(items);
}
void RTPSessionImpl::associatePayloadsImpl(const AsteriskSCF::Media::RTP::V1::PayloadMap& mappings)
@@ -966,25 +939,25 @@ private:
RTPSessionPrx AsteriskSCF::PJMediaRTP::RTPSession::create(const Ice::ObjectAdapterPtr& adapter,
const std::string& id, const RTPServiceLocatorParamsPtr& params,
const PJMediaEnvironmentPtr& environment,
- const AsteriskSCF::System::Component::V1::ReplicaPrx& replicaControl,
- const AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>& stateReplicator,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configuration)
{
RTPSessionImplPtr servant(new RTPSessionImpl(adapter, id, environment, params,
- replicaControl, stateReplicator, configuration));
+ replicationContext, configuration));
return servant->activate(id);
}
ReplicationAdapterPtr AsteriskSCF::PJMediaRTP::RTPSession::create(const Ice::ObjectAdapterPtr& adapter,
const PJMediaEnvironmentPtr& environment,
const RtpSessionStateItemPtr& item,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configuration)
{
RTPSessionImplPtr servant(new RTPSessionImpl(adapter,
adapter->getCommunicator()->identityToString(item->sessionIdentity),
environment,
item->port, item->formats, item->ipv6, item->srtp,
- AsteriskSCF::Discovery::SmartProxy<RtpStateReplicatorPrx>(),
+ replicationContext,
configuration));
servant->activate(item->sessionIdentity, item->sourceIdentity, item->sinkIdentity);
return ReplicationAdapterPtr(new ReplicationAdapterImpl(servant));
diff --git a/src/RTPSession.h b/src/RTPSession.h
index a4f8072..962d680 100644
--- a/src/RTPSession.h
+++ b/src/RTPSession.h
@@ -8,6 +8,7 @@
#pragma once
+#include "RtpReplicationContext.h"
#include "RTPConfiguration.h"
#include "PJMediaEnvironment.h"
#include "RtpStateReplicationIf.h"
@@ -31,15 +32,14 @@ public:
const std::string& id,
const AsteriskSCF::Media::RTP::V1::RTPServiceLocatorParamsPtr& params,
const PJMediaEnvironmentPtr& environment,
- const AsteriskSCF::System::Component::V1::ReplicaPrx& replicaControl,
- const AsteriskSCF::Discovery::SmartProxy<
- AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateReplicatorPrx>& stateReplicator,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configuration
);
static ReplicationAdapterPtr create(const Ice::ObjectAdapterPtr& objectAdapter,
const PJMediaEnvironmentPtr& environment,
const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpSessionStateItemPtr& update,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr& configuration
);
};
diff --git a/src/RTPSource.cpp b/src/RTPSource.cpp
index 8f501a9..c9592b1 100644
--- a/src/RTPSource.cpp
+++ b/src/RTPSource.cpp
@@ -273,8 +273,8 @@ std::string StreamSourceRTPImpl::getId(const Ice::Current&)
*/
void StreamSourceRTPImpl::requestFormat(const AsteriskSCF::Media::V1::FormatPtr&, const Ice::Current&)
{
- /* We do not currently support switching formats. */
- throw new MediaFormatSwitchException();
+ // We do not currently support switching formats.
+ throw MediaFormatSwitchException();
}
/**
diff --git a/src/RtpReplicationContext.h b/src/RtpReplicationContext.h
new file mode 100644
index 0000000..8153465
--- /dev/null
+++ b/src/RtpReplicationContext.h
@@ -0,0 +1,78 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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 <boost/shared_ptr.hpp>
+
+#include <AsteriskSCF/Discovery/SmartProxy.h>
+#include <AsteriskSCF/Replication/ReplicationContext.h>
+#include <AsteriskSCF/Component/TestContext.h>
+
+#include "RtpStateReplicationIf.h"
+
+typedef AsteriskSCF::Discovery::SmartProxy<AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateReplicatorPrx> ReplicatorSmartPrx;
+
+/**
+ * This class provides the component's classes with the context needed to perform replication.
+ */
+class RtpReplicationContext : public AsteriskSCF::Replication::ReplicationContext
+{
+public:
+ RtpReplicationContext(AsteriskSCF::Replication::ReplicationStateType state) :
+ AsteriskSCF::Replication::ReplicationContext(state)
+ {
+ }
+
+ // Override
+ virtual bool isReplicating()
+ {
+ // If the base context says we aren't replicating, we aren't.
+ if (!ReplicationContext::isReplicating())
+ {
+ return false;
+ }
+
+ // Do we have a replicator proxy?
+ if (mReplicator.isInitialized())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get a reference to the state replicator service.
+ */
+ ReplicatorSmartPrx getReplicator()
+ {
+ return mReplicator;
+ }
+
+ /**
+ * Sets the reference to the state replicator service.
+ */
+ void setReplicator(const ReplicatorSmartPrx& replicator)
+ {
+ mReplicator = replicator;
+ }
+
+private:
+ ReplicatorSmartPrx mReplicator;
+};
+typedef boost::shared_ptr<RtpReplicationContext> RtpReplicationContextPtr;
+
+
diff --git a/src/RtpStateReplicator.h b/src/RtpStateReplicator.h
index d193fd9..c3aacae 100644
--- a/src/RtpStateReplicator.h
+++ b/src/RtpStateReplicator.h
@@ -19,6 +19,7 @@
#include "RtpStateReplicationIf.h"
#include "RTPConfiguration.h"
#include "PJMediaEnvironment.h"
+#include "RtpReplicationContext.h"
#include <Ice/Ice.h>
#include <AsteriskSCF/Replication/StateReplicator.h>
@@ -40,8 +41,10 @@ struct RtpStateReplicatorListenerImpl;
class RtpStateReplicatorListenerI : public AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateReplicatorListener
{
public:
- RtpStateReplicatorListenerI(const Ice::ObjectAdapterPtr&, const AsteriskSCF::PJMediaRTP::PJMediaEnvironmentPtr&,
+ RtpStateReplicatorListenerI(const Ice::ObjectAdapterPtr&,
+ const AsteriskSCF::PJMediaRTP::PJMediaEnvironmentPtr&,
const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpGeneralStateItemPtr&,
+ const RtpReplicationContextPtr& replicationContext,
const ConfigurationServiceImplPtr&);
~RtpStateReplicatorListenerI();
void stateRemoved(const Ice::StringSeq&, const Ice::Current&);
diff --git a/src/RtpStateReplicatorApp.cpp b/src/RtpStateReplicatorApp.cpp
index 8d5129b..4de161e 100644
--- a/src/RtpStateReplicatorApp.cpp
+++ b/src/RtpStateReplicatorApp.cpp
@@ -56,10 +56,11 @@ public:
mComponentService = 0;
mAdapter = 0;
mStateReplicator = 0;
- mConfigurationReplicator = 0;
+ mConfigurationReplicator = 0;
};
virtual void start(const string &name, const Ice::CommunicatorPtr& ic, const Ice::StringSeq& args);
virtual void stop();
+
private:
void initialize(const string& appName, const Ice::CommunicatorPtr& ic);
void registerWithServiceLocator(const Ice::CommunicatorPtr& ic);
@@ -76,7 +77,6 @@ private:
CollocatedIceStormPtr mIceStorm;
Ice::ObjectPrx mConfigurationPublisher;
Discovery::V1::ServiceManagementPrx mConfigurationManagement;
- std::string mConfigCompareGuid;
};
static const string ComponentServiceId("RtpStateReplicatorComponent");
@@ -111,44 +111,6 @@ private:
RtpStateReplicatorService& mService;
};
-class RtpStateReplicatorCompare : public ServiceLocatorParamsCompare
-{
-public:
- RtpStateReplicatorCompare(const string& name) : mName(name) {}
- bool isSupported(const ServiceLocatorParamsPtr ¶ms, const Ice::Current &)
- {
- RtpStateReplicatorParamsPtr sipParams = RtpStateReplicatorParamsPtr::dynamicCast(params);
- if (sipParams->name == mName)
- {
- return true;
- }
- return false;
- }
-private:
- string mName;
-};
-
-typedef IceUtil::Handle<RtpStateReplicatorCompare> RtpStateReplicatorComparePtr;
-
-class RtpConfigurationCompare : public ServiceLocatorParamsCompare
-{
-public:
- RtpConfigurationCompare(const string& name) : mName(name) {}
- bool isSupported(const ServiceLocatorParamsPtr ¶ms, const Ice::Current &)
- {
- RtpConfigurationParamsPtr configParams = RtpConfigurationParamsPtr::dynamicCast(params);
- if (configParams->name == mName)
- {
- return true;
- }
- return false;
- }
-private:
- string mName;
-};
-
-typedef IceUtil::Handle<RtpConfigurationCompare> RtpConfigurationComparePtr;
-
class ConfigurationReplicatorI : public ConfigurationReplicator
{
public:
@@ -162,18 +124,18 @@ void ConfigurationReplicatorI::registerConfigurationService(const AsteriskSCF::S
{
if (mConfigurationReplicationTopic)
{
- IceStorm::QoS qos;
- qos["reliability"] = "ordered";
-
- try
- {
- mConfigurationReplicationTopic->subscribeAndGetPublisher(qos, service);
- }
- catch (const IceStorm::AlreadySubscribed&)
- {
- // This is perfectly okay actually, it just means what they wanted us to do
- // is already done.
- }
+ IceStorm::QoS qos;
+ qos["reliability"] = "ordered";
+
+ try
+ {
+ mConfigurationReplicationTopic->subscribeAndGetPublisher(qos, service);
+ }
+ catch (const IceStorm::AlreadySubscribed&)
+ {
+ // This is perfectly okay actually, it just means what they wanted us to do
+ // is already done.
+ }
}
}
@@ -191,7 +153,7 @@ void RtpStateReplicatorService::registerWithServiceLocator(const Ice::Communicat
if (mServiceLocatorManagement == 0)
{
- lg(Error) << "Unable to obtain proxy to ServiceLocatorManagement interface. Check config file. "
+ lg(Error) << "Unable to obtain proxy to LocatorServiceManagement interface. Check config file. "
"This component can't be found until this is corrected.";
return;
}
@@ -208,7 +170,8 @@ void RtpStateReplicatorService::registerWithServiceLocator(const Ice::Communicat
// Add category as a parameter to enable other components look this component up.
ServiceLocatorParamsPtr genericparams = new ServiceLocatorParams();
genericparams->category = AsteriskSCF::Replication::MediaRTPPJMedia::V1::StateReplicatorComponentCategory;
-
+ genericparams->service = ic->getProperties()->getPropertyWithDefault("RtpStateReplicator.Service", "default");
+ genericparams->id = mAppName;
mComponentServiceManagement->addLocatorParams(genericparams, "");
Ice::ObjectPrx stateReplicatorObjectPrx = mAdapter->createDirectProxy(ic->stringToIdentity(ServiceDiscoveryId));
@@ -220,34 +183,20 @@ void RtpStateReplicatorService::registerWithServiceLocator(const Ice::Communicat
ServiceLocatorParamsPtr discoveryParams = new ServiceLocatorParams;
discoveryParams->category = AsteriskSCF::Replication::MediaRTPPJMedia::V1::StateReplicatorDiscoveryCategory;
+ discoveryParams->service = ic->getProperties()->getPropertyWithDefault("RtpStateReplicator.Service", "default");
+ discoveryParams->id = mAppName;
+ mStateReplicationManagement->addLocatorParams(discoveryParams, "");
- string replicatorName = ic->getProperties()->getPropertyWithDefault("RtpStateReplicator.Name", "default");
- RtpStateReplicatorCompare* nameCompare = new RtpStateReplicatorCompare(replicatorName);
- ServiceLocatorParamsComparePrx compareProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
- mAdapter->addWithUUID(nameCompare));
-
- string compareGuid = IceUtil::generateUUID();
- mServiceLocatorManagement->addCompare(compareGuid, compareProxy);
- mStateReplicationManagement->addLocatorParams(discoveryParams, compareGuid);
-
- // Publish the configuration service IceStorm topic so everybody gets configuration
- mConfigurationManagement = ServiceManagementPrx::uncheckedCast(
-
- mServiceLocatorManagement->addService(mConfigurationPublisher, ""));
-
- // Populate the configuration parameters with details so we can be found
- RtpConfigurationParamsPtr configurationParams = new RtpConfigurationParams();
- configurationParams->category = ConfigurationDiscoveryCategory;
- configurationParams->name = ic->getProperties()->getPropertyWithDefault("RtpConfiguration.Name", "");
-
- // Add our custom comparator so we can support multiple simultaneous configuration sinks
- RtpConfigurationComparePtr configNameCompare = new RtpConfigurationCompare(configurationParams->name);
- ServiceLocatorParamsComparePrx configCompareProxy = ServiceLocatorParamsComparePrx::uncheckedCast(
- mAdapter->addWithUUID(configNameCompare));
+ // Publish the configuration service IceStorm topic so everybody gets configuration
+ mConfigurationManagement = ServiceManagementPrx::uncheckedCast(
+ mServiceLocatorManagement->addService(mConfigurationPublisher, ""));
... 600 lines suppressed ...
--
asterisk-scf/release/media_rtp_pjmedia.git
More information about the asterisk-scf-commits
mailing list