[asterisk-scf-commits] asterisk-scf/integration/file_media_service.git branch "initial_development" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Wed Sep 28 09:23:42 CDT 2011
branch "initial_development" has been updated
via 91de09a86569f0cd197cacff890f77594c93677b (commit)
via afcff260059346b4fd8c12680e72ae981d22cb58 (commit)
via c1872b6bcbe5babb6f01b0decebea26d1a40a74e (commit)
via 35ee1c6397db57a0d69c1a94922c326d38af58b4 (commit)
via 3105b3f1e64026ec11ae46042b6f4c247ead8ddc (commit)
via f01227427dfd4852f7ecc65b350d066b32758010 (commit)
from 3a8cdb202a77cac4fb1c298e72f0097fead59a8d (commit)
Summary of changes:
CMakeLists.txt | 1 +
.../FileMediaServiceConfigurationIf.ice | 122 ++++
.../FileMediaService/ContainerFileIf.ice | 120 +++
.../FileMediaService/MatroskaContainerIf.ice | 49 ++
slice/AsteriskSCF/Media/File/FileMediaIf.ice | 197 -----
.../FileMediaService/FileMediaSessionStateIf.ice | 72 ++
slice/CMakeLists.txt | 15 +
src/CMakeLists.txt | 43 +-
src/CODE_STRUCTURE_NOTES.TXT | 38 +
src/Component.cpp | 98 +++
src/Config.h | 29 +
src/ContainerConfigurationAdapter.h | 42 ++
src/ContainerImpl.cpp | 233 ++++++
src/ContainerImpl.h | 47 ++
src/ContainerInfoImpl.cpp | 72 ++
src/ContainerInfoImpl.h | 74 ++
src/ContainerRepository.cpp | 766 ++++++++++++++++++++
src/ContainerRepository.h | 49 ++
src/FileMediaServiceComponent.cpp | 48 ++
src/FileMediaServiceComponent.h | 61 ++
src/LoggerF.h | 34 +
src/OpaqueContainerData.h | 48 ++
src/ReplicationContext.h | 50 ++
src/ReplicationListener.h | 36 +
src/RepositoryConfigurationAdapter.h | 62 ++
src/RepositoryReplicationAdapter.h | 41 +
src/StreamImpl.cpp | 77 ++
src/StreamImpl.h | 41 +
test/CMakeLists.txt | 21 +
test/UnitTest_ContainerRepository.cpp | 161 ++++
30 files changed, 2542 insertions(+), 205 deletions(-)
create mode 100644 slice/AsteriskSCF/Configuration/FileMediaService/FileMediaServiceConfigurationIf.ice
create mode 100644 slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
create mode 100644 slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
delete mode 100755 slice/AsteriskSCF/Media/File/FileMediaIf.ice
create mode 100644 slice/AsteriskSCF/Replication/FileMediaService/FileMediaSessionStateIf.ice
create mode 100755 slice/CMakeLists.txt
mode change 100755 => 100644 src/CMakeLists.txt
create mode 100644 src/CODE_STRUCTURE_NOTES.TXT
create mode 100644 src/Component.cpp
create mode 100644 src/Config.h
create mode 100644 src/ContainerConfigurationAdapter.h
create mode 100644 src/ContainerImpl.cpp
create mode 100644 src/ContainerImpl.h
create mode 100644 src/ContainerInfoImpl.cpp
create mode 100644 src/ContainerInfoImpl.h
create mode 100644 src/ContainerRepository.cpp
create mode 100644 src/ContainerRepository.h
create mode 100644 src/FileMediaServiceComponent.cpp
create mode 100644 src/FileMediaServiceComponent.h
create mode 100644 src/LoggerF.h
create mode 100644 src/OpaqueContainerData.h
create mode 100755 src/ReplicationContext.h
create mode 100644 src/ReplicationListener.h
create mode 100644 src/RepositoryConfigurationAdapter.h
create mode 100644 src/RepositoryReplicationAdapter.h
create mode 100644 src/StreamImpl.cpp
create mode 100644 src/StreamImpl.h
create mode 100644 test/CMakeLists.txt
create mode 100644 test/UnitTest_ContainerRepository.cpp
- Log -----------------------------------------------------------------
commit 91de09a86569f0cd197cacff890f77594c93677b
Author: Brent Eagles <beagles at digium.com>
Date: Tue Sep 27 20:18:21 2011 -0230
Started re-integrating matroska into new structure.
diff --git a/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice b/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
index 74aaa6a..10a6ad1 100644
--- a/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
+++ b/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
@@ -17,6 +17,7 @@
#pragma once
#include <Ice/BuiltinSequences.ice>
+#include <AsteriskSCF/Media/File/FileMediaIf.ice>
/**
* The MediaContainer elements define a contract that a media container implementation should satisfy for the file media
@@ -47,10 +48,18 @@ unsliceable class ContainerInfo
* Descriptive name
*/
string name;
+
/**
* Unique id for the container object.
*/
string id;
+
+ /**
+ * The operations supported by this container. Some may only support a subset of the operations
+ * supplied by the hosting service.
+ */
+ AsteriskSCF::Media::File::V1::FileOperations supportedOperations =
+ AsteriskSCF::Media::File::V1::Playback;
};
sequence<ContainerInfo> ContainerInfoSeq;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fe1cc2f..27edf7b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,7 @@
include_directories(${logger_dir}/include)
include_directories(${astscf-ice-util-cpp_dir}/include)
+include_directories(${astscf-ebml_dir})
+include_directories(${astscf-matroska_dir})
astscf_slice_include_collection(FILEMEDIASERVICE)
astscf_component_init(FileMediaService)
@@ -17,22 +19,17 @@ astscf_component_add_files(FileMediaService
FileMediaServiceComponent.h
ContainerImpl.cpp
ContainerImpl.h
+ OpaqueContainerData.h
LoggerF.h
ReplicationListener.h
RepositoryConfigurationAdapter.h
RepositoryReplicationAdapter.h
)
-#astscf_component_add_slices(FileMediaService PROJECT
-# AsteriskSCF/Replication/FileMediaService/FileMediaSessionStateIf.ice
-# AsteriskSCF/FileMediaService/ContainerFileIf.ice
-# AsteriskSCF/FileMediaService/MatroskaContainerIf.ice)
+
astscf_component_add_ice_libraries(FileMediaService IceStorm)
astscf_component_add_boost_libraries(FileMediaService core)
astscf_component_add_slice_collection_libraries(FileMediaService FILEMEDIASERVICE)
astscf_component_add_slice_collection_libraries(FileMediaService ASTSCF)
astscf_component_build_icebox(FileMediaService)
-target_link_libraries(FileMediaService logging-client astscf-ice-util-cpp)
+target_link_libraries(FileMediaService logging-client astscf-ice-util-cpp astscf-ebml astscf-matroska)
astscf_component_install(FileMediaService)
-
-# MatroskaContainerImpl.cpp
-# MatroskaContainerImpl.h
diff --git a/src/ContainerConfigurationAdapter.h b/src/ContainerConfigurationAdapter.h
index 973d5c2..e441f13 100644
--- a/src/ContainerConfigurationAdapter.h
+++ b/src/ContainerConfigurationAdapter.h
@@ -32,8 +32,7 @@ namespace Implementation
class ContainerConfigurationAdapter : public IceUtil::Shared
{
public:
- virtual void updateConfiguration(const std::string& uri,
- AsteriskSCF::Media::File::V1::FileOperations supportedOperations) = 0;
+ virtual void update(const std::string& uri, AsteriskSCF::Media::File::V1::FileOperations supportedOperations) = 0;
};
typedef IceUtil::Handle<ContainerConfigurationAdapter> ContainerConfigurationAdapterPtr;
diff --git a/src/ContainerImpl.cpp b/src/ContainerImpl.cpp
index 4b90b32..18467da 100644
--- a/src/ContainerImpl.cpp
+++ b/src/ContainerImpl.cpp
@@ -16,13 +16,22 @@
#include "ContainerImpl.h"
#include "ContainerRepository.h"
-// #include <matroska/FileKax.h>
+#include "OpaqueContainerData.h"
+
+#include <matroska/FileKax.h>
+#include <ebml/StdIOCallback.h>
+
#include <AsteriskSCF/logger.h>
-#include "ContainerConfigurationAdapter.h"
#include <Ice/Ice.h>
#include <IceUtil/UUID.h>
+#define BOOST_FILESYSTEM_VERSION 3
+#include <boost/filesystem.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+using namespace libmatroska;
+using namespace libebml;
using namespace AsteriskSCF::MatroskaContainer::Implementation;
using namespace AsteriskSCF::FileMediaService::MediaContainer::V1;
using namespace AsteriskSCF::System::Logging;
@@ -39,18 +48,85 @@ namespace MatroskaContainer
namespace Implementation
{
+typedef boost::shared_ptr<StdIOCallback> StdIOCallbackPtr;
+
+//
+// Matroska memory management is so bloody hairy that I'm going to wrap up this aspect of it.
+//
+class MatroskaImpl : public FileMatroska
+{
+public:
+ MatroskaImpl(const StdIOCallbackPtr& myIOCallback):
+ FileMatroska(*myIOCallback.get()),
+ mIOCallback(myIOCallback)
+ {
+ }
+
+private:
+ StdIOCallbackPtr mIOCallback;
+};
+
+typedef boost::shared_ptr<MatroskaImpl> MatroskaImplPtr;
+
+class ContainerDataImpl : public OpaqueContainerData
+{
+public:
+ ContainerDataImpl(const MatroskaImplPtr& impl) :
+ mMatroskaFile(impl)
+ {
+ }
+
+ FileKaxPtr getFile()
+ {
+ return boost::dynamic_pointer_cast<FileMatroska>(mMatroskaFile);
+ }
+
+private:
+ MatroskaImplPtr mMatroskaFile;
+};
+typedef IceUtil::Handle<ContainerDataImpl> ContainerDataImplPtr;
+
class ContainerServant : public ContainerImpl
{
public:
- ContainerServant(const ContainerInfoPtr info, const Logger& logger) :
+ ContainerServant(const ContainerInfoImplPtr& info, const Logger& logger) :
mInfo(info),
mLogger(logger)
{
}
+ void updateInfo(const string& uri, const AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
+ {
+ UniqueLock lock(mLock);
+
+ bool nameChanged = mInfo->filename != uri;
+
+ if (nameChanged)
+ {
+ //
+ // We will need to refresh our stream info. We cannot really destroy the streams that
+ // are out there. They are more or less autonomous.
+ //
+ ContainerDataImplPtr newData = refresh(uri, supportedOperations);
+ if (!newData)
+ {
+ //
+ // TODO:
+ // Throw an exception would be good here, but it might be tough depending on the
+ // caller's context.
+ //
+ mLogger(Error) << "Unable to recreate file data from new file information, possibly bad info. Keeping old state.";
+ return;
+ }
+ mMatroskaData = newData;
+ }
+ mInfo->filename = uri;
+ mInfo->supportedOperations = supportedOperations;
+ }
+
ContainerInfoPtr getInfo(const Ice::Current&)
{
- return 0;
+ return getInfoImpl();
}
StreamInfoSeq getStreamInfo(const Ice::Current&)
@@ -69,13 +145,83 @@ public:
}
private:
- ContainerInfoPtr mInfo;
+ boost::shared_mutex mLock;
+
+ //
+ // I cannot be the only one in the world who is tired of typing this out each time.
+ //
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+
+ ContainerInfoImplPtr mInfo;
Logger mLogger;
+
+ ContainerInfoImplPtr getInfoImpl()
+ {
+ SharedLock lock(mLock);
+ return mInfo;
+ }
+
+ StreamInfoSeq mStreamInfo;
+ ContainerDataImplPtr mMatroskaData;
+
+ ContainerDataImplPtr refresh(const string& filename, AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
+ {
+ if (supportedOperations == AsteriskSCF::Media::File::V1::Both)
+ {
+ mLogger(Error) << "This container file implementation does not support concurrent reading and writing to the "
+ "same container";
+ return 0;
+ }
+ boost::filesystem::path filePath(filename);
+ //
+ // Sanity check time.
+ //
+ if (boost::filesystem::is_directory(filePath))
+ {
+ //
+ // Oh oh.
+ //
+ mLogger(Error) << "Provided container information was for directory. Failing.";
+ return 0;
+ }
+
+ bool fileExists = boost::filesystem::exists(filePath);
+ if (!fileExists && supportedOperations == AsteriskSCF::Media::File::V1::Playback)
+ {
+ mLogger(Error) << "Trying to initialize a container file without recording support on a "
+ "non existent file";
+ return 0;
+ }
+
+ open_mode mode;
+ if (fileExists && supportedOperations == AsteriskSCF::Media::File::V1::Recording)
+ {
+ mode = MODE_WRITE;
+ }
+ else if (fileExists && supportedOperations == AsteriskSCF::Media::File::V1::Playback)
+ {
+ mode = MODE_READ;
+ }
+ else if (!fileExists && supportedOperations == AsteriskSCF::Media::File::V1::Recording)
+ {
+ mode = MODE_CREATE;
+ }
+ else
+ {
+ mLogger(Error) << "Logic error! Cannot determine the proper mode to open file.";
+ return 0;
+ }
+
+ StdIOCallbackPtr callback(new StdIOCallback(filePath.string().c_str(), mode));
+ ContainerDataImplPtr data(new ContainerDataImpl(MatroskaImplPtr(new MatroskaImpl(callback))));
+ return data;
+ }
};
typedef IceUtil::Handle<ContainerServant> ContainerServantPtr;
ContainerImplPtr
-ContainerImpl::create(const AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfoPtr& info,
+ContainerImpl::create(const ContainerInfoImplPtr& info,
const AsteriskSCF::System::Logging::Logger& logger)
{
return new ContainerServant(info, logger);
diff --git a/src/ContainerImpl.h b/src/ContainerImpl.h
index 3ace54f..77dd459 100644
--- a/src/ContainerImpl.h
+++ b/src/ContainerImpl.h
@@ -19,6 +19,8 @@
#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
#include "LoggerF.h"
+#include "ContainerInfoImpl.h"
+
namespace AsteriskSCF
{
namespace MatroskaContainer
@@ -29,8 +31,11 @@ namespace Implementation
class ContainerImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::Container
{
public:
+
+ void updateInfo(const std::string& uri, const AsteriskSCF::Media::File::V1::FileOperations supportedOperations);
+
static IceUtil::Handle<ContainerImpl> create(
- const AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfoPtr& info,
+ const ContainerInfoImplPtr& info,
const AsteriskSCF::System::Logging::Logger& logger);
};
typedef IceUtil::Handle<ContainerImpl> ContainerImplPtr;
diff --git a/src/ContainerRepository.cpp b/src/ContainerRepository.cpp
index d5f455d..8d7a3ba 100644
--- a/src/ContainerRepository.cpp
+++ b/src/ContainerRepository.cpp
@@ -20,6 +20,7 @@
#include "ContainerConfigurationAdapter.h"
#include <AsteriskSCF/logger.h>
+#include <AsteriskSCF/Media/File/FileMediaIf.h>
#include <vector>
#include <set>
@@ -98,6 +99,12 @@ public:
void removeFilenameExtension(const string& extension);
void setFilenameExtensions(const vector<string>& extensions);
vector<string> getFilenameExtensions();
+
+ //
+ // Container info configurations support.
+ //
+ void updateContainerInfo(const string& id, const string& uri,
+ AsteriskSCF::Media::File::V1::FileOperations supportedOperations);
private:
boost::shared_mutex mLock;
@@ -180,6 +187,18 @@ private:
Logger mLogger;
};
+class ContainerConfigurationAdapterImpl : public ContainerConfigurationAdapter
+{
+public:
+ ContainerConfigurationAdapterImpl(const string& id, const ContainerRepositoryServantPtr& containerRepository,
+ const Logger& logger);
+ void update(const string& uri, AsteriskSCF::Media::File::V1::FileOperations supportedOperations);
+private:
+ string mId;
+ ContainerRepositoryServantPtr mRepository;
+ Logger mLogger;
+};
+
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// UpdaterImpl Implementation
@@ -325,9 +344,10 @@ void ConfigurationAdapterImpl::removeContainer(const string&)
{
}
-ContainerConfigurationAdapterPtr ConfigurationAdapterImpl::addContainer(const string&, const string&,
- AsteriskSCF::Media::File::V1::FileOperations)
+ContainerConfigurationAdapterPtr ConfigurationAdapterImpl::addContainer(const string& id, const string& uri,
+ AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
{
+ ContainerInfoImplPtr newInfo(new ContainerInfoImpl);
return 0;
}
@@ -338,6 +358,25 @@ ContainerConfigurationAdapterPtr ConfigurationAdapterImpl::getContainer(const st
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
+// ContainerConfigurationAdapterImpl Implementation
+//
+ContainerConfigurationAdapterImpl::ContainerConfigurationAdapterImpl(const string& id,
+ const ContainerRepositoryServantPtr& containerRepository,
+ const Logger& logger) :
+ mId(id),
+ mRepository(containerRepository),
+ mLogger(logger)
+{
+}
+
+void ContainerConfigurationAdapterImpl::update(const string& uri,
+ AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
+{
+ mRepository->updateContainerInfo(mId, uri, supportedOperations);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
// ContainerRepositoryServant Implementation
//
@@ -368,7 +407,7 @@ ContainerPrx ContainerRepositoryServant::getContainer(const string& containerId,
//
// Check to see if we are looking at a known container and get the info for it.
//
- ContainerInfoPtr containerInfo;
+ ContainerInfoImplPtr containerInfo;
{
SharedLock lock(mLock);
if (mDestroyed)
@@ -519,6 +558,11 @@ void ContainerRepositoryServant::refresh()
newContainer->id = idgen.str();
newContainer->name = filename->string();
newContainer->filename = filename->string();
+
+ //
+ // We only support playback for files we know nothing else about.
+ //
+ newContainer->supportedOperations = AsteriskSCF::Media::File::V1::Playback;
mContainerInfoList.push_back(newContainer);
}
//
@@ -642,6 +686,65 @@ vector<string> ContainerRepositoryServant::getFilenameExtensions()
return vector<string>(mExtensions.begin(), mExtensions.end());
}
+void ContainerRepositoryServant::updateContainerInfo(const string& id, const string& uri,
+ AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
+{
+ ContainerInfoImplPtr info;
+ {
+ UniqueLock lock(mLock);
+
+ for (ContainerInfoImplSeq::const_iterator it = mContainerInfoList.begin(); it != mContainerInfoList.end(); ++it)
+ {
+ if ((*it)->id == id)
+ {
+ info = *it;
+ break;
+ }
+ }
+
+ //
+ // What does it mean if we don't have it? Probably a race condition of some kind has occurred. It is probably
+ // safest to simply toss the update aside because the danger is that an update might come along after
+ // a remove and things might kind of linger.
+ //
+ if (!info)
+ {
+ mLogger(Warning) << "Received a configuration update for an unknown container id. This probably indicates some "
+ "kind of race condition and should be monitored for recurrence!";
+ return;
+ }
+
+
+ //
+ // We'll the repository info first, then free up the lock and see about updating the container object if it
+ // exists. Thanks to the wonders of smart pointers, we just modify "info" in place. We *do* need to make
+ // sure these modifications happen within the context of a write lock on the repository.
+ //
+ info->filename = uri;
+ info->supportedOperations = supportedOperations;
+ }
+
+ //
+ // So we know about the info... let's see if we have an instance of it already in play.
+ //
+ Ice::Identity identity = mAdapter->getCommunicator()->stringToIdentity(info->id);
+ Ice::ObjectPtr obj = mAdapter->find(identity);
+ if (obj)
+ {
+ //
+ // OOooh we do have one in use, so we need to update it too.
+ //
+ ContainerImplPtr container = ContainerImplPtr::dynamicCast(obj);
+ assert(container);
+ if (!container)
+ {
+ mLogger(Error) << "There is an object using the same id as the one we want to use for our container! (type : " <<
+ obj->ice_id() << ')';
+ return;
+ }
+ }
+
+}
string ContainerRepositoryServant::getPath()
{
diff --git a/src/StreamImpl.h b/src/OpaqueContainerData.h
similarity index 65%
copy from src/StreamImpl.h
copy to src/OpaqueContainerData.h
index 7cecb35..6ed3412 100644
--- a/src/StreamImpl.h
+++ b/src/OpaqueContainerData.h
@@ -16,8 +16,17 @@
#pragma once
-#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
-#include "LoggerF.h"
+#include <IceUtil/Shared.h>
+#include <IceUtil/Handle.h>
+#include <boost/shared_ptr.hpp>
+
+/**
+ * Forward declarations for matroska.
+ */
+namespace libmatroska
+{
+class FileMatroska;
+}
namespace AsteriskSCF
{
@@ -25,15 +34,15 @@ namespace MatroskaContainer
{
namespace Implementation
{
-class StreamImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::Stream
+typedef boost::shared_ptr<libmatroska::FileMatroska> FileKaxPtr;
+
+class OpaqueContainerData : public IceUtil::Shared
{
public:
- static IceUtil::Handle<StreamImpl> create(const std::string& id, const AsteriskSCF::System::Logging::Logger& logger);
+ virtual FileKaxPtr getFile() = 0;
};
-typedef IceUtil::Handle<StreamImpl> StreamImplPtr;
+typedef IceUtil::Handle<OpaqueContainerData> OpaqueContainerDataPtr;
} /* End of namespace Implementation */
} /* End of namespace MatroskaContainer */
} /* End of namespace AsteriskSCF */
-
-
diff --git a/src/StreamImpl.cpp b/src/StreamImpl.cpp
index 52b2ba8..bc3803e 100644
--- a/src/StreamImpl.cpp
+++ b/src/StreamImpl.cpp
@@ -62,7 +62,7 @@ typedef IceUtil::Handle<StreamServant> StreamServantPtr;
IceUtil::Handle<AsteriskSCF::MatroskaContainer::Implementation::StreamImpl>
-StreamImpl::create(const string& id, const Logger& logger)
+StreamImpl::create(const OpaqueContainerDataPtr&, const string& id, const Logger& logger)
{
//
// TODO: Find the container itself so it can be opened.
diff --git a/src/StreamImpl.h b/src/StreamImpl.h
index 7cecb35..681b8f4 100644
--- a/src/StreamImpl.h
+++ b/src/StreamImpl.h
@@ -17,6 +17,7 @@
#pragma once
#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
+#include "OpaqueContainerData.h"
#include "LoggerF.h"
namespace AsteriskSCF
@@ -28,7 +29,8 @@ namespace Implementation
class StreamImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::Stream
{
public:
- static IceUtil::Handle<StreamImpl> create(const std::string& id, const AsteriskSCF::System::Logging::Logger& logger);
+ static IceUtil::Handle<StreamImpl> create(const OpaqueContainerDataPtr& data, const std::string& id,
+ const AsteriskSCF::System::Logging::Logger& logger);
};
typedef IceUtil::Handle<StreamImpl> StreamImplPtr;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 1857b91..29dcb75 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,5 +1,7 @@
include_directories(${logger_dir}/include)
include_directories(${astscf-ice-util-cpp_dir}/include)
+include_directories(${astscf-ebml_dir})
+include_directories(${astscf-matroska_dir})
#
# Unit test for the container repository
@@ -15,5 +17,5 @@ astscf_component_add_slice_collection_libraries(UnitTestContainerRepository ASTS
astscf_component_add_slice_collection_libraries(UnitTestContainerRepository FILEMEDIASERVICE)
astscf_component_build_standalone(UnitTestContainerRepository)
-target_link_libraries(UnitTestContainerRepository logging-client astscf-ice-util-cpp)
+target_link_libraries(UnitTestContainerRepository logging-client astscf-ice-util-cpp astscf-matroska astscf-ebml)
astscf_test_boost(UnitTestContainerRepository)
commit afcff260059346b4fd8c12680e72ae981d22cb58
Author: Brent Eagles <beagles at digium.com>
Date: Tue Sep 27 17:26:30 2011 -0230
Auto scan test with file masks.
diff --git a/src/ContainerRepository.cpp b/src/ContainerRepository.cpp
index 9230c02..d5f455d 100644
--- a/src/ContainerRepository.cpp
+++ b/src/ContainerRepository.cpp
@@ -22,6 +22,7 @@
#include <AsteriskSCF/logger.h>
#include <vector>
+#include <set>
#include <string>
#include <Ice/Ice.h>
@@ -92,6 +93,11 @@ public:
void stopBackgroundUpdates();
void setUpdateInterval(const IceUtil::Time& interval);
void setAutoUpdateOption(bool enable);
+
+ void addFilenameExtension(const string& extension);
+ void removeFilenameExtension(const string& extension);
+ void setFilenameExtensions(const vector<string>& extensions);
+ vector<string> getFilenameExtensions();
private:
boost::shared_mutex mLock;
@@ -112,6 +118,8 @@ private:
ContainerInfoImplSeq mContainerInfoList;
UpdaterPtr mUpdater;
+ set<string> mExtensions;
+
//
// A *locked* accessor for obtaining the path string. Handy for methods that want the path,
// but don't have a lock yet. NOT for use in locked scenarios.
@@ -153,6 +161,14 @@ public:
~ConfigurationAdapterImpl();
void setRootPath(const string& filesystemPath);
string getRootPath();
+
+ void addFilenameExtension(const string& extension);
+ void removeFilenameExtension(const string& extension);
+ void setFilenameExtensions(const vector<string>& extensions);
+ vector<string> getFilenameExtensions();
+
+ void setAutoUpdateOption(bool enable);
+
void setRunBackgroundUpdatesFlag(bool enable);
void setBackgroundUpdateIntervalInSeconds(unsigned int updateInterval);
void removeContainer(const string& catalogId);
@@ -259,6 +275,35 @@ std::string ConfigurationAdapterImpl::getRootPath()
return mRepository->getRootPath();
}
+void ConfigurationAdapterImpl::addFilenameExtension(const string& extension)
+{
+ mRepository->addFilenameExtension(extension);
+ mRepository->refresh();
+}
+
+void ConfigurationAdapterImpl::removeFilenameExtension(const string& extension)
+{
+ mRepository->removeFilenameExtension(extension);
+ mRepository->refresh();
+}
+
+void ConfigurationAdapterImpl::setFilenameExtensions(const vector<string>& extensions)
+{
+ mRepository->setFilenameExtensions(extensions);
+ mRepository->refresh();
+}
+
+vector<string> ConfigurationAdapterImpl::getFilenameExtensions()
+{
+ return mRepository->getFilenameExtensions();
+}
+
+void ConfigurationAdapterImpl::setAutoUpdateOption(bool enable)
+{
+ mRepository->setAutoUpdateOption(enable);
+ mRepository->refresh();
+}
+
void ConfigurationAdapterImpl::setRunBackgroundUpdatesFlag(bool enable)
{
if (enable)
@@ -314,7 +359,7 @@ ContainerInfoSeq ContainerRepositoryServant::getContainerList(const Ice::Current
throw Ice::ObjectNotExistException(__FILE__, __LINE__);
}
ContainerInfoSeq result;
- copy(mContainerInfoList.begin(), mContainerInfoList.end(), result.begin());
+ copy(mContainerInfoList.begin(), mContainerInfoList.end(), back_inserter(result));
return result;
}
@@ -405,11 +450,11 @@ void ContainerRepositoryServant::refresh()
mLogger(Error) << mName << ": container repository path (" << mPath << ") must be a directory";
return;
}
- vector<string> dirList;
+ vector<boost::filesystem::path> dirList;
for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(p);
i != boost::filesystem::directory_iterator(); ++i)
{
- dirList.push_back(i->path().string());
+ dirList.push_back(i->path());
}
UniqueLock lock(mLock);
@@ -426,9 +471,10 @@ void ContainerRepositoryServant::refresh()
containerInfo != mContainerInfoList.end(); ++containerInfo)
{
bool found = false;
- for (vector<string>::const_iterator filename = dirList.begin(); filename != dirList.end();
+ for (vector<boost::filesystem::path>::const_iterator filename = dirList.begin(); filename != dirList.end();
++filename)
{
+
//
// If we found a match we want to several things:
// - set the flag on the container info that we have indeed found a matching file.
@@ -437,7 +483,7 @@ void ContainerRepositoryServant::refresh()
// 2. it serves the auto-update function if enabled
// - get the heck out of the loop.
//
- if ((*filename) == (*containerInfo)->filename)
+ if (filename->string() == (*containerInfo)->filename)
{
(*containerInfo)->setExistFlag(true);
found = true;
@@ -456,13 +502,24 @@ void ContainerRepositoryServant::refresh()
}
if (mAutoUpdate && !dirList.empty())
{
- for (vector<string>::const_iterator filename = dirList.begin(); filename != dirList.end();
+ for (vector<boost::filesystem::path>::const_iterator filename = dirList.begin(); filename != dirList.end();
++filename)
{
+ string extension = filename->extension().string();
+ if (!extension.empty() && mExtensions.count(extension.substr(1)) == 0)
+ {
+ //
+ // We are not configured to pick up files with that extension.
+ //
+ break;
+ }
ContainerInfoImplPtr newContainer = new ContainerInfoImpl;
- newContainer->id = IceUtil::generateUUID();
- newContainer->name = newContainer->id;
- newContainer->filename = *filename;
+ stringstream idgen;
+ idgen << filename->string() << ".auto";
+ newContainer->id = idgen.str();
+ newContainer->name = filename->string();
+ newContainer->filename = filename->string();
+ mContainerInfoList.push_back(newContainer);
}
//
// TODO: replicate
@@ -559,6 +616,33 @@ void ContainerRepositoryServant::setAutoUpdateOption(bool enable)
mAutoUpdate = enable;
}
+void ContainerRepositoryServant::addFilenameExtension(const string& extension)
+{
+ UniqueLock lock(mLock);
+ mExtensions.insert(extension);
+}
+
+void ContainerRepositoryServant::removeFilenameExtension(const string& extension)
+{
+ UniqueLock lock(mLock);
+ mExtensions.erase(extension);
+}
+
+void ContainerRepositoryServant::setFilenameExtensions(const vector<string>& extensions)
+{
+ UniqueLock lock(mLock);
+ mExtensions.clear();
+ copy(extensions.begin(), extensions.end(), inserter(mExtensions, mExtensions.begin()));
+}
+
+
+vector<string> ContainerRepositoryServant::getFilenameExtensions()
+{
+ SharedLock lock(mLock);
+ return vector<string>(mExtensions.begin(), mExtensions.end());
+}
+
+
string ContainerRepositoryServant::getPath()
{
SharedLock lock(mLock);
diff --git a/src/RepositoryConfigurationAdapter.h b/src/RepositoryConfigurationAdapter.h
index eb752dc..8d8816b 100644
--- a/src/RepositoryConfigurationAdapter.h
+++ b/src/RepositoryConfigurationAdapter.h
@@ -19,6 +19,8 @@
#include "ContainerConfigurationAdapter.h"
#include <AsteriskSCF/Media/File/FileMediaIf.h>
#include <IceUtil/Handle.h>
+#include <string>
+#include <vector>
namespace AsteriskSCF
{
@@ -36,6 +38,13 @@ public:
virtual void setRootPath(const std::string& filesystemPath) = 0;
virtual std::string getRootPath() = 0;
+ virtual void addFilenameExtension(const std::string& extension) = 0;
+ virtual void removeFilenameExtension(const std::string& extension) = 0;
+ virtual void setFilenameExtensions(const std::vector<std::string>& extensions) = 0;
+ virtual std::vector<std::string> getFilenameExtensions() = 0;
+
+ virtual void setAutoUpdateOption(bool enable) = 0;
+
virtual void setRunBackgroundUpdatesFlag(bool enable) = 0;
virtual void setBackgroundUpdateIntervalInSeconds(unsigned int updateInterval) = 0;
virtual ContainerConfigurationAdapterPtr addContainer(const std::string& catalogId,
diff --git a/test/UnitTest_ContainerRepository.cpp b/test/UnitTest_ContainerRepository.cpp
index 22ad20b..2be115e 100644
--- a/test/UnitTest_ContainerRepository.cpp
+++ b/test/UnitTest_ContainerRepository.cpp
@@ -42,24 +42,82 @@ public:
void rootPathTest()
{
- ContainerRepositoryServantPtr testImpl(new ContainerRepositoryServant(mObjectAdapter, "TestRepository", mLogger));
- BOOST_REQUIRE(testImpl != 0);
- ContainerRepositoryPrx repository = ContainerRepositoryPrx::uncheckedCast(
- mObjectAdapter->addWithUUID(testImpl));
- BOOST_REQUIRE(repository != 0);
-
- string configurationProperty = mCommunicator->getProperties()->getPropertyWithDefault("Test.RootPath", "./data");
- BOOST_REQUIRE(!configurationProperty.empty());
- testImpl->configurationAdapter()->setRootPath(configurationProperty);
- BOOST_CHECK(testImpl->configurationAdapter()->getRootPath() == configurationProperty);
- mObjectAdapter->remove(repository->ice_getIdentity());
- repository = 0;
- testImpl = 0;
- //
+ ContainerRepositoryPrx repository;
+ try
+ {
+ ContainerRepositoryServantPtr testImpl(new ContainerRepositoryServant(mObjectAdapter, "TestRepository", mLogger));
+ BOOST_REQUIRE(testImpl != 0);
+ ContainerRepositoryPrx repository = ContainerRepositoryPrx::uncheckedCast(
+ mObjectAdapter->addWithUUID(testImpl));
+ BOOST_REQUIRE(repository != 0);
+
+ string configurationProperty = mCommunicator->getProperties()->getPropertyWithDefault("Test.RootPath", "./data");
+ BOOST_REQUIRE(!configurationProperty.empty());
+ testImpl->configurationAdapter()->setRootPath(configurationProperty);
+ BOOST_CHECK(testImpl->configurationAdapter()->getRootPath() == configurationProperty);
+ }
+ catch (...)
+ {
+ mLogger(Error) << "Unexception occurred in test.";
+ }
+ if (repository)
+ {
+ mObjectAdapter->remove(repository->ice_getIdentity());
+ repository = 0;
+ }
+ //
// This would be a good spot to put a breakpoint in a destructor if doing a code walk through.
//
}
+ void rootPathScanTest()
+ {
+ ContainerRepositoryPrx repository;
+ try
+ {
+ ContainerRepositoryServantPtr testImpl(new ContainerRepositoryServant(mObjectAdapter, "TestRepository", mLogger));
+ BOOST_REQUIRE(testImpl != 0);
+ repository = ContainerRepositoryPrx::uncheckedCast(
+ mObjectAdapter->addWithUUID(testImpl));
+ BOOST_REQUIRE(repository != 0);
+
+ string configurationProperty = mCommunicator->getProperties()->getPropertyWithDefault("Test.RootPath", "./data");
+ BOOST_REQUIRE(!configurationProperty.empty());
+ testImpl->configurationAdapter()->setRootPath(configurationProperty);
+ BOOST_REQUIRE(testImpl->configurationAdapter()->getRootPath() == configurationProperty);
+
+ vector<string> extensions = testImpl->configurationAdapter()->getFilenameExtensions();
+ BOOST_REQUIRE(extensions.empty());
+ ContainerInfoSeq containers = repository->getContainerList();
+ BOOST_REQUIRE(containers.empty());
+ testImpl->configurationAdapter()->addFilenameExtension("mka");
+ containers = repository->getContainerList();
+ BOOST_REQUIRE(containers.empty());
+ testImpl->configurationAdapter()->setAutoUpdateOption(true);
+ containers = repository->getContainerList();
+ BOOST_REQUIRE(!containers.empty());
+ bool pickedOne = false;
+ for (ContainerInfoSeq::const_iterator it = containers.begin(); it != containers.end(); ++it)
+ {
+ if ((*it)->id.find("auto") == string::npos)
+ {
+ pickedOne = true;
+ }
+ }
+ BOOST_CHECK_MESSAGE(!pickedOne, "With no container info configured, all entries should have been tagged as 'auto'");
+ }
+ catch (...)
+ {
+ mLogger(Error) << "Unexception occurred in test.";
+ }
+
+ if (repository)
+ {
+ mObjectAdapter->remove(repository->ice_getIdentity());
+ repository = 0;
+ }
+ }
+
private:
Ice::CommunicatorPtr mCommunicator;
Ice::ObjectAdapterPtr mObjectAdapter;
@@ -71,6 +129,7 @@ boost::shared_ptr<ContainerRepositoryTests> globalTestSuite;
bool init_unit_test()
{
framework::master_test_suite().add(BOOST_TEST_CASE(boost::bind(&ContainerRepositoryTests::rootPathTest, globalTestSuite)));
+ framework::master_test_suite().add(BOOST_TEST_CASE(boost::bind(&ContainerRepositoryTests::rootPathScanTest, globalTestSuite)));
return true;
}
commit c1872b6bcbe5babb6f01b0decebea26d1a40a74e
Author: Brent Eagles <beagles at digium.com>
Date: Tue Sep 27 15:57:53 2011 -0230
Getting unit test suite under control.
diff --git a/src/ContainerRepository.cpp b/src/ContainerRepository.cpp
index 99a922a..9230c02 100644
--- a/src/ContainerRepository.cpp
+++ b/src/ContainerRepository.cpp
@@ -87,6 +87,7 @@ public:
*/
void refresh();
void updateRootPath(const string& pathname);
+ string getRootPath();
void startBackgroundUpdates();
void stopBackgroundUpdates();
void setUpdateInterval(const IceUtil::Time& interval);
@@ -151,6 +152,7 @@ public:
ConfigurationAdapterImpl(const ContainerRepositoryServantPtr& containerRepository, const Logger&);
~ConfigurationAdapterImpl();
void setRootPath(const string& filesystemPath);
+ string getRootPath();
void setRunBackgroundUpdatesFlag(bool enable);
void setBackgroundUpdateIntervalInSeconds(unsigned int updateInterval);
void removeContainer(const string& catalogId);
@@ -252,6 +254,11 @@ void ConfigurationAdapterImpl::setRootPath(const string& filesystemPath)
mRepository->refresh();
}
+std::string ConfigurationAdapterImpl::getRootPath()
+{
+ return mRepository->getRootPath();
+}
+
void ConfigurationAdapterImpl::setRunBackgroundUpdatesFlag(bool enable)
{
if (enable)
@@ -483,6 +490,12 @@ void ContainerRepositoryServant::updateRootPath(const string& path)
mPath = path;
}
+string ContainerRepositoryServant::getRootPath()
+{
+ SharedLock lock(mLock);
+ return mPath;
+}
+
void ContainerRepositoryServant::startBackgroundUpdates()
{
//
diff --git a/src/RepositoryConfigurationAdapter.h b/src/RepositoryConfigurationAdapter.h
index abc749d..eb752dc 100644
--- a/src/RepositoryConfigurationAdapter.h
+++ b/src/RepositoryConfigurationAdapter.h
@@ -34,6 +34,8 @@ class RepositoryConfigurationAdapter : public IceUtil::Shared
{
public:
virtual void setRootPath(const std::string& filesystemPath) = 0;
+ virtual std::string getRootPath() = 0;
+
virtual void setRunBackgroundUpdatesFlag(bool enable) = 0;
virtual void setBackgroundUpdateIntervalInSeconds(unsigned int updateInterval) = 0;
virtual ContainerConfigurationAdapterPtr addContainer(const std::string& catalogId,
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8f4c188..1857b91 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -9,8 +9,8 @@ astscf_component_init(UnitTestContainerRepository)
astscf_component_add_files(UnitTestContainerRepository UnitTest_ContainerRepository.cpp)
astscf_component_add_files(UnitTestContainerRepository ../src/ContainerImpl.cpp)
astscf_component_add_files(UnitTestContainerRepository ../src/ContainerInfoImpl.cpp)
-astscf_component_add_ice_libraries(UnitTestContainerRepository IceStorm)
-astscf_component_add_boost_libraries(UnitTestContainerRepository core filesystem)
+
+astscf_component_add_boost_libraries(UnitTestContainerRepository unit_test_framework core filesystem)
astscf_component_add_slice_collection_libraries(UnitTestContainerRepository ASTSCF)
astscf_component_add_slice_collection_libraries(UnitTestContainerRepository FILEMEDIASERVICE)
astscf_component_build_standalone(UnitTestContainerRepository)
diff --git a/test/UnitTest_ContainerRepository.cpp b/test/UnitTest_ContainerRepository.cpp
index c2e1b4d..22ad20b 100644
--- a/test/UnitTest_ContainerRepository.cpp
+++ b/test/UnitTest_ContainerRepository.cpp
@@ -17,34 +17,86 @@
//
// Yes... we do intend to include the source file.
//
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/debug.hpp>
+#include <boost/bind.hpp>
+
#include "../src/ContainerRepository.cpp"
using namespace AsteriskSCF::MatroskaContainer::Implementation;
using namespace AsteriskSCF::System::Logging;
+using namespace boost::unit_test;
+
+class ContainerRepositoryTests
+{
+public:
+ ContainerRepositoryTests(const Ice::CommunicatorPtr& communicator, const Ice::ObjectAdapterPtr& adapter,
+ const Logger& logger) :
+ mCommunicator(communicator),
+ mObjectAdapter(adapter),
+ mLogger(logger)
+ {
+ }
+
+ void rootPathTest()
+ {
+ ContainerRepositoryServantPtr testImpl(new ContainerRepositoryServant(mObjectAdapter, "TestRepository", mLogger));
+ BOOST_REQUIRE(testImpl != 0);
+ ContainerRepositoryPrx repository = ContainerRepositoryPrx::uncheckedCast(
+ mObjectAdapter->addWithUUID(testImpl));
+ BOOST_REQUIRE(repository != 0);
+
+ string configurationProperty = mCommunicator->getProperties()->getPropertyWithDefault("Test.RootPath", "./data");
+ BOOST_REQUIRE(!configurationProperty.empty());
+ testImpl->configurationAdapter()->setRootPath(configurationProperty);
+ BOOST_CHECK(testImpl->configurationAdapter()->getRootPath() == configurationProperty);
+ mObjectAdapter->remove(repository->ice_getIdentity());
+ repository = 0;
+ testImpl = 0;
+ //
+ // This would be a good spot to put a breakpoint in a destructor if doing a code walk through.
+ //
+ }
+
+private:
+ Ice::CommunicatorPtr mCommunicator;
+ Ice::ObjectAdapterPtr mObjectAdapter;
+ Logger mLogger;
+};
+
+boost::shared_ptr<ContainerRepositoryTests> globalTestSuite;
+
+bool init_unit_test()
+{
+ framework::master_test_suite().add(BOOST_TEST_CASE(boost::bind(&ContainerRepositoryTests::rootPathTest, globalTestSuite)));
+ return true;
+}
int main(int argc, char** argv)
{
+ Logger logger(getLoggerFactory().getLogger("AsteriskSCF.UnitTest.ContainerRepository"));
+
try
{
- Logger logger(getLoggerFactory().getLogger("AsteriskSCF.UnitTest.ContainerRepository"));
-
Ice::CommunicatorPtr communicator(Ice::initialize(argc, argv));
Ice::ObjectAdapterPtr objectAdapter(
communicator->createObjectAdapterWithEndpoints("UTAdapter",
communicator->getProperties()->getPropertyWithDefault("UTAdapter.Endpoints", "default")));
-
- ContainerRepositoryServantPtr testImpl(new ContainerRepositoryServant(objectAdapter, "TestRepository", logger));
- ContainerRepositoryPrx repository = ContainerRepositoryPrx::uncheckedCast(
- objectAdapter->addWithUUID(testImpl));
-
- testImpl->configurationAdapter()->setRootPath(
- communicator->getProperties()->getPropertyWithDefault("Test.RootPath", "./data")
- );
+ globalTestSuite.reset(new ContainerRepositoryTests(communicator, objectAdapter, logger));
+ return unit_test_main(&init_unit_test, argc, argv);
+ }
+ catch (const std::exception& ex)
+ {
+ logger(Error) << "Unexpected " << ex.what() << " caught in main(). Things are on their way to the grave!";
+ return EXIT_FAILURE;
}
catch (...)
{
+ logger(Error) << "A complete unexpected exception has occurred... boo!";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
-}
+}
\ No newline at end of file
commit 35ee1c6397db57a0d69c1a94922c326d38af58b4
Author: Brent Eagles <beagles at digium.com>
Date: Tue Sep 27 13:23:50 2011 -0230
Fixup build issues and deal with moving slice around.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7029935..4d78299 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,7 @@
astscf_project(FileMediaService 3.4)
+add_subdirectory(slice)
add_subdirectory(src)
if(BUILD_TESTING)
add_subdirectory(test)
diff --git a/slice/AsteriskSCF/Configuration/FileMediaService/FileMediaServiceConfigurationIf.ice b/slice/AsteriskSCF/Configuration/FileMediaService/FileMediaServiceConfigurationIf.ice
index 454d456..0728b09 100644
--- a/slice/AsteriskSCF/Configuration/FileMediaService/FileMediaServiceConfigurationIf.ice
+++ b/slice/AsteriskSCF/Configuration/FileMediaService/FileMediaServiceConfigurationIf.ice
@@ -16,6 +16,8 @@
#pragma once
+#include <AsteriskSCF/System/Component/ConfigurationIf.ice>
+#include <AsteriskSCF/FileMediaService/ContainerFileIf.ice>
#include <AsteriskSCF/Media/File/FileMediaIf.ice>
/**
@@ -74,7 +76,7 @@ class RepositoryLocation extends FileMediaServiceItem
string pathname;
};
-const DefaultUpdateInterval = 60; /* Update interval is specified in seconds */
+const long DefaultUpdateInterval = 60; /* Update interval is specified in seconds */
/**
* Configure the background management facility.
@@ -111,7 +113,7 @@ class ContainerItem extends FileMediaServiceItem
/**
* Operations allowed for this container item.
**/
- FileOperations supportedOperations;
+ // XXX default value name scope generation bug!! AsteriskSCF::Media::File::V1::FileOperations supportedOperations;
};
}; /* End of module V1 */
diff --git a/src/ContainerFileIf.ice b/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
similarity index 100%
rename from src/ContainerFileIf.ice
rename to slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
diff --git a/src/MatroskaContainerIf.ice b/slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
similarity index 95%
rename from src/MatroskaContainerIf.ice
rename to slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
index ca8ad7c..f0e1e2d 100644
--- a/src/MatroskaContainerIf.ice
+++ b/slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
@@ -17,7 +17,7 @@
// XXX
// comments
-#include "ContainerFileIf.ice"
+#include <AsteriskSCF/FileMediaService/ContainerFileIf.ice>
#pragma once
diff --git a/slice/AsteriskSCF/Media/File/FileMediaIf.ice b/slice/AsteriskSCF/Media/File/FileMediaIf.ice
deleted file mode 100755
index a75fb2c..0000000
--- a/slice/AsteriskSCF/Media/File/FileMediaIf.ice
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 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
-
-module AsteriskSCF
-{
-module Media
-{
-module File
-{
-module V1
-{
-
-const string ComponentCategory = "FileMediaService";
-const string DiscoveryCategory = "FileMediaService";
-
-/**
- *
- * Supported operations.
- *
- **/
-enum FileOperations
-{
- Playback,
- Recording,
- Both
-};
-
-/**
- *
- * Specifications for required file media specification.
- *
- **/
-struct FileMediaSpecification
-{
- /**
- *
- * A sequence of formats that the File Media Service is expected to accept or produce. This is not used in the
- * same manner as RTP when the media session is allocated. A file media session creates a source or sink for
- * each format specified.
- *
- **/
- AsteriskSCF::Media::V1::FormatSeq formats;
-
- /**
- *
- * The supported file operations.
- *
- */
- FileOperations supportedOperations;
-
- /**
- *
- * Media catalogue identifier. Most relevant to services providing playback. May simply be a filename.
- *
- **/
- string catalogID;
-};
-
-/**
- *
- * The service discovery parameters used for locating file media sessions that support particular
- * options.
- *
- **/
-unsliceable class FileMediaServiceLocator extends AsteriskSCF::Core::Discovery::V1::ServiceLocatorParams
-{
- FileMediaSpecification mediaSpecification;
-};
-/**
- *
- * Indicates that the specified file operation is not supported.
- *
- **/
-exception FileOperationNotAvailable
-{
- string message;
-};
-
-/**
- *
- * Indicates that the file based session could not be allocated with the provided path.
- *
- **/
-exception PathNotAvailable
-{
- string message;
-};
-
-/**
- *
- * Thrown if the specified catalog Id is not available.
- *
- **/
-exception UnknownCatalogID
-{
- string catalogID;
-};
-
-/**
- *
- * The requested file session could not be allocated due to a resource being unavailable.
- * The message data member contains a description of the error. These exceptions may be
- * thrown if the backing file is unavailable for some reason
- * (e.g. sharing violation, unavailable disk drive).
- *
- **/
-exception ResourceUnavailable
-{
- string message;
-};
-
-/**
- *
- * A file media session that includes an accessor for a specification that should be somewhat
- * related to the specification that was used to allocate it. It also defines a control interface
- * for media consumption (in the case of recording) or playback.
- *
- **/
-interface FileSession extends Session
-{
- /**
- *
- * Obtain the specification for the file that backs this session.
- *
- */
- FileMediaSpecification getInfo();
-
- /**
- * Start recording or playback on the Media Session's sinks and/or sources.
- */
- void start();
-
- /**
- * Temporarily halt recording or playback.
- **/
- void pause();
-
- /**
- * Resume recording and/or playback, starting at the point where pause() was called.
- */
- void unpause();
-
- /**
- * Restart recording and/or playback at the beginning. If recording, previously
- * recorded data should be abandoned.
- */
- void restart();
-
- /**
- * Halt recording and/or playback, destroy the object and release any resources
- * held on behalf of this object
- */
- void release();
-};
-
-/**
- *
- * The FileMediaService provides allocation services for File based media sessions.
- *
- **/
-interface FileMediaService
-{
- /**
- *
- * Instantiate a file based session supporting the provided parameters.
- *
- **/
- FileSession* create(FileMediaSpecification parameters) throws FileOperationNotAvailable, UnknownCatalogID,
- ResourceUnavailable;
-
- /**
- *
- * Instantiate a file based session supporting the provided parameters, backed with a file residing at the
- * specified file.
- *
- **/
- FileSession* createWithPath(string path, FileMediaSpecification parameters)
- throws FileOperationNotAvailable, UnknownCatalogID, PathNotAvailable, ResourceUnavailable;
-
-};
-
-} /* end of module V1 */
-} /* end of module File */
-} /* end of module Media */
-} /* end of module AsteriskSCF */
diff --git a/slice/CMakeLists.txt b/slice/CMakeLists.txt
new file mode 100755
index 0000000..7a6ef62
--- /dev/null
+++ b/slice/CMakeLists.txt
@@ -0,0 +1,15 @@
+astscf_slice_collection(GLOBAL
+ NAME FILEMEDIASERVICE
+ PATH "${CMAKE_CURRENT_SOURCE_DIR}"
+ HEADERS "${CMAKE_CURRENT_BINARY_DIR}/astscf-file-media-service/slice-FILEMEDIASERVICE"
+ LIBRARY astscf-file-media-service
+ )
+
+astscf_slice_include_collection(FILEMEDIASERVICE)
+
+astscf_component_init(astscf-file-media-service)
+astscf_component_add_slices(astscf-file-media-service FILEMEDIASERVICE GLOB_RECURSE "AsteriskSCF/*.ice")
+astscf_component_add_slice_collection_libraries(astscf-file-media-service ASTSCF)
+astscf_component_build_library(astscf-file-media-service)
+astscf_slice_collection_install(FILEMEDIASERVICE)
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dc91018..fe1cc2f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,34 +1,38 @@
include_directories(${logger_dir}/include)
include_directories(${astscf-ice-util-cpp_dir}/include)
+
+astscf_slice_include_collection(FILEMEDIASERVICE)
astscf_component_init(FileMediaService)
astscf_component_add_files(FileMediaService
Component.cpp
Config.h
ContainerConfigurationAdapter.h
- ContainerImpl.cpp
- ContainerImpl.h
StreamImpl.cpp
StreamImpl.h
ContainerInfoImpl.cpp
ContainerInfoImpl.h
ContainerRepository.cpp
ContainerRepository.h
- ContainImpl.h
FileMediaServiceComponent.cpp
FileMediaServiceComponent.h
+ ContainerImpl.cpp
+ ContainerImpl.h
LoggerF.h
- MatroskaContainerImpl.cpp
- MatroskaContainerImpl.h
ReplicationListener.h
RepositoryConfigurationAdapter.h
RepositoryReplicationAdapter.h
)
-astscf_component_add_slices(FileMediaService PROJECT
- AsteriskSCF/Replication/FileMediaService/FileMediaSessionStateIf.ice
- ../src/ContainerFileIf.ice
- ../src/MatroskaContainerIf.ice)
+#astscf_component_add_slices(FileMediaService PROJECT
+# AsteriskSCF/Replication/FileMediaService/FileMediaSessionStateIf.ice
+# AsteriskSCF/FileMediaService/ContainerFileIf.ice
+# AsteriskSCF/FileMediaService/MatroskaContainerIf.ice)
astscf_component_add_ice_libraries(FileMediaService IceStorm)
astscf_component_add_boost_libraries(FileMediaService core)
+astscf_component_add_slice_collection_libraries(FileMediaService FILEMEDIASERVICE)
astscf_component_add_slice_collection_libraries(FileMediaService ASTSCF)
astscf_component_build_icebox(FileMediaService)
target_link_libraries(FileMediaService logging-client astscf-ice-util-cpp)
+astscf_component_install(FileMediaService)
+
+# MatroskaContainerImpl.cpp
+# MatroskaContainerImpl.h
diff --git a/src/ContainerImpl.cpp b/src/ContainerImpl.cpp
index cc6f965..4b90b32 100644
--- a/src/ContainerImpl.cpp
+++ b/src/ContainerImpl.cpp
@@ -15,9 +15,22 @@
*/
#include "ContainerImpl.h"
+#include "ContainerRepository.h"
+// #include <matroska/FileKax.h>
+#include <AsteriskSCF/logger.h>
+#include "ContainerConfigurationAdapter.h"
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
+
+using namespace AsteriskSCF::MatroskaContainer::Implementation;
using namespace AsteriskSCF::FileMediaService::MediaContainer::V1;
using namespace AsteriskSCF::System::Logging;
+using namespace std;
+
+/**
+ * The matroska container file is intended to be used on collocation-optimized communicator.
+ **/
namespace AsteriskSCF
{
@@ -25,11 +38,13 @@ namespace MatroskaContainer
{
namespace Implementation
{
+
class ContainerServant : public ContainerImpl
{
public:
- ContainerServant(const Ice::ObjectAdapterPtr& adapter) :
- mAdapter(adapter)
+ ContainerServant(const ContainerInfoPtr info, const Logger& logger) :
+ mInfo(info),
+ mLogger(logger)
{
}
@@ -43,7 +58,7 @@ public:
return StreamInfoSeq();
}
- StreamPrx createStream(const std::string&, const Ice::Current&)
+ StreamPrx createStream(const string& id, const Ice::Current&)
{
return 0;
}
@@ -52,22 +67,21 @@ public:
{
return StreamSeq();
}
-
+
private:
- Ice::ObjectAdapterPtr mAdapter;
+ ContainerInfoPtr mInfo;
+ Logger mLogger;
};
-typedef IceUtil::Handle<ContainerImpl> ContainerImplPtr;
+typedef IceUtil::Handle<ContainerServant> ContainerServantPtr;
-IceUtil::Handle<ContainerImpl>
-ContainerImpl::create(const Ice::ObjectAdapterPtr& adapter, const ContainerInfoPtr&, const Logger&)
+ContainerImplPtr
+ContainerImpl::create(const AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfoPtr& info,
+ const AsteriskSCF::System::Logging::Logger& logger)
{
- //
- // TODO: Find the container itself so it can be opened.
- //
- return new ContainerServant(adapter);
+ return new ContainerServant(info, logger);
}
+
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
-
diff --git a/src/ContainerImpl.h b/src/ContainerImpl.h
index 349c4a1..3ace54f 100644
--- a/src/ContainerImpl.h
+++ b/src/ContainerImpl.h
@@ -16,7 +16,7 @@
#pragma once
-#include "ContainerFileIf.h"
+#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
#include "LoggerF.h"
namespace AsteriskSCF
@@ -25,12 +25,13 @@ namespace MatroskaContainer
{
namespace Implementation
{
+
class ContainerImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::Container
{
public:
- static IceUtil::Handle<ContainerImpl> create(const Ice::ObjectAdapterPtr& adapter,
- const AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfoPtr& info,
- const AsteriskSCF::System::Logging::Logger& logger);
+ static IceUtil::Handle<ContainerImpl> create(
+ const AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfoPtr& info,
+ const AsteriskSCF::System::Logging::Logger& logger);
};
typedef IceUtil::Handle<ContainerImpl> ContainerImplPtr;
diff --git a/src/ContainerInfoImpl.h b/src/ContainerInfoImpl.h
index 467d957..36dbb21 100644
--- a/src/ContainerInfoImpl.h
+++ b/src/ContainerInfoImpl.h
@@ -15,7 +15,7 @@
*/
#pragma once
-#include "MatroskaContainerIf.h"
+#include <AsteriskSCF/FileMediaService/MatroskaContainerIf.h>
#include <vector>
#include <Ice/ObjectFactory.h>
diff --git a/src/ContainerRepository.cpp b/src/ContainerRepository.cpp
index e434b94..99a922a 100644
--- a/src/ContainerRepository.cpp
+++ b/src/ContainerRepository.cpp
@@ -16,12 +16,17 @@
#include "ContainerRepository.h"
#include "ContainerInfoImpl.h"
+#include "ContainerImpl.h"
+#include "ContainerConfigurationAdapter.h"
#include <AsteriskSCF/logger.h>
#include <vector>
#include <string>
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
+
//
// Use latest boost stuff.
//
@@ -134,8 +139,10 @@ class ReplicationAdapterImpl : public RepositoryReplicationAdapter
{
public:
ReplicationAdapterImpl(const ContainerRepositoryServantPtr& containerRepository, const Logger&);
+ ~ReplicationAdapterImpl();
private:
ContainerRepositoryServantPtr mRepository;
+ Logger mLogger;
};
class ConfigurationAdapterImpl : public RepositoryConfigurationAdapter
@@ -146,6 +153,10 @@ public:
void setRootPath(const string& filesystemPath);
void setRunBackgroundUpdatesFlag(bool enable);
void setBackgroundUpdateIntervalInSeconds(unsigned int updateInterval);
+ void removeContainer(const string& catalogId);
+ ContainerConfigurationAdapterPtr addContainer(const string& catalogId, const string& filename, AsteriskSCF::Media::File::V1::FileOperations);
+ ContainerConfigurationAdapterPtr getContainer(const string& id);
+
private:
ContainerRepositoryServantPtr mRepository;
Logger mLogger;
@@ -203,7 +214,24 @@ void UpdaterImpl::setUpdateInterval(const IceUtil::Time& t)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
-// ConfigurationAdapter Implementation
+// ReplicationAdapterImpl Implementation
+//
+ReplicationAdapterImpl::ReplicationAdapterImpl(const ContainerRepositoryServantPtr& containerRepository,
+ const Logger& logger) :
+ mRepository(containerRepository),
+ mLogger(logger)
+{
+ mLogger(Trace) << "Creating repository replication adapter";
+}
+
+ReplicationAdapterImpl::~ReplicationAdapterImpl()
+{
+ mLogger(Trace) << "Destroying repository replication adapter";
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// ConfigurationAdapterImpl Implementation
//
ConfigurationAdapterImpl::ConfigurationAdapterImpl(const ContainerRepositoryServantPtr& containerRepository,
const Logger& logger) :
@@ -241,8 +269,19 @@ void ConfigurationAdapterImpl::setBackgroundUpdateIntervalInSeconds(unsigned int
mRepository->setUpdateInterval(IceUtil::Time::seconds(updateInterval));
}
-void ConfigurationAdapterImpl::removeContainer(const string& catalogId)
+void ConfigurationAdapterImpl::removeContainer(const string&)
+{
+}
+
+ContainerConfigurationAdapterPtr ConfigurationAdapterImpl::addContainer(const string&, const string&,
+ AsteriskSCF::Media::File::V1::FileOperations)
+{
+ return 0;
+}
+
+ContainerConfigurationAdapterPtr ConfigurationAdapterImpl::getContainer(const string&)
{
+ return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -256,7 +295,7 @@ ContainerRepositoryServant::ContainerRepositoryServant(const Ice::ObjectAdapterP
mName(name),
mLogger(logger),
mDestroyed(false),
- mAutoupdate(false)
+ mAutoUpdate(false)
{
}
@@ -265,9 +304,9 @@ ContainerInfoSeq ContainerRepositoryServant::getContainerList(const Ice::Current
SharedLock lock(mLock);
if (mDestroyed)
{
- throw Ice::ObjectNotExistException();
+ throw Ice::ObjectNotExistException(__FILE__, __LINE__);
}
- ContainerInfSeq result;
+ ContainerInfoSeq result;
copy(mContainerInfoList.begin(), mContainerInfoList.end(), result.begin());
return result;
}
@@ -282,11 +321,11 @@ ContainerPrx ContainerRepositoryServant::getContainer(const string& containerId,
SharedLock lock(mLock);
if (mDestroyed)
{
- throw Ice::ObjectNotExistException();
+ throw Ice::ObjectNotExistException(__FILE__, __LINE__);
}
- for (ContainerInfoSeq::const_iterator i = mContainerInfoList.begin(); i != mContainerInfoList.end(); ++i)
+ for (ContainerInfoImplSeq::const_iterator i = mContainerInfoList.begin(); i != mContainerInfoList.end(); ++i)
{
- if (i->id == containerId)
+ if ((*i)->id == containerId)
{
containerInfo = *i;
break;
@@ -323,10 +362,20 @@ ContainerPrx ContainerRepositoryServant::getContainer(const string& containerId,
//
// If we got this far, we need to create a new servant, activate it and move on!
//
- ContainerImplPtr newContainer(ContainerImpl::create(mAdapter, containerInfo, mLogger));
+ ContainerImplPtr newContainer(ContainerImpl::create(containerInfo, mLogger));
return ContainerPrx::uncheckedCast(mAdapter->add(newContainer, id));
}
+RepositoryConfigurationAdapterPtr ContainerRepositoryServant::configurationAdapter()
+{
+ return new ConfigurationAdapterImpl(this, mLogger);
+}
+
+RepositoryReplicationAdapterPtr ContainerRepositoryServant::replicationAdapter()
+{
+ return new ReplicationAdapterImpl(this, mLogger);
+}
+
void ContainerRepositoryServant::refresh()
{
string pathString(getPath());
@@ -353,7 +402,7 @@ void ContainerRepositoryServant::refresh()
for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(p);
i != boost::filesystem::directory_iterator(); ++i)
{
- dirList.push_back(i->string());
+ dirList.push_back(i->path().string());
}
UniqueLock lock(mLock);
@@ -398,7 +447,7 @@ void ContainerRepositoryServant::refresh()
(*containerInfo)->setExistFlag(false);
}
}
- if (mAutoupdate && !dirList.empty())
+ if (mAutoUpdate && !dirList.empty())
{
for (vector<string>::const_iterator filename = dirList.begin(); filename != dirList.end();
++filename)
diff --git a/src/ContainerRepository.h b/src/ContainerRepository.h
index 6a22a9f..5791e75 100644
--- a/src/ContainerRepository.h
+++ b/src/ContainerRepository.h
@@ -16,7 +16,7 @@
#pragma once
-#include "ContainerFileIf.h"
+#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
#include "RepositoryConfigurationAdapter.h"
#include "RepositoryReplicationAdapter.h"
#include "LoggerF.h"
diff --git a/src/FileMediaServiceComponent.cpp b/src/FileMediaServiceComponent.cpp
index 5bc6ee9..46f9a19 100644
--- a/src/FileMediaServiceComponent.cpp
+++ b/src/FileMediaServiceComponent.cpp
@@ -16,12 +16,12 @@
#include "FileMediaServiceComponent.h"
-#include "MatroskaContainerImpl.h"
+#include "ContainerImpl.h"
using namespace AsteriskSCF::FileMediaService;
using namespace std;
-void FileMediaServiceComponent::addFeatureProxyToPrimaryServices(const Ice::ObjectPrx& proxy,
+void FileMediaServiceComponent::addFeatureProxyToServices(const Ice::ObjectPrx& proxy,
const string& category)
{
managePrimaryService(wrapServiceForRegistration(proxy, category));
@@ -43,6 +43,6 @@ void FileMediaServiceComponent::initializeInternals()
//
// We really don't have any properties here.
//
- mInternalCommunicator = Ice::initialize(initData);
+ mInternalCommunicator = Ice::initialize(args);
mRepositoryAdapter = mInternalCommunicator->createObjectAdapter(getName() + ".RepositoryAdapter");
}
diff --git a/src/MatroskaContainerImpl.cpp b/src/MatroskaContainerImpl.cpp
deleted file mode 100644
index 6231545..0000000
--- a/src/MatroskaContainerImpl.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 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.
- */
-
-#include "MatroskaContainerImpl.h"
-#include "ContainerRepository.h"
-#include <matroska/FileKax.h>
-
-using namespace AsteriskSCF::FileMediaService::MatroskaContainer::V1;
-using namespace AsteriskSCF::FileMediaService::MediaContainer::V1;
-
-/**
- * The matroska container file is intended to be used on collocation-optimized communicator.
- **/
-
-namespace
-{
-class ContainerImpl : public Container
-{
-public:
- ContainerInfoPtr getInfo(const Ice::Current&)
- {
- return 0;
- }
-
- StreamInfoSeq getStreamInfo(const Ice::Current&)
- {
- return StreamInfoSeq();
- }
-
- StreamPrx createString(const string& id, const Ice::Current&)
- {
- return 0;
- }
-
- StreamSeq createAllStreams(const Ice::Current&)
- {
- return StreamSeq();
- }
-};
-typedef IceUtil::Handle<ContainerImpl> ContainerImplPtr;
-
-class ContainerRepositoryImpl : public ContainerRepository
-{
-public:
- ContainerInfoSeq getContainerList(const Ice::Current& current)
- {
- }
-
- ContainerPrx getContainer(const string& containerId, const Ice::Current& current)
- {
- }
-
-private:
-
-};
-typedef IceUtil::Handle<ContainerRepositoryImpl> ContainerRepositoryImpl;
-
-
-class RepositoryFactoryImpl : public MatroskaRepositoryFactory
-{
-public:
- //
- // Pretty simple really, just create an instance of the repo object. We don't really expect
- // there to be multiple calls on this, but there is no technical reason to disallow it.
- //
- ContainerRepositoryPrx createRepository(const Ice::Current&)
- {
- ContainerRepositoryImplPtr impl(ContainerRepositoryImpl::create(mAdapter,
- mAdapter->getCommunicator()->getProperties()->
- getPropertyWithDefault("MatroskaContainer.Repository.Id", "MatrsokaContainer")));
- string id("matroska-repo-factory.");
- id += IceUtil::generateUUID();
- return ContainerRepositoryFactoryPrx::uncheckedCast(mAdapter->add(impl,
- mAdapter->getCommunicator()->stringToIdentity(id)));
- }
-
- RepositoryFactoryImpl(const Ice::ObjectAdapterPtr& adapter) :
- mAdapter(adapter)
- {
- }
-private:
- //
- // Note that this adapter is not the one that this servant will be activated on.. it is strictly
- // for the objects created by this repository factory.
- //
- Ice::ObjectAdapterPtr mAdapter;
-};
-
-typedef IceUtil::Handle<RepositoryFactoryImpl> RepositoryFactoryImplPtr;
-
-}
-
-AsteriskSCF::MatroskaContainer::Implementation::MatroskaRepositoryFactoryPtr
-AsteriskSCF::MatroskaContainer::Implementation::MatroskaRepository::create(const Ice::CommunicatorPtr& communicator,
- const string& adapterName)
-{
- Ice::ObjectAdapterPtr adapter = communicator->createAdapterWithEndpoints(adapterName,
- communicator->getProperties()->getPropertyWithDefault(adapterName + ".Endpoints", "default"));
- return new RepositoryFactoryImpl(adapter);
-}
diff --git a/src/MatroskaContainerImpl.h b/src/MatroskaContainerImpl.h
deleted file mode 100644
index d088af5..0000000
--- a/src/MatroskaContainerImpl.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 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
... 3336 lines suppressed ...
--
asterisk-scf/integration/file_media_service.git
More information about the asterisk-scf-commits
mailing list