[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