[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 Oct 12 09:44:42 CDT 2011
branch "initial_development" has been updated
via 12ee5808908be376f29b5246c71106e5d0704f67 (commit)
from 6c709564f50f467984ba65bac6b1568e48246426 (commit)
Summary of changes:
.../FileMediaService/ContainerFileIf.ice | 5 +
.../FileMediaService/MatroskaContainerIf.ice | 49 -
src/CMakeLists.txt | 16 +-
src/Component.cpp | 21 +
src/ContainerConfigurationAdapter.h | 2 +-
src/ContainerImpl.cpp | 935 +++++++++++++++++---
src/ContainerImpl.h | 8 +-
src/ContainerInfoImpl.cpp | 13 +-
src/ContainerInfoImpl.h | 8 +-
src/ContainerRepository.cpp | 13 +-
src/ContainerRepository.h | 4 +-
src/MatroskaCodec.cpp | 2 +-
src/MatroskaCodec.h | 6 +-
src/MatroskaDefines.h | 4 +-
src/MatroskaUtils.cpp | 6 +-
src/MatroskaUtils.h | 4 +-
src/OpaqueContainerData.h | 4 +-
src/RepositoryConfigurationAdapter.h | 2 +-
src/RepositoryReplicationAdapter.h | 2 +-
src/StreamImpl.cpp | 4 +-
src/StreamImpl.h | 4 +-
test/CMakeLists.txt | 7 +-
test/UnitTest_ContainerRepository.cpp | 208 +++--
23 files changed, 1012 insertions(+), 315 deletions(-)
delete mode 100644 slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
- Log -----------------------------------------------------------------
commit 12ee5808908be376f29b5246c71106e5d0704f67
Author: Brent Eagles <beagles at digium.com>
Date: Wed Oct 12 12:13:53 2011 -0230
Systematic removal of libmatroska references. Rewrote playback object in terms
of avformat. More testing and tests required.
diff --git a/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice b/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
index 555b38c..178bc92 100644
--- a/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
+++ b/slice/AsteriskSCF/FileMediaService/ContainerFileIf.ice
@@ -53,6 +53,11 @@ unsliceable class ContainerInfo
* Unique id for the container object.
*/
string id;
+
+ /**
+ * A physical resource identifier
+ */
+ string filename;
/**
* The operations supported by this container. Some may only support a subset of the operations
diff --git a/slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice b/slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
deleted file mode 100644
index f0e1e2d..0000000
--- a/slice/AsteriskSCF/FileMediaService/MatroskaContainerIf.ice
+++ /dev/null
@@ -1,49 +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.
- */
-
-// XXX
-// comments
-
-#include <AsteriskSCF/FileMediaService/ContainerFileIf.ice>
-
-#pragma once
-
-module AsteriskSCF
-{
-module FileMediaService
-{
-module MatroskaContainer
-{
-module V1
-{
-
-unsliceable class MatroskaContainerInfo extends AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfo
-{
- /**
- * The file system file name for the container file.
- */
- string filename;
-};
-
-interface RepositoryFactory
-{
- AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerRepository* createRepository();
-};
-
-}; /* End of module V1 */
-}; /* End of module MatroskaContainer */
-}; /* End of module FileMediaService */
-}; /* End of module AsteriskSCF */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 31c04cc..12d2a9d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,7 +1,5 @@
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)
@@ -9,26 +7,18 @@ astscf_component_add_files(FileMediaService
Component.cpp
Config.h
ContainerConfigurationAdapter.h
- StreamImpl.cpp
- StreamImpl.h
ContainerInfoImpl.cpp
ContainerInfoImpl.h
ContainerRepository.cpp
ContainerRepository.h
FileMediaServiceComponent.cpp
FileMediaServiceComponent.h
- ContainerImpl.cpp
- ContainerImpl.h
- OpaqueContainerData.h
+ ContainerImpl.cpp
+ ContainerImpl.h
LoggerF.h
ReplicationListener.h
RepositoryConfigurationAdapter.h
RepositoryReplicationAdapter.h
- MatroskaDefines.h
- MatroskaCodec.h
- MatroskaCodec.cpp
- MatroskaUtils.h
- MatroskaUtils.cpp
)
astscf_component_add_ice_libraries(FileMediaService IceStorm)
@@ -36,5 +26,5 @@ 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-ebml astscf-matroska)
+target_link_libraries(FileMediaService logging-client astscf-ice-util-cpp avformat avcodec avutil)
astscf_component_install(FileMediaService)
diff --git a/src/Component.cpp b/src/Component.cpp
index c799c85..cc2c829 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -31,6 +31,13 @@
#include "ReplicationContext.h"
#include "FileMediaServiceComponent.h"
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/log.h>
+}
+
using namespace std;
using namespace AsteriskSCF::Core::Routing::V1;
using namespace AsteriskSCF::Core::Discovery::V1;
@@ -61,6 +68,20 @@ public:
// - initialize the Container file library
//
+ void onPreInitialize()
+ {
+ //
+ // Initialize the avX libraries.
+ //
+ av_register_all();
+ avcodec_register_all();
+
+ //
+ // TODO: Should be made configurable.
+ //
+ av_log_set_level(AV_LOG_DEBUG);
+ }
+
void createReplicationStateListeners()
{
}
diff --git a/src/ContainerConfigurationAdapter.h b/src/ContainerConfigurationAdapter.h
index e441f13..7a20189 100644
--- a/src/ContainerConfigurationAdapter.h
+++ b/src/ContainerConfigurationAdapter.h
@@ -21,7 +21,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
diff --git a/src/ContainerImpl.cpp b/src/ContainerImpl.cpp
index 3e04d05..3864aa6 100644
--- a/src/ContainerImpl.cpp
+++ b/src/ContainerImpl.cpp
@@ -16,11 +16,6 @@
#include "ContainerImpl.h"
#include "ContainerRepository.h"
-#include "OpaqueContainerData.h"
-#include "StreamImpl.h"
-
-#include <matroska/FileKax.h>
-#include <ebml/StdIOCallback.h>
#include <AsteriskSCF/logger.h>
@@ -31,100 +26,143 @@
#define BOOST_FILESYSTEM_VERSION 3
#include <boost/filesystem.hpp>
#include <boost/thread/shared_mutex.hpp>
+#include <boost/lexical_cast.hpp>
+
+extern "C"
+{
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+}
-using namespace libmatroska;
-using namespace libebml;
-using namespace AsteriskSCF::MatroskaContainer::Implementation;
using namespace AsteriskSCF::FileMediaService::MediaContainer::V1;
using namespace AsteriskSCF::Media::File::V1;
using namespace AsteriskSCF::Media::V1;
using namespace AsteriskSCF::System::Logging;
using namespace std;
-/**
- * The matroska container file is intended to be used on collocation-optimized communicator.
- **/
+//
+// TODO: While working on the snags of our file handling library, I'm going to assume a single
+// stream.
+//
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
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
+/**
+ *
+ * Base class for file session driver. Basically defines and implements methods that
+ * are used by the driver thread to *do stuff*. All of this probably should be ported
+ * to the thread pool.
+ *
+ */
+class FileSessionIODriver : public AsteriskSCF::Media::File::V1::FileSession
{
public:
- MatroskaImpl(const StdIOCallbackPtr& myIOCallback):
- FileMatroska(*myIOCallback.get()),
- mIOCallback(myIOCallback)
+
+ FileSessionIODriver() :
+ mPaused(false)
{
}
+ virtual bool execute() = 0;
- libebml::IOCallback* getIO()
+ void wait(const IceUtil::Time& waiting)
{
- return mIOCallback.get();
+ Monitor::Lock lock(mMonitor);
+ mMonitor.timedWait(waiting);
}
-private:
- StdIOCallbackPtr mIOCallback;
-
-};
-
-typedef boost::shared_ptr<MatroskaImpl> MatroskaImplPtr;
-class ContainerDataImpl : public OpaqueContainerData
-{
-public:
- ContainerDataImpl(const MatroskaImplPtr& impl) :
- mMatroskaFile(impl)
+ void waitWhilePaused()
{
+ bool paused = true;
+ while(paused)
+ {
+ Monitor::Lock lock(mMonitor);
+ if (mPaused)
+ {
+ mMonitor.wait();
+ }
+ paused = mPaused;
+ }
}
- MatroskaFilePtr getFile() const
+ void pauseImpl()
{
- return boost::dynamic_pointer_cast<FileMatroska>(mMatroskaFile);
+ Monitor::Lock lock(mMonitor);
+ mPaused = true;
+ mMonitor.notify();
}
- libebml::IOCallback* getIO() const
+ void resume()
{
- return mMatroskaFile->getIO();
+ Monitor::Lock lock(mMonitor);
+ mPaused = false;
+ mMonitor.notify();
}
private:
- MatroskaImplPtr mMatroskaFile;
+ typedef IceUtil::Monitor<IceUtil::Mutex> Monitor;
+ Monitor mMonitor;
+ bool mPaused;
};
-typedef IceUtil::Handle<ContainerDataImpl> ContainerDataImplPtr;
-//
-// Forward declarations.
-//
-class ContainerDataImpl;
+typedef IceUtil::Handle<FileSessionIODriver> FileSessionIODriverPtr;
-//
-// TODO: Port to thread pool.
-//
-// The container needs to buffer writes so that only one thread accesses the file at a time.
-//
-class FileIODriver : public IceUtil::Thread
+/**
+ *
+ * The driver thread itself.
+ *
+ */
+class IODriverThread : public IceUtil::Thread
{
public:
- FileIODriver(ContainerDataImpl* container);
+ IODriverThread(const FileSessionIODriverPtr& elem) :
+ mElement(elem),
+ mDone(false)
+ {
+ }
+
+
+ void run()
+ {
+ while(mElement->execute() && !isDone())
+ {
+ }
+ }
+
+ void stop()
+ {
+ UniqueLock lock(mLock);
+ mDone = true;
+ }
- void run();
- void stop();
+ bool isDone()
+ {
+ SharedLock lock(mLock);
+ return mDone;
+ }
private:
- IceUtil::Monitor<IceUtil::Mutex> mMonitor;
- ContainerDataImpl* mContainer;
+ boost::shared_mutex mLock;
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+ FileSessionIODriverPtr mElement;
bool mDone;
-
};
+typedef IceUtil::Handle<IODriverThread> IODriverThreadPtr;
+
+/**
+ *
+ * Wrap up and encapsulate cookie management functions, cut down on
+ * code duplication for the read and write file session implementations.
+ *
+ * TODO: replication.
+ *
+ */
class CookieManager
{
public:
@@ -193,19 +231,86 @@ private:
SessionCookies mCookies;
};
-class PlaybackSessionImpl : public AsteriskSCF::Media::File::V1::FileSession
+/**
+ *
+ * Implementation of a playback file session. A media session of this type does
+ * not implement sink objects, only source objects. Unlike a media session that
+ * interfaces with an external interactive agent, a file session must itself be
+ * active and produce frames with the correct timing. For a media session that
+ * has multiple source streams, frames must be written to the sinks in sensible
+ * order relative to the other source streams in the session. This is
+ * accomplished by having the media session object act as a sort of thread
+ * driven "director" of a series of stream source implementation. Each stream
+ * source implementation basically functions like a sink connection manager,
+ * encoder of ASCF frames from source packets and queue manager of frames to be
+ * delivered. For each "loop" of the thread function, the playback
+ * implementation checks to see if any of the sink managers have no data to
+ * send. If they don't, a packet is read and passed to whoever's sink manager
+ * it is meant for. The next step is to tell all the sink managers that it is
+ * time to figure out if there is something for it to do and if so, do it. This
+ * process also checks the relative time of the last queued frame (if there is
+ * one) and moves a time token forward if it is earlier than the time of the
+ * current token. If there are no frames to deliver, the time token is not
+ * touched.
+ *
+ * TODO:
+ *
+ * - test the living crap out of
+ * - replication
+ *
+ */
+class PlaybackSessionImpl : virtual public FileSessionIODriver
{
public:
- class TrackPlayer : public AsteriskSCF::Media::V1::StreamSource
+ /**
+ * Stream source implemenation. Manages connections with sinks,
+ * converts AVPackets to ASCF frames, and sends data if it is time.
+ */
+ class SinkManager : public AsteriskSCF::Media::V1::StreamSource
{
public:
- TrackPlayer(const string& id, const TrackReaderPtr& reader) :
+ SinkManager(const string& id, const Logger& logger,
+ AVCodecContext* codecContext, AVCodec* codec,
+ const Ice::ObjectAdapterPtr& adapter) :
mId(id),
- mReader(reader),
- mLastRealTime(IceUtil::Time::now())
+ mLogger(logger),
+ mCodecContext(codecContext),
+ mCodec(codec),
+ mAdapter(adapter),
+ mSeqno(0)
{
- mLastTimecode = reader->getStartTimecode();
+ mFormat = new AudioFormat;
+ switch (mCodecContext->sample_fmt)
+ {
+ case SAMPLE_FMT_U8:
+ mFormat->sampleSize = 8;
+ break;
+ case SAMPLE_FMT_S16:
+ mFormat->sampleSize = 16;
+ break;
+ case SAMPLE_FMT_S32:
+ mFormat->sampleSize = 32;
+ break;
+ default:
+ mFormat->sampleSize = 8;
+ //
+ // hrmm.. there are floating point sample formats.
+ //
+ }
+
+ //
+ // TODO: Double check this calc.
+ //
+ mFormat->sampleRate = mCodecContext->sample_rate;
+ mFormat->frameSize = mCodecContext->sample_rate * 20 / 1000;
+ }
+
+ ~SinkManager()
+ {
+ //
+ // TODO cleanup codec context and codec.
+ //
}
void addSink(const StreamSinkPrx& sink, const Ice::Current& current)
@@ -214,9 +319,7 @@ public:
string newSinkId = current.adapter->getCommunicator()->identityToString(sink->ice_getIdentity());
if (mSinks.find(newSinkId) != mSinks.end())
{
- //
- // Probably should indicated that a sink is being updated.
- //
+ mLogger(Info) << mId << " is updating proxy for " << newSinkId;
}
mSinks[newSinkId] = sink;
}
@@ -227,13 +330,32 @@ public:
return getSinksImpl();
}
+ void removeSink(const StreamSinkPrx& sink, const Ice::Current& current)
+ {
+ UniqueLock lock(mLock);
+ string newSinkId = current.adapter->getCommunicator()->identityToString(sink->ice_getIdentity());
+ if (mSinks.find(newSinkId) != mSinks.end())
+ {
+ mSinks.erase(newSinkId);
+ }
+ }
+
FormatSeq getFormats(const Ice::Current&)
{
- return FormatSeq(); // XXX ooo
+ //
+ // TODO: It is actually conceivable that different copies of the same track exist with
+ // different formats. It might be possible to support this.
+ //
+ FormatSeq r;
+ r.push_back(mFormat);
+ return r;
}
string getId(const Ice::Current&)
{
+ //
+ // Immutable, so locking is not necessary.
+ //
return mId;
}
@@ -241,48 +363,165 @@ public:
{
//
// You get what you got!
+ //
+ // TODO: well, it should allow it if the format actually matches!
//
throw MediaFormatSwitchException();
}
- void doWork()
+ //
+ // TODO: Oh gross. Ok, so here is the deal'eo. For fixed/known length
+ // codecs, avcodec returns n frames in a packet, otherwise it returns a
+ // single frame. Would have been a lot simpler if they always returned
+ // a single frame. With that in mind.. this is pretty much broken for
+ // other formats.
+ //
+ void distributePacket(AVPacket& packet)
{
- SharedLock lock(mLock);
//
- // Pull data out from track.
+ // We have to decode the whole packet and store it in our own frame(s), because
+ // the next read or close of the avf context will invalidate the contents
+ // of the packet.
//
- FrameSeq frames;
- IceUtil::Time advance = IceUtil::Time::now() - mLastRealTime;
- mLastRealTime = IceUtil::Time::now();
- uint64 nextTimecode = mLastTimecode + advance.toMilliSeconds();
+ size_t bytesToDecode = packet.size;
+ unsigned char* buf = static_cast<unsigned char*>(packet.data);
+
+ while(bytesToDecode != 0)
+ {
+ FrameSeq frames;
+ AudioFramePtr frame = new AudioFrame;
+ frame->seqno = ++mSeqno;
+ frame->timestamp = packet.dts;
+ frame->mediaFormat = mFormat;
+
+ unsigned long samplesLeft =
+ static_cast<size_t>(mFormat->frameSize) > bytesToDecode ? bytesToDecode: mFormat->frameSize;
+
+ //
+ // TODO: other sample formats.
+ //
+ if (mFormat->sampleSize == 16)
+ {
+ short* buf16 = reinterpret_cast<short*>(buf);
+ Ice::ShortSeq payloadData(buf16, buf16 + samplesLeft);
+ ShortSeqPayloadPtr payloadObj = new ShortSeqPayload;
+ payloadObj->payload = payloadData;
+ frame->payload = payloadObj;
+ }
+ else
+ {
+ Ice::ByteSeq payloadData(buf, buf + samplesLeft);
+ ByteSeqPayloadPtr payloadObj = new ByteSeqPayload;
+ payloadObj->payload = payloadData;
+ frame->payload = payloadObj;
+ }
+
+ bytesToDecode -= samplesLeft;
+ buf += samplesLeft;
+
+ //
+ // TODO: byte order!!! See RTP component for example.
+ //
+
+ //
+ // Note that frames read from a container file ought to be in proper order as it is.
+ //
+ mQueuedFrames.push_back(frame);
+ }
+ }
+
+ bool needsData()
+ {
+ return mQueuedFrames.empty();
+ }
+
+ IceUtil::Time pulse()
+ {
+ //
+ // This one has nothing to contribute.. but we don't have any data so we don't know
+ // if we have something that needs to be sent now, so we set t to now. This should
+ // cause the loop to go around "right now" and read the next packet.
+ //
+ if (mQueuedFrames.empty())
+ {
+ return IceUtil::Time::seconds(0);
+ }
+
+ //
+ // get a snapshot of our current sinks.
+ //
+ StreamSinkSeq mySinks = getSinksImpl();
//
- // Get the frames from the last time to now, it's relative because
+ // Select frames
//
- mReader->getFrames(frames, mLastTimecode, nextTimecode);
+ FrameSeq ready;
+ IceUtil::Time now = IceUtil::Time::now();
//
- // XXX convert frames..
+ // these are set outside the loop because we want to use them afterwards.
//
- AsteriskSCF::Media::V1::FrameSeq ascfFrames;
+ FrameSeq::iterator frameIter = mQueuedFrames.begin();
+ IceUtil::Time frameStamp;
+ bool updateT = false;
- for (SinkMap::const_iterator iter = mSinks.begin(); iter != mSinks.end() ; ++iter)
+ for (; frameIter != mQueuedFrames.end(); ++frameIter)
+ {
+ //
+ // Calculate a timestamp relative to the time that playback started
+ // for this session.
+ //
+ frameStamp = mStartTime;
+ StreamFramePtr p = StreamFramePtr::dynamicCast(*frameIter);
+ if (p)
+ {
+ frameStamp += IceUtil::Time::milliSeconds(p->timestamp);
+ updateT = true;
+ }
+
+ if (frameStamp <= now)
+ {
+ ready.push_back(*frameIter);
+ }
+ }
+ if (!updateT)
+ {
+ frameStamp = IceUtil::Time::seconds(0);
+ }
+
+ //
+ // There aren't any frames to send, leave early.
+ //
+ if (ready.empty())
+ {
+ return frameStamp;
+ }
+
+ for (StreamSinkSeq::const_iterator iter = mySinks.begin(); iter != mySinks.end(); ++iter)
{
try
{
- //
- // Dispatch model?
- //
- iter->second->write(ascfFrames);
+ (*iter)->write(ready);
}
- catch (const std::exception&x)
+ catch (const Ice::ObjectNotExistException&)
{
- //
- // XXX do something.
- //
+ removeSinkImpl(*iter);
+ }
+ catch (const Ice::Exception& ex)
+ {
+ mLogger(Error) << ex.what() << " caught when writing frames to " << (*iter);
+ }
+ catch (...)
+ {
+ mLogger(Error) << "Unknown exception caught when writing frames to " << (*iter);
}
}
- mLastTimecode = nextTimecode;
+ return frameStamp;
+ }
+
+ void start(const IceUtil::Time& newStart)
+ {
+ mStartTime = newStart;
}
private:
@@ -295,9 +534,14 @@ public:
SinkMap mSinks;
string mId;
- TrackReaderPtr mReader;
- uint64 mLastTimecode;
- IceUtil::Time mLastRealTime;
+ Logger mLogger;
+ AVCodecContext* mCodecContext;
+ AVCodec* mCodec;
+ IceUtil::Time mStartTime;
+ Ice::ObjectAdapterPtr mAdapter;
+ size_t mSeqno;
+ AudioFormatPtr mFormat;
+ FrameSeq mQueuedFrames;
StreamSinkSeq getSinksImpl()
{
@@ -308,23 +552,122 @@ public:
}
return results;
}
+
+ void removeSinkImpl(const StreamSinkPrx& sink)
+ {
+ string id = mAdapter->getCommunicator()->identityToString(sink->ice_getIdentity());
+ UniqueLock lock(mLock);
+ mSinks.erase(id);
+ }
};
+ typedef IceUtil::Handle<SinkManager> SinkManagerPtr;
+ typedef vector<SinkManagerPtr> SinkManagerSeq;
- PlaybackSessionImpl(const Ice::ObjectAdapterPtr& adapter, const ContainerReaderPtr& reader, const string& id,
- const FileMediaSpecification& spec) :
+ PlaybackSessionImpl(const Ice::ObjectAdapterPtr& adapter, const string& id,
+ const FileMediaSpecification& spec,
+ const Logger& logger) :
mObjectAdapter(adapter),
- mReader(reader),
mId(id),
- mSpec(spec)
+ mSpec(spec),
+ mLogger(logger),
+ mInput(0),
+ mStarted(false)
{
//
// Nothing to do here yet.
//
}
+ ~PlaybackSessionImpl()
+ {
+ try
+ {
+ if (mInput)
+ {
+ av_close_input_file(mInput);
+ }
+ }
+ catch (...)
+ {
+ }
+ }
+
+ bool setup(const string& filename)
+ {
+ mLogger(Debug) << "Setting up playback session with file: " << filename;
+ //
+ // This should never be called twice.
+ //
+ assert(!mInput);
+ int result = av_open_input_file(&mInput, filename.c_str(), 0, 0, 0);
+ if (result < 0)
+ {
+ //
+ // Crap!!! Actually no, this will never get to this point ..
+ // We should open thing snad pass it into the session instead.
+ //
+ mLogger(Error) << "Unable to open the data file";
+ mInput = 0;
+ return false;
+ }
+ result = av_find_stream_info(mInput);
+ if (result < 0)
+ {
+ mLogger(Error) << "Cannot read header information";
+ av_close_input_file(mInput);
+ mInput = 0;
+ return false;
+ }
+
+ if (mInput->nb_streams < 1)
+ {
+ mLogger(Error) << "Umm.. this file appears to have 0 streams in it.";
+ av_close_input_file(mInput);
+ mInput = 0;
+ return false;
+ }
+
+ mSinkManagers.resize(mInput->nb_streams);
+ for (size_t i = 0; i < mInput->nb_streams; ++i) // TODO: create the relevant sources.
+ {
+ string sourceId = mId;
+ sourceId += ".";
+ sourceId += boost::lexical_cast<string>(i);
+
+ AVCodecContext* codecContext = mInput->streams[i]->codec;
+ if (!codecContext)
+ {
+ mLogger(Debug) << "No codec context for stream " << i << ", skipping.";
+ continue;
+ }
+ AVCodec* codec = avcodec_find_decoder(codecContext->codec_id);
+ if (!codec)
+ {
+ mLogger(Debug) << "Unable to find codec for " << i << " (" << codecContext->codec_id
+ << "), skipping.";
+ continue;
+ }
+
+ result = avcodec_open(codecContext, codec);
+ if (result < 0)
+ {
+ mLogger(Debug) << "Unable to open codec for " << i << " (" << codecContext->codec_id
+ << "), continuing hopefully.";
+ }
+
+
+ mSinkManagers[i] = new SinkManager(sourceId, mLogger, codecContext, codec, mObjectAdapter);
+ Ice::Identity id = mObjectAdapter->getCommunicator()->stringToIdentity(sourceId);
+ mSources.push_back(StreamSourcePrx::uncheckedCast(mObjectAdapter->add(mSinkManagers[i], id)));
+ }
+
+ av_init_packet(&mPacket);
+ return true;
+ }
+
StreamSourceSeq getSources(const Ice::Current&)
{
- return StreamSourceSeq();
+ return mSources;
}
StreamSinkSeq getSinks(const Ice::Current&)
@@ -373,27 +716,166 @@ public:
void start(const Ice::Current&)
{
+ {
+ UniqueLock lock(mLock);
+ if (mStarted)
+ return;
+ mStarted = true;
+ }
+
+ IceUtil::Time currentStart = IceUtil::Time::now();
+
+ for (SinkManagerSeq::const_iterator iter = mSinkManagers.begin();
+ iter != mSinkManagers.end(); ++iter)
+ {
+ if ((*iter))
+ {
+ (*iter)->start(currentStart);
+ }
+ }
+
+ mDriver = new IODriverThread(this);
+ mDriver->start();
}
void pause(const Ice::Current&)
{
+ //
+ // This will cause execute to block until it "unpaused".
+ //
+ pauseImpl();
}
void unpause(const Ice::Current&)
{
+ IceUtil::Time currentStart = IceUtil::Time::now();
+
+ for (SinkManagerSeq::const_iterator iter = mSinkManagers.begin();
+ iter != mSinkManagers.end(); ++iter)
+ {
+ if ((*iter))
+ {
+ (*iter)->start(currentStart);
+ }
+ }
+ resume();
}
void restart(const Ice::Current&)
{
//
- // TODO: this is trickier to implement than I thought!
+ // TODO: this might be trickier to implement than I thought. I will need to think
+ // a bit more about this.
//
}
- void release(const Ice::Current& current)
+ bool execute()
{
- mReader.reset();
+ waitWhilePaused();
+ if (!mStarted)
+ {
+ return false;
+ }
+
+ bool readPacket = false;
+ for (SinkManagerSeq::const_iterator iter = mSinkManagers.begin();
+ iter != mSinkManagers.end() && !readPacket; ++iter)
+ {
+ if ((*iter) && (*iter)->needsData())
+ {
+ readPacket = true;
+ }
+ }
+ //
+ // Ok, somebody needs some data, so lets rock and roll.
+ //
+ if (readPacket)
+ {
+ if(av_read_frame(mInput, &mPacket) < 0)
+ {
+ //
+ // This should indicate that the file is done, return false should break
+ // the driver thread.
+ //
+ return false;
+ }
+ int trackIndex = mPacket.stream_index;
+
+ if (trackIndex >= 0 && trackIndex < static_cast<long>(mSinkManagers.size()))
+ {
+ SinkManagerPtr p = mSinkManagers[trackIndex];
+ if (p)
+ {
+ //
+ // Distribute the data to whomever it was destined for.
+ //
+ p->distributePacket(mPacket);
+ }
+ }
+ else
+ {
+ mLogger(Error) << "Read track index " << trackIndex << ", not sure how to deal with it. "
+ "Continuing on hopefully.";
+ }
+ }
+
+ IceUtil::Time nextWait = IceUtil::Time::now();
+ bool newTime = false;
+
+ for (SinkManagerSeq::const_iterator iter = mSinkManagers.begin();
+ iter != mSinkManagers.end(); ++iter)
+ {
+ if ((*iter))
+ {
+ IceUtil::Time mgrsNextTime = (*iter)->pulse();
+
+ //
+ // If the pulse returns a 0 time, don't adjust our scheduling..
+ // we'll end up relooping immediately if they all do (which is
+ // what we want).
+ //
+ if (mgrsNextTime.toSeconds() != 0)
+ {
+ //
+ // The first non-zero time sets earliest-time-so-far for
+ // comparison.
+ //
+ if (!newTime)
+ {
+ nextWait = mgrsNextTime;
+ newTime = true;
+ }
+ else if (mgrsNextTime < nextWait)
+ {
+ //
+ // Subsequent checks will compare the current earliest
+ // time to the result of the pulse and move the next
+ // scheduled time if necessary.
+ //
+ nextWait = mgrsNextTime;
+ }
+ }
+ }
+ }
+
+ //
+ // We should at this point know if we should wati or not.
+ //
+ if (nextWait > IceUtil::Time::now())
+ {
+ wait(nextWait);
+ }
+
+ //
+ // Woohoo! Go again? Yeah sure, lets!
+ //
+
+ return true;
+ }
+
+ void release(const Ice::Current& current)
+ {
Ice::Identity myAlleged = current.id;
try
{
@@ -402,35 +884,221 @@ public:
catch (const Ice::Exception&)
{
}
+
+ UniqueLock lock(mLock);
+ mStarted = false;
+ mDriver->stop();
+ mDriver = 0;
}
private:
+ boost::shared_mutex mLock;
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+
Ice::ObjectAdapterPtr mObjectAdapter;
- ContainerReaderPtr mReader;
const string mId;
FileMediaSpecification mSpec;
+ Logger mLogger;
CookieManager mCookieManager;
+ AVFormatContext* mInput;
+ SinkManagerSeq mSinkManagers;
+ StreamSourceSeq mSources;
+ AVPacket mPacket;
+ IODriverThreadPtr mDriver;
+ bool mStarted;
+};
+typedef IceUtil::Handle<PlaybackSessionImpl> PlaybackSessionImplPtr;
+
+//
+// End of playback stuff.. start of recording stuff.
+//
+
+//
+// In progress.. lots of questions about multi-stream sinking.
+//
+class FrameWriter : public IceUtil::Shared
+{
+public:
+ FrameWriter(AVFormatContext* output, AVOutputFormat* fmt ):
+ mOutput(output),
+ mOutputFormat(fmt)
+ {
+ }
+
+ void write(const FrameSeq&, unsigned)
+ {
+ UniqueLock lock(mLock);
+
+ AVPacket out;
+ //
+ // TODO: convert frames to apacket.
+ //
+ av_interleaved_write_frame(mOutput, &out);
+
+ }
+
+private:
+ boost::shared_mutex mLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ AVFormatContext* mOutput;
+ AVOutputFormat* mOutputFormat;
};
-class RecordingSessionImpl : public AsteriskSCF::Media::File::V1::FileSession
+typedef IceUtil::Handle<FrameWriter> FrameWriterPtr;
+
+class RecordingSessionImpl : public FileSessionIODriver
{
public:
- RecordingSessionImpl(const Ice::ObjectAdapterPtr& adapter, const ContainerWriterPtr& writer) :
+
+ class SourceManager : public AsteriskSCF::Media::V1::StreamSink
+ {
+ public:
+ SourceManager(const string& id, const FrameWriterPtr&, unsigned trackNo) :
+ mId(id),
+ mTrack(trackNo)
+ {
+ }
+
+ void write(const FrameSeq&, const Ice::Current&)
+ {
+ //
+ // The frames really need to be queued up and written
+ //
+ }
+
+ void setSource(const StreamSourcePrx& source, const Ice::Current&)
+ {
+ UniqueLock lock(mLock);
+ mSource = source;
+ }
+
+ StreamSourcePrx getSource(const Ice::Current&)
+ {
+ SharedLock lock(mLock);
+ return mSource;
+ }
+
+ FormatSeq getFormats(const Ice::Current&)
+ {
+ //
+ // XXX
+ //
+ SharedLock lock(mLock);
+ return FormatSeq();
+ }
+
+ string getId(const Ice::Current&)
+ {
+ SharedLock lock(mLock);
+ return mId;
+ }
+
+ private:
+ string mId;
+ StreamSourcePrx mSource;
+ unsigned mTrack;
+ FrameWriterPtr mWriter;
+
+ boost::shared_mutex mLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ };
+
+ RecordingSessionImpl(const Ice::ObjectAdapterPtr& adapter, const string& id,
+ const FileMediaSpecification& spec) :
mObjectAdapter(adapter),
- mWriter(writer)
+ mId(id),
+ mSpec(spec),
+ mOutput(0),
+ mOutputFormat(0)
{
}
+
+ void setCookies(const SessionCookies& cookies, const Ice::Current&)
+ {
+ mCookieManager.setCookies(cookies);
+ }
+
+ void removeCookies(const SessionCookies& cookies, const Ice::Current&)
+ {
+ mCookieManager.removeCookies(cookies);
+ }
+
+ void getCookies_async(
+ const ::AsteriskSCF::Media::V1::AMD_Session_getCookiesPtr& cb,
+ const AsteriskSCF::Media::V1::SessionCookies& cookiesToGet,
+ const Ice::Current&)
+ {
+ try
+ {
+ cb->ice_response(mCookieManager.getCookies(cookiesToGet));
+ }
+ catch (const Ice::Exception& ex)
+ {
+ cb->ice_exception(ex);
+ }
+ catch (...)
+ {
+ cb->ice_exception();
+ }
+ }
+
+ FileMediaSpecification getInfo(const Ice::Current&)
+ {
+ return mSpec;
+ }
+
+ void start(const Ice::Current&)
+ {
+
+ }
+
+ void pause(const Ice::Current&)
+ {
+ }
+
+ void unpause(const Ice::Current&)
+ {
+ }
+
+ void restart(const Ice::Current&)
+ {
+ //
+ // TODO: this is trickier to implement than I thought!
+ //
+ }
+
+ void release(const Ice::Current& current)
+ {
+ Ice::Identity myAlleged = current.id;
+ try
+ {
+ mObjectAdapter->remove(myAlleged);
+ }
+ catch (const Ice::Exception&)
+ {
+ }
+ }
private:
Ice::ObjectAdapterPtr mObjectAdapter;
- ContainerWriterPtr mWriter;
+ const string mId;
+ FileMediaSpecification mSpec;
+ CookieManager mCookieManager;
+ AVFormatContext* mOutput;
+ AVOutputFormat* mOutputFormat;
};
class ContainerServant : public ContainerImpl
{
public:
- ContainerServant(const ContainerInfoImplPtr& info, const Ice::ObjectAdapterPtr& adapter, const Logger& logger) :
+ ContainerServant(const ContainerInfoImplPtr& info,
+ const FileMediaSpecification& spec,
+ const Ice::ObjectAdapterPtr& adapter, const Logger& logger) :
mInfo(info),
+ mSpec(spec),
mAdapter(adapter),
mLogger(logger)
{
@@ -448,8 +1116,8 @@ public:
// 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)
+ bool success = refresh(uri, supportedOperations);
+ if (!success)
{
//
// TODO:
@@ -459,7 +1127,6 @@ public:
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;
@@ -474,7 +1141,26 @@ public:
{
if (mInfo->supportedOperations == AsteriskSCF::Media::File::V1::Playback)
{
+ //
+ // Just stick to using the adapter to keep track of servants for now.
+ //
+
+ string id = getInfoImpl()->id;
+ id += ".";
+ id += IceUtil::generateUUID();
+ Ice::Identity iceId = mAdapter->getCommunicator()->stringToIdentity(id);
+ PlaybackSessionImplPtr playback = new PlaybackSessionImpl(mAdapter, id, mSpec, mLogger);
+ AsteriskSCF::Media::File::V1::FileSessionPrx result =
+ AsteriskSCF::Media::File::V1::FileSessionPrx::uncheckedCast(mAdapter->add(playback, iceId));
+ //
+ // Creates sources and gets ready to produce data.
+ //
+ if (playback->setup(getInfoImpl()->filename))
+ {
+ return AsteriskSCF::Media::File::V1::FileSessionPrx();
+ }
+ return result;
}
else if(mInfo->supportedOperations == AsteriskSCF::Media::File::V1::Recording)
{
@@ -493,10 +1179,10 @@ private:
typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
ContainerInfoImplPtr mInfo;
+ FileMediaSpecification mSpec;
Ice::ObjectAdapterPtr mAdapter;
Logger mLogger;
- ContainerDataImplPtr mMatroskaData;
ContainerInfoImplPtr getInfoImpl()
{
@@ -504,13 +1190,13 @@ private:
return mInfo;
}
- ContainerDataImplPtr refresh(const string& filename, AsteriskSCF::Media::File::V1::FileOperations supportedOperations)
+ bool 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;
+ return false;
}
boost::filesystem::path filePath(filename);
//
@@ -522,7 +1208,7 @@ private:
// Oh oh.
//
mLogger(Error) << "Provided container information was for directory. Failing.";
- return 0;
+ return false;
}
bool fileExists = boost::filesystem::exists(filePath);
@@ -530,45 +1216,26 @@ private:
{
mLogger(Error) << "Trying to initialize a container file without recording support on a "
"non existent file";
- return 0;
+ return false;
}
- 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;
- }
+ return true;
//
// File I/O is handled by the callback object.
// TODO: we may have to derive from that to get the full functionality that we want.
//
- 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 ContainerInfoImplPtr& info,
+ const FileMediaSpecification& spec,
const Ice::ObjectAdapterPtr& adapter,
const AsteriskSCF::System::Logging::Logger& logger)
{
- return new ContainerServant(info, adapter, logger);
+ return new ContainerServant(info, spec, adapter, logger);
}
diff --git a/src/ContainerImpl.h b/src/ContainerImpl.h
index 33aa8b0..e962b92 100644
--- a/src/ContainerImpl.h
+++ b/src/ContainerImpl.h
@@ -23,7 +23,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -32,17 +32,19 @@ class ContainerImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::
{
public:
- void updateInfo(const std::string& uri, const AsteriskSCF::Media::File::V1::FileOperations supportedOperations);
+ virtual void updateInfo(const std::string& uri,
+ const AsteriskSCF::Media::File::V1::FileOperations supportedOperations) = 0;
static IceUtil::Handle<ContainerImpl> create(
const ContainerInfoImplPtr& info,
+ const AsteriskSCF::Media::File::V1::FileMediaSpecification& spec,
const Ice::ObjectAdapterPtr& adapter,
const AsteriskSCF::System::Logging::Logger& logger);
};
typedef IceUtil::Handle<ContainerImpl> ContainerImplPtr;
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMedaiService */
} /* End of namespace AsteriskSCF */
diff --git a/src/ContainerInfoImpl.cpp b/src/ContainerInfoImpl.cpp
index 08cc036..622225a 100644
--- a/src/ContainerInfoImpl.cpp
+++ b/src/ContainerInfoImpl.cpp
@@ -18,7 +18,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -26,11 +26,7 @@ namespace Implementation
Ice::ObjectPtr ContainerInfoFactory::create(const std::string& typeId)
{
Ice::ObjectPtr result;
- if (typeId == AsteriskSCF::FileMediaService::MatroskaContainer::V1::MatroskaContainerInfo::ice_staticId())
- {
- result = new ContainerInfoImpl;
- }
- else if (typeId == AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfo::ice_staticId())
+ if (typeId == AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfo::ice_staticId())
{
result = new ContainerInfoImpl;
}
@@ -44,8 +40,9 @@ void ContainerInfoFactory::destroy()
//
}
-ContainerInfoImpl::ContainerInfoImpl(const MatroskaContainerInfo& rhs) :
- AsteriskSCF::FileMediaService::MatroskaContainer::V1::MatroskaContainerInfo(rhs),
+ContainerInfoImpl::ContainerInfoImpl(const ContainerInfoImpl& rhs) :
+ IceUtil::Shared(),
+ AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfo(rhs),
mExists(false)
{
}
diff --git a/src/ContainerInfoImpl.h b/src/ContainerInfoImpl.h
index 36dbb21..43fe06e 100644
--- a/src/ContainerInfoImpl.h
+++ b/src/ContainerInfoImpl.h
@@ -15,13 +15,13 @@
*/
#pragma once
-#include <AsteriskSCF/FileMediaService/MatroskaContainerIf.h>
+#include <AsteriskSCF/FileMediaService/ContainerFileIf.h>
#include <vector>
#include <Ice/ObjectFactory.h>
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -42,10 +42,10 @@ public:
* Why create a local version of container object instances? To avoid having to wrap and/or translate to
* an internal implementation type.
*/
-class ContainerInfoImpl : public AsteriskSCF::FileMediaService::MatroskaContainer::V1::MatroskaContainerInfo
+class ContainerInfoImpl : public AsteriskSCF::FileMediaService::MediaContainer::V1::ContainerInfo
{
public:
- ContainerInfoImpl(const MatroskaContainerInfo& rhs);
+ ContainerInfoImpl(const ContainerInfoImpl& rhs);
ContainerInfoImpl();
/**
diff --git a/src/ContainerRepository.cpp b/src/ContainerRepository.cpp
index 56f6748..7542003 100644
--- a/src/ContainerRepository.cpp
+++ b/src/ContainerRepository.cpp
@@ -38,7 +38,8 @@
using namespace AsteriskSCF::FileMediaService::MediaContainer::V1;
using namespace AsteriskSCF::System::Logging;
-using namespace AsteriskSCF::MatroskaContainer::Implementation;
+using namespace AsteriskSCF::FileMediaService::Implementation;
+using namespace AsteriskSCF::Media::File::V1;
using namespace std;
namespace
@@ -208,7 +209,7 @@ UpdaterImpl::UpdaterImpl(const ContainerRepositoryServantPtr& containerRepositor
mRepository(containerRepository),
mLogger(logger),
mDone(false),
- mUpdateInterval(IceUtil::Time::seconds(60))
+ mUpdateInterval(IceUtil::Time::seconds(60)) /* XXX configurable! */
{
}
@@ -454,10 +455,11 @@ ContainerPrx ContainerRepositoryServant::getContainer(const string& containerId,
return ContainerPrx::uncheckedCast(mAdapter->createProxy(id));
}
+ FileMediaSpecification spec; // TODO.
//
// If we got this far, we need to create a new servant, activate it and move on!
//
- ContainerImplPtr newContainer(ContainerImpl::create(containerInfo, mAdapter, mLogger));
+ ContainerImplPtr newContainer(ContainerImpl::create(containerInfo, spec, mAdapter, mLogger));
return ContainerPrx::uncheckedCast(mAdapter->add(newContainer, id));
}
@@ -683,7 +685,6 @@ void ContainerRepositoryServant::setFilenameExtensions(const vector<string>& ext
copy(extensions.begin(), extensions.end(), inserter(mExtensions, mExtensions.begin()));
}
-
vector<string> ContainerRepositoryServant::getFilenameExtensions()
{
SharedLock lock(mLock);
@@ -758,8 +759,8 @@ string ContainerRepositoryServant::getPath()
}
-AsteriskSCF::MatroskaContainer::Implementation::ContainerRepositoryImplPtr
-AsteriskSCF::MatroskaContainer::Implementation::ContainerRepositoryImpl::create(
+AsteriskSCF::FileMediaService::Implementation::ContainerRepositoryImplPtr
+AsteriskSCF::FileMediaService::Implementation::ContainerRepositoryImpl::create(
const Ice::ObjectAdapterPtr& adapter, const string& repositoryName,
const Logger& logger)
{
diff --git a/src/ContainerRepository.h b/src/ContainerRepository.h
index 5791e75..ab705c2 100644
--- a/src/ContainerRepository.h
+++ b/src/ContainerRepository.h
@@ -23,7 +23,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -45,5 +45,5 @@ public:
typedef IceUtil::Handle<ContainerRepositoryImpl> ContainerRepositoryImplPtr;
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/src/MatroskaCodec.cpp b/src/MatroskaCodec.cpp
index e80e9c6..62da989 100755
--- a/src/MatroskaCodec.cpp
+++ b/src/MatroskaCodec.cpp
@@ -16,7 +16,7 @@
#include "MatroskaCodec.h"
-using namespace AsteriskSCF::MatroskaContainer::Implementation;
+using namespace AsteriskSCF::FileMediaService::Implementation;
CodecPtr MatroskaCodecTranslator::create(const AsteriskSCF::Media::V1::FormatPtr&)
diff --git a/src/MatroskaCodec.h b/src/MatroskaCodec.h
index 526b322..5433be0 100755
--- a/src/MatroskaCodec.h
+++ b/src/MatroskaCodec.h
@@ -21,7 +21,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -79,5 +79,5 @@ public:
};
} /* End of namespace implementation */
-} /* End of namespace MatroskaContainer */
-} /* End of namespace AsteriskSCF */
\ No newline at end of file
+} /* End of namespace FileMediaService */
+} /* End of namespace AsteriskSCF */
diff --git a/src/MatroskaDefines.h b/src/MatroskaDefines.h
index f6756d6..12f1f6a 100755
--- a/src/MatroskaDefines.h
+++ b/src/MatroskaDefines.h
@@ -19,7 +19,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -88,5 +88,5 @@ const std::string MatroskaSubtitleHDMVvPGS = "S_HDMV/PGS";
const std::string MatroskaBlobVOB = "B_VOBBTN";
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/src/MatroskaUtils.cpp b/src/MatroskaUtils.cpp
index f548d56..9f2a51c 100755
--- a/src/MatroskaUtils.cpp
+++ b/src/MatroskaUtils.cpp
@@ -64,7 +64,7 @@ using namespace std;
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -1486,7 +1486,7 @@ void ContainerReaderImpl::close()
} /* End of namespace internal. */
-using namespace ::AsteriskSCF::MatroskaContainer::Implementation::Internal;
+using namespace ::AsteriskSCF::FileMediaService::Implementation::Internal;
ContainerWriterPtr ContainerWriter::create()
{
@@ -1536,6 +1536,6 @@ ContainerReaderPtr ContainerReader::locateAndRead(const OpaqueContainerDataPtr&
}
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/src/MatroskaUtils.h b/src/MatroskaUtils.h
index 820b173..222fd44 100755
--- a/src/MatroskaUtils.h
+++ b/src/MatroskaUtils.h
@@ -26,7 +26,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -271,5 +271,5 @@ protected:
};
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namepsace AsteriskSCF */
diff --git a/src/OpaqueContainerData.h b/src/OpaqueContainerData.h
index 32dbfd5..6cd74eb 100644
--- a/src/OpaqueContainerData.h
+++ b/src/OpaqueContainerData.h
@@ -35,7 +35,7 @@ class FileMatroska;
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -53,5 +53,5 @@ public:
typedef IceUtil::Handle<OpaqueContainerData> OpaqueContainerDataPtr;
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/src/RepositoryConfigurationAdapter.h b/src/RepositoryConfigurationAdapter.h
index 8d8816b..86cbd80 100644
--- a/src/RepositoryConfigurationAdapter.h
+++ b/src/RepositoryConfigurationAdapter.h
@@ -24,7 +24,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
diff --git a/src/RepositoryReplicationAdapter.h b/src/RepositoryReplicationAdapter.h
index 419e7c0..bcd5749 100644
--- a/src/RepositoryReplicationAdapter.h
+++ b/src/RepositoryReplicationAdapter.h
@@ -20,7 +20,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
diff --git a/src/StreamImpl.cpp b/src/StreamImpl.cpp
index d7ca7d4..aef5ff7 100644
--- a/src/StreamImpl.cpp
+++ b/src/StreamImpl.cpp
@@ -28,7 +28,7 @@ using namespace libmatroska;
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -39,6 +39,6 @@ StreamSinkImpl::StreamSinkImpl(const TrackWriterPtr& writer) :
}
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/src/StreamImpl.h b/src/StreamImpl.h
index 870a628..e99c0ba 100644
--- a/src/StreamImpl.h
+++ b/src/StreamImpl.h
@@ -25,7 +25,7 @@
namespace AsteriskSCF
{
-namespace MatroskaContainer
+namespace FileMediaService
{
namespace Implementation
{
@@ -49,7 +49,7 @@ private:
typedef IceUtil::Handle<StreamSourceImpl> StreamSourceImplPtr;
} /* End of namespace Implementation */
-} /* End of namespace MatroskaContainer */
+} /* End of namespace FileMediaService */
} /* End of namespace AsteriskSCF */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 2f161c1..b875769 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,7 +1,5 @@
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
@@ -9,9 +7,6 @@ include_directories(${astscf-matroska_dir})
astscf_slice_include_collection(FILEMEDIASERVICE)
astscf_component_init(UnitTestContainerRepository)
astscf_component_add_files(UnitTestContainerRepository UnitTest_ContainerRepository.cpp)
-astscf_component_add_files(UnitTestContainerRepository ../src/OpaqueContainerData.h)
-astscf_component_add_files(UnitTestContainerRepository ../src/ContainerImpl.h)
-astscf_component_add_files(UnitTestContainerRepository ../src/ContainerImpl.cpp)
astscf_component_add_files(UnitTestContainerRepository ../src/ContainerInfoImpl.h)
astscf_component_add_files(UnitTestContainerRepository ../src/ContainerInfoImpl.cpp)
@@ -20,7 +15,7 @@ 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 astscf-matroska astscf-ebml)
+target_link_libraries(UnitTestContainerRepository logging-client astscf-ice-util-cpp avformat avcodec avutil)
pjproject_link(UnitTestContainerRepository pjmedia)
pjproject_link(UnitTestContainerRepository pjlib)
pjproject_link(UnitTestContainerRepository pjlib-util)
diff --git a/test/UnitTest_ContainerRepository.cpp b/test/UnitTest_ContainerRepository.cpp
index d3dce41..cdd54c2 100644
--- a/test/UnitTest_ContainerRepository.cpp
+++ b/test/UnitTest_ContainerRepository.cpp
@@ -27,16 +27,13 @@
#include <boost/test/debug.hpp>
#include <boost/bind.hpp>
-#include <ebml/StdIOCallback.h>
-#include <matroska/FileKax.h>
+#include <Ice/Ice.h>
//
// Yes... we do intend to include the source files.
//
-#include "../src/MatroskaDefines.h"
-#include "../src/MatroskaUtils.cpp"
-#include "../src/OpaqueContainerData.h"
#include "../src/ContainerRepository.cpp"
+#include "../src/ContainerImpl.cpp"
#ifdef WIN32
#pragma warning(push)
@@ -46,72 +43,15 @@
#include <pjmedia.h>
#include <pjlib.h>
+#include <vector>
+
#ifdef WIN32
#pragma warning(pop)
#endif
-using namespace AsteriskSCF::MatroskaContainer::Implementation;
-using namespace AsteriskSCF::MatroskaContainer::Implementation::Internal;
using namespace AsteriskSCF::System::Logging;
using namespace boost::unit_test;
using namespace std;
-using namespace libmatroska;
-using namespace libebml;
-
-class NullOpaqueContainer : public OpaqueContainerData
-{
-public:
- NullOpaqueContainer()
- {
- }
-
- MatroskaFilePtr getFile() const
- {
- return MatroskaFilePtr();
- }
-
- IOCallback* getIO() const
- {
- return 0;
- }
-};
-
-class TestOpaqueContainer : public OpaqueContainerData
-{
-public:
- TestOpaqueContainer(const string& name, bool writing) :
- mIO(0)
- {
- mIO = new StdIOCallback(name.c_str(), (writing ? MODE_CREATE : MODE_READ));
- mMatroska.reset(new FileMatroska(*mIO));
- }
-
- ~TestOpaqueContainer()
- {
- mIO->close();
- //
- // Make sure we release the file before we delete the callback.. lest things go completely snakey.
- //
- mMatroska.reset();
-
- delete mIO;
- }
-
- MatroskaFilePtr getFile() const
- {
- return mMatroska;
- }
-
- IOCallback* getIO() const
- {
- return mIO;
- }
-
-private:
-
- MatroskaFilePtr mMatroska;
- StdIOCallback* mIO;
-};
class ContainerRepositoryTests
{
@@ -202,6 +142,129 @@ public:
}
}
+ class TestSink : public AsteriskSCF::Media::V1::StreamSink
+ {
+ public:
+ TestSink(const string& id) :
+ mId(id)
+ {
+ }
+
+ void write(const FrameSeq& frames, const Ice::Current&)
+ {
+ UniqueLock lock(mLock);
+ mFrames.push_back(frames);
+ }
+
+ void setSource(const AsteriskSCF::Media::V1::StreamSourcePrx&,
+ const Ice::Current&)
+ {
+ }
+
+ AsteriskSCF::Media::V1::StreamSourcePrx getSource(const Ice::Current&)
+ {
+ return AsteriskSCF::Media::V1::StreamSourcePrx();
+ }
+
+ AsteriskSCF::Media::V1::FormatSeq getFormats(const Ice::Current&)
+ {
+ return AsteriskSCF::Media::V1::FormatSeq();
+ }
+
+ string getId(const Ice::Current&)
+ {
+ return mId;
+ }
+
+ vector<FrameSeq> getFrames()
+ {
+ SharedLock lock(mLock);
+ return mFrames;
+ }
+
+ private:
+ string mId;
+ boost::shared_mutex mLock;
+ typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+ typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+
+ vector<FrameSeq> mFrames;
+ };
+
+ typedef IceUtil::Handle<TestSink> TestSinkPtr;
+
+ void testSimplePlayback()
+ {
+ //
+ // The test file can be just about anything, but it should have two relatively small tracks in them
+ // with concurrent timecodes (for simultaneous playback). We don't do internal decoding so whatever
+ // is *inside* is what should come out.
+ //
+ PlaybackSessionImplPtr playback =
+ new PlaybackSessionImpl(mObjectAdapter, "testSimplePlayback", FileMediaSpecification(),
+ mLogger);
+ string containerFileName =
+ mCommunicator->getProperties()->getPropertyWithDefault("Test.SimplePlayback.MkvFile",
+ "simpleplayback.mka");
+
+ bool result = playback->setup(containerFileName);
+
+ BOOST_REQUIRE(result);
+
... 105 lines suppressed ...
--
asterisk-scf/integration/file_media_service.git
More information about the asterisk-scf-commits
mailing list