[asterisk-scf-commits] asterisk-scf/integration/test_channel.git branch "fileplayback-catchup" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon Jun 27 08:00:17 CDT 2011


branch "fileplayback-catchup" has been created
        at  8cf24ecdd763f1ef6a6f2661d2f9606ba112e0cf (commit)

- Log -----------------------------------------------------------------
commit 8cf24ecdd763f1ef6a6f2661d2f9606ba112e0cf
Author: Brent Eagles <beagles at digium.com>
Date:   Fri Jun 24 17:17:46 2011 -0230

    Merging long lost file playback branch.

diff --git a/TestTools.py b/TestTools.py
new file mode 100644
index 0000000..d2da4f5
--- /dev/null
+++ b/TestTools.py
@@ -0,0 +1,112 @@
+#
+# Snippet module for running some simple tests with the test_channel library.
+#
+import Ice
+import AsteriskSCF
+import sys
+
+#
+# The file playback session endpoint implements a specialized SessionEndpoint
+# derived interface, AsteriskSCF::RemoteControl::V1::SessionFactory. This
+# interface allows you to register listeners to automatically be added to
+# session's it creates.  This makes it possible for a session listener to react
+# immediately to events on that session.
+#
+class SessionListener(AsteriskSCF.SessionCommunications.V1.SessionListener):
+    def __init__(self, trackName):
+        self.mTrackname = trackName
+
+    def connected(self, sessionPrx, current):
+        try:
+            if sessionPrx == None:
+                print "Received connect with nil proxy"
+                return
+
+            mediaSession = sessionPrx.getMediaSession()
+            if mediaSession == None:
+                print "No media session"
+                return
+
+            sources = mediaSession.getSources()
+            if len(sources) < 1:
+                print "No sources"
+                return
+
+            remoteControl = AsteriskSCF.RemoteControl.V1.SourcePrx.checkedCast(sources[0].ice_facet("Control"))
+            if remoteControl == None:
+                print "No remote control interface"
+                return
+
+            # 
+            # Media sink should already have been set by the bridge.
+            #
+            print "Starting the playback"
+            remoteControl.playTrack(self.mTrackname)
+            remoteControl.start()
+        except Ice.Exception,e:
+            print e
+
+
+def makeAutoPlaybackListener(filename):
+    return SessionListener(filename)
+
+global communicator
+global adapter
+global testEndpointLocatorPrx
+global endpointLocatorRegistryPrx
+global serviceLocatorPrx
+global sessionListener
+global sessionListenerPrx
+
+# 
+# Set up our Ice communicator and an object adapter.  This code can be safely
+# modified to use configuration for the object adapter configuraiton.
+#
+communicator = Ice.initialize(sys.argv)
+adapter = communicator.createObjectAdapterWithEndpoints("interactive", "default -p 54321")
+adapter.activate()
+
+#
+# Obtain some proxies to the services of interest. We'll use checked casts
+# for now, but these can easily be changed to unchecked casts if you want to 
+# the script to run without really "doing anything" and the services aren't
+# running yet.
+#
+testEndpointLocatorPrx  = AsteriskSCF.Core.Routing.V1.EndpointLocatorPrx.checkedCast(communicator.propertyToProxy("FilePlaybackLocator.Proxy"))
+if testEndpointLocatorPrx == None:
+    print "Unable to obtain file playback endpoint locator."
+    sys.exit(1)
+
+serviceLocatorPrx = AsteriskSCF.Core.Discovery.V1.ServiceLocatorPrx.checkedCast(communicator.propertyToProxy("LocatorService.Proxy"))
+if serviceLocatorPrx == None:
+    print "Unable to obtain service locator proxy."
+    sys.exit(1)
+
+# 
+# The Locator registry is found by way of the service locator.
+#
+searchParams = AsteriskSCF.Core.Discovery.V1.ServiceLocatorParams()
+searchParams.category = AsteriskSCF.Core.Routing.V1.RoutingServiceLocatorRegistryDiscoveryCategory
+endpointRegistryPrx = AsteriskSCF.Core.Routing.V1.LocatorRegistryPrx.checkedCast(serviceLocatorPrx.locate(searchParams))
+if endpointRegistryPrx == None:
+    print "Unable to obtain locator registry proxy."
+    sys.exit(1)
+
+endpointRegistryPrx.addEndpointLocator("fileplayback", ["9.*"], testEndpointLocatorPrx)
+
+sessionListenerPrx = AsteriskSCF.SessionCommunications.V1.SessionListenerPrx.uncheckedCast(adapter.addWithUUID(makeAutoPlaybackListener("blip.au")))
+
+def registerDefaultExampleListener():
+    playbackEndpointPrx = AsteriskSCF.RemoteControl.V1.SessionFactory(testEndpointLocatorPrx.lookup("999")) # can really be anything.
+    playbackEndpointPrx.addDefaultSessionListener(sessionListenerPrx)
+
+#
+# Now we have an environment with everything setup to add a sample session
+# listener.  It is recommended that you instantiate your own session listener
+# instance with an audio file of your liking and add it to the playback
+# endpoint. registerDefaultExampleListener() contains example code on how to do
+# this.
+# 
+# If you run this code as an argument to "python -i", you can interactively 
+# use these variables and methods to perform ad-hoc testing.
+#
diff --git a/slice/AsteriskSCF/TestChannel/RemoteControlIf.ice b/slice/AsteriskSCF/TestChannel/RemoteControlIf.ice
new file mode 100644
index 0000000..d1a30b5
--- /dev/null
+++ b/slice/AsteriskSCF/TestChannel/RemoteControlIf.ice
@@ -0,0 +1,84 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+#pragma once
+
+#include <Ice/BuiltinSequences.ice>
+#include <AsteriskSCF/Media/MediaIf.ice>
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.ice>
+
+module AsteriskSCF
+{
+module TestChannel
+{
+module V1
+{
+
+exception FileNotFoundException
+{
+    string filename;
+};
+
+exception TrackNotFoundException
+{
+    string trackname;
+};
+
+interface SourceController
+{
+    Media::V1::FormatSeq filterFormats(Media::V1::FormatSeq possibleFormats);
+    bool allowFormatChange(Media::V1::Format newFormat); 
+};
+
+interface SinkController
+{
+    Media::V1::FormatSeq filterFormats(Media::V1::FormatSeq possibleFormats);
+    bool allowWrite();
+};
+
+interface Source
+{
+    void start();
+    void pause();
+    void setController(SourceController* controller);
+    Ice::StringSeq listTracks();
+    void playTrack(string trackName)
+        throws FileNotFoundException, TrackNotFoundException;
+
+    Media::V1::StreamSink* getTrackInput(string trackName);
+
+    void destroy();
+};
+
+interface Sink
+{
+    void setController(SinkController* controller);
+    void startRecording();
+    void stopRecording();
+    void reset();
+    void copyToSink(Media::V1::StreamSink* destinationSink);
+
+    void destroy();
+};
+
+interface SessionFactory extends AsteriskSCF::SessionCommunications::V1::SessionEndpoint
+{
+    void addDefaultSessionListener(AsteriskSCF::SessionCommunications::V1::SessionListener* listener);
+    void removeDefaultSessionListener(AsteriskSCF::SessionCommunications::V1::SessionListener* listener);
+};
+
+}; /* End of module V1 */
+}; /* End of module RemoteControl */
+}; /* End of module AsteriskSCF */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5ffa22a..f190124 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,11 +1,16 @@
 astscf_slice_include_collection(TEST_CHANNEL)
+include_directories(${logger_dir}/include)
+include_directories(${astscf-ice-util-cpp_dir}/include)
 
 astscf_component_init(test_channel)
 astscf_component_add_files(test_channel Service.cpp)
 astscf_component_add_files(test_channel MediaEchoThread.cpp)
+astscf_component_add_files(test_channel MediaEchoThread.h)
 astscf_component_add_files(test_channel MediaSession.cpp)
 astscf_component_add_files(test_channel TestEndpoint.cpp)
 astscf_component_add_files(test_channel TestEndpoint.h)
+astscf_component_add_files(test_channel FilePlaybackSessionEndpoint.h)
+astscf_component_add_files(test_channel FilePlaybackSessionEndpoint.cpp)
 astscf_component_add_ice_libraries(test_channel IceStorm)
 astscf_component_add_boost_libraries(test_channel thread date_time)
 astscf_component_add_slice_collection_libraries(test_channel ASTSCF TEST_CHANNEL)
@@ -16,6 +21,7 @@ astscf_component_init(console_driver)
 astscf_component_add_files(console_driver ConsoleDriver.cpp)
 astscf_component_add_files(console_driver ConsoleDriver.h)
 astscf_component_add_files(console_driver main.cpp)
-astscf_component_add_slice_collection_libraries(console_driver TEST_CHANNEL)
+astscf_component_add_slice_collection_libraries(console_driver ASTSCF TEST_CHANNEL)
 astscf_component_build_standalone(console_driver)
 astscf_component_install(console_driver)
+
diff --git a/src/FilePlaybackService.h b/src/FilePlaybackService.h
new file mode 100644
index 0000000..a42889c
--- /dev/null
+++ b/src/FilePlaybackService.h
@@ -0,0 +1,56 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+#pragma once
+
+#include <string>
+#include <Ice/Ice.h>
+
+namespace AsteriskSCF
+{
+namespace FilePlayback
+{
+inline std::string getId(const Ice::Current& current)
+{
+    return current.adapter->getCommunicator()->identityToString(current.id);
+}
+} // End of namespace FilePlayback
+} // End of namespace AsteriskSCF
+
+template <class T>
+class IdentityComparePred : public std::unary_function<T, bool>
+{
+public:
+    IdentityComparePred(const T& example) :
+        mExample(example)
+    {
+    }
+
+    bool operator()(const T& toTest)
+    {
+        if(toTest == 0)
+        {
+            return (mExample == 0);
+        }
+        if(mExample == 0)
+        {
+            return false;
+        }
+        return (mExample->ice_getIdentity() == toTest->ice_getIdentity());
+    }
+private:
+    T mExample;
+};
+
diff --git a/src/FilePlaybackSessionEndpoint.cpp b/src/FilePlaybackSessionEndpoint.cpp
new file mode 100644
index 0000000..a060ee8
--- /dev/null
+++ b/src/FilePlaybackSessionEndpoint.cpp
@@ -0,0 +1,1269 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+#include "FilePlaybackSessionEndpoint.h"
+#include <AsteriskSCF/System/Time/TimeIf.h>
+#include <AsteriskSCF/System/ExceptionsIf.h>
+#include <IceUtil/UUID.h>
+
+#include <boost/filesystem.hpp>
+#include "ListenerManager.h"
+#include "MediaEchoThread.h"
+#include <AsteriskSCF/TestChannel/RemoteControlIf.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/Handle.h>
+#include <pjmedia.h>
+
+#include <fstream>
+#include <memory>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO:
+// * separate class implementations in this file into their own header/source files.
+// * rename the controller interface, its not really a controller but more like a filter/extension point
+//   kind of thing.
+// * finish implementing the "record" functionality provided by the sink.
+// * incorporate matroska catalogue file
+//   * it would be better to incorporate the matroska tools instead of the library directly as they've
+//     implemented loads of higher level stuff. There is another C++ library to look at, but the name
+//     escapes me at the moment.
+// * stereo to mono conversion
+// * real format handling
+//
+
+/**
+ * I usually eschew these using clauses, but the logger 
+ * log level descriptors would get awfully cumbersome if I 
+ * didn't do this.
+ */
+using namespace AsteriskSCF::System::Logging;
+
+namespace FBSPNS /* arbitrary ns name to deal with anonymous NS bugs */
+{
+
+static std::string getFilename(const Ice::CommunicatorPtr& communicator, const std::string& destination,
+  const AsteriskSCF::System::Logging::Logger& logger)
+{
+    boost::filesystem::path basePath = communicator->getProperties()->getProperty("MediaFiles");
+    basePath /= destination;
+    if (!boost::filesystem::exists(basePath))
+    {
+        logger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " non-existent file " << destination;
+        throw AsteriskSCF::TestChannel::V1::FileNotFoundException(basePath.string());
+    }
+    return basePath.string();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Default controller objects.
+//
+class DummySourceController : public AsteriskSCF::TestChannel::V1::SourceController
+{
+public:
+    AsteriskSCF::Media::V1::FormatSeq filterFormats(const AsteriskSCF::Media::V1::FormatSeq& possibleFormats, 
+      const Ice::Current& current)
+    {
+        return possibleFormats;
+    }
+
+    bool allowFormatChange(const AsteriskSCF::Media::V1::FormatPtr& newFormat, const Ice::Current& current)
+    {
+        return true;
+    }
+};
+
+class DummySinkController : public AsteriskSCF::TestChannel::V1::SinkController
+{
+public:
+    AsteriskSCF::Media::V1::FormatSeq filterFormats(const AsteriskSCF::Media::V1::FormatSeq& possibleFormats, 
+      const Ice::Current& current)
+    {
+        return possibleFormats;
+    }
+
+    bool allowWrite(const Ice::Current& current)
+    {
+        return true;
+    }
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Media implementations for file playback and recording.
+//
+
+/**
+ * MatroskaMediaSource - a Media StreamSource object implementation.
+ * This source object is designed to be used along with a remote control
+ * object implemented elsewhere in this project to allow some extra
+ * control over the media information it produces. The remote control 
+ * interface is useful for test suites or interactive testing through
+ * a command line interface or GUI app. 
+ */
+class MatroskaMediaSource : public AsteriskSCF::Media::V1::StreamSource
+{
+public:
+    MatroskaMediaSource(const AsteriskSCF::System::Logging::Logger& logger,
+      const std::string& id, 
+      const AsteriskSCF::TestChannel::V1::SourceControllerPrx& controller,
+      const std::string& defaultFile):
+        mId(id),
+        mController(controller),
+        mDefaultFilename(defaultFile),
+        mThread(new AsteriskSCF::TestUtil::MediaEchoThread),
+        mLogger(logger),
+        mStarted(false)
+    {
+    }
+      
+    //
+    // Media StreamSource interface implementations.
+    //
+    void setSink(const AsteriskSCF::Media::V1::StreamSinkPrx& destination, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        mSink = destination;
+        mThread->setSink(mSink);
+    }
+
+    AsteriskSCF::Media::V1::StreamSinkPrx getSink(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        return mSink;
+    }
+
+    AsteriskSCF::Media::V1::FormatSeq getFormats(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        //
+        // check our list of available formats and filter them through the controller.
+        //
+        if(mController)
+        {
+            return mController->filterFormats(mFormats);
+        }
+        return mFormats;
+    }
+
+    std::string getId(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        //
+        // The id is set at construction and is immutable, there is no need for
+        // a lock here.
+        //
+        return mId;
+    }
+
+    void requestFormat(const AsteriskSCF::Media::V1::FormatPtr& newFormat, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        //
+        // check to see if we can produce the format
+        // then ask the controller if we can switch
+        //
+        if(mController && !mController->allowFormatChange(newFormat))
+        {
+            throw AsteriskSCF::Media::V1::MediaFormatSwitchException();
+        }
+        mCurrentFormat = newFormat;
+    }
+
+    //
+    // Internal methods made available for remote control.
+    //
+
+    //
+    // Start the echo thread.
+    //
+    void startThread()
+    {
+        bool startThread = false;
+        {
+            IceUtil::Mutex::Lock lock(mMutex);
+            if(!mStarted)
+            {
+                mStarted = true;
+                startThread = true;
+            }
+        }
+        mThread->resume();
+        if(startThread)
+        {
+            mThread->start();
+        }
+    }
+
+    void pauseThread()
+    {
+        mThread->pause();
+    }
+
+    //
+    // Set the controller object.
+    //
+    void setController(const AsteriskSCF::TestChannel::V1::SourceControllerPrx& controller)
+    {
+        IceUtil::Mutex::Lock lock(mMutex);
+        mController = controller;
+    }
+
+    //
+    // Get the list of the tracks that are available in this source.
+    //
+    Ice::StringSeq getTracks()
+    {
+        IceUtil::Mutex::Lock lock(mMutex);
+        return mTracks;
+    }
+
+    //
+    // Play the track by name.
+    //
+    void playTrack(const std::string& name, const Ice::Current& current)
+    {
+        if(!mSink)
+        {
+            return;
+        }
+        std::string filename = name;
+        if(name.size() == 0)
+        {
+            filename = mDefaultFilename;
+        }
+        filename = getFilename(current.adapter->getCommunicator(), filename, mLogger);
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            "loading file " << filename;
+
+        //
+        // Find the track, read it into our encoder, and push the frames to the echo thread.
+        //
+
+        // 
+        // The null arguments to this call basically encourage the sox library to 
+        // figure out info about the file on its own. We'll be able to provide
+        // this info by the matroska track info.
+        //
+        bool done = false;
+
+        std::ifstream input(filename.c_str(), std::ios::binary | std::ios::in);
+        if(input.good())
+        {
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+                " file opened successfully " << filename;
+        }
+        else
+        {
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+                " file open failed " << filename;
+            return;
+        }
+        input.seekg(0);
+
+        //
+        // TODO: this and the media echo thread should be put into a separate file.
+        // 
+
+        pjmedia_wave_hdr waveHeader;
+        int rdSize = sizeof(waveHeader) -8;
+        input.get((char*)(&waveHeader), rdSize + 1);
+        if(!input.good() || input.gcount() != rdSize)
+        {
+            std::cout << "header read reported: " << input.gcount() << " was supposed to have read " << rdSize << std::endl;
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+                " unable to read the wav header.";
+            return;
+        }
+        pjmedia_wave_hdr_file_to_host(&waveHeader);
+        
+        if(waveHeader.riff_hdr.riff != PJMEDIA_RIFF_TAG ||
+          waveHeader.riff_hdr.wave != PJMEDIA_WAVE_TAG ||
+          waveHeader.fmt_hdr.fmt != PJMEDIA_FMT_TAG)
+        {
+            mLogger(Debug) << "Riff header " << waveHeader.riff_hdr.riff << " expected " << PJMEDIA_RIFF_TAG;
+            mLogger(Debug) << "Wave header " << waveHeader.riff_hdr.wave << " expected " << PJMEDIA_WAVE_TAG;
+            mLogger(Debug) << "Fmt header " << waveHeader.fmt_hdr.fmt << " expected " << PJMEDIA_FMT_TAG;
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' <<  __FUNCTION__ <<
+                " invalid file format for playback.";
+            return;
+        }
+
+        //
+        // TODO: expand to support other PCM file formats.
+        //
+        if(waveHeader.fmt_hdr.fmt_tag != PJMEDIA_WAVE_FMT_TAG_ULAW)
+        {
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+                " sorry, we are only support ulaw right now."; 
+            return;
+        }
+
+        pjmedia_wave_fmt_tag format = static_cast<pjmedia_wave_fmt_tag>(waveHeader.fmt_hdr.fmt_tag);
+        size_t bytesPerSample = waveHeader.fmt_hdr.bits_per_sample /8;
+
+        if(waveHeader.fmt_hdr.len > 16)
+        {
+            rdSize = waveHeader.fmt_hdr.len -16;
+            input.seekg(rdSize, std::ios_base::cur);
+            if(!input.good())
+            {
+                mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+                    " sorry, processing header.";
+                return;
+            }
+        }
+
+        //
+        // get to the actual audio data.
+        //
+        int readSize = 8;
+        while(true)
+        {
+            pjmedia_wave_subchunk subchunk;
+            input.get(reinterpret_cast<char*>(&subchunk), readSize +1);
+            if(input.gcount() != readSize || !input.good())
+            {
+                mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+                    " sorry, wave file was too short."; 
+                return;
+            }
+            PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&subchunk);
+            if(subchunk.id == PJMEDIA_DATA_TAG)
+            {
+                waveHeader.data_hdr.data = PJMEDIA_DATA_TAG;
+                waveHeader.data_hdr.len = subchunk.len;
+                break;
+            }
+            readSize = subchunk.len;
+            input.seekg(readSize, std::ios_base::cur);
+        }
+
+        //
+        // XXX keeping track of this for now, but we probably don't need it.
+        // 
+        size_t dataStart = input.tellg();
+
+        //
+        // TODO- more file validation.
+        //
+
+        if(waveHeader.fmt_hdr.nchan != 1)
+        {
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+                " sorry, we are only support mono right now.";
+            return;
+        }
+        size_t sampleRate = waveHeader.fmt_hdr.sample_rate;
+        size_t bitsPerSample = waveHeader.fmt_hdr.bits_per_sample;
+        //
+        // TODO: variable clock rates? Media echo thread is set at 8000Hz by default.
+        //
+        size_t samplesPerFrame =  20 * sampleRate / 1000;
+
+        size_t bufSize = samplesPerFrame * bitsPerSample / 8;
+        std::auto_ptr<char> buf(new char[bufSize]);
+        mLogger(Debug) <<  __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+            "Using a buffer size of " << bufSize << " bytes.";
+
+        size_t sequence = 0;
+        AsteriskSCF::Media::V1::FrameSeq frames;
+        AsteriskSCF::Media::V1::AudioFormatPtr mediaFormat(new AsteriskSCF::Media::V1::AudioFormat);
+        mediaFormat->name = "ulaw";
+        mediaFormat->sampleRate = sampleRate;
+        mediaFormat->frameSize = 20;
+        mediaFormat->maximumFrameSize = 20;
+        mediaFormat->minimumFrameSize = 20;
+
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ <<
+            "Format: " << format <<
+            ", Bytes per sample: " << bytesPerSample <<
+            ", Bits per sample: " << bitsPerSample <<
+            ", Data start: " << dataStart <<
+            ", Sample rate: " << sampleRate;
+
+        while(true)
+        {
+            input.get(buf.get(), bufSize +1);
+            size_t bytesRead = input.gcount();
+
+            if(bytesRead == 0)
+            {
+                done = true;
+                break;
+            }
+            //
+            // for the moment we are going to assume that the output is ulaw.
+            //
+            AsteriskSCF::Media::V1::AudioFramePtr frame = new AsteriskSCF::Media::V1::AudioFrame;
+            frame->mediaformat = mediaFormat;
+            frame->seqno = sequence++;
+            frame->timestamp = samplesPerFrame;
+            frame->payload.assign(buf.get(), buf.get()+bytesRead);
+            frames.push_back(frame);
+        }
+        mThread->pushFrames(frames);
+    }
+
+    void destroyImpl()
+    {
+        mThread->destroy();
+    }
+
+private:
+
+    // Lock for the internal state.
+    IceUtil::Mutex mMutex;
+
+    // Id string, required for the StreamSource interface implementation.
+    std::string mId;
+
+    // Remote control object to modify behavior.
+    AsteriskSCF::TestChannel::V1::SourceControllerPrx mController;
+
+    // Default file name or track.
+    const std::string mDefaultFilename;
+
+    // The media sink that will receive the data from the source.
+    AsteriskSCF::Media::V1::StreamSinkPrx mSink;
+
+    // The formats supported by the source.
+    AsteriskSCF::Media::V1::FormatSeq mFormats;
+
+    // Background thread for taking data from the source and
+    // writing the sink at the prescribed rate.
+    AsteriskSCF::TestUtil::MediaEchoThreadPtr mThread;
+
+    // Asterisk SCF logger object.
+    AsteriskSCF::System::Logging::Logger mLogger;
+
+    // The names of the tracks in this source, in string form.
+    Ice::StringSeq mTracks;
+
+    // The current format we are supposed to be using.
+    AsteriskSCF::Media::V1::FormatPtr mCurrentFormat;
+
+    // Flag for whether the media echo thread has been started or not.
+    bool mStarted;
+};
+typedef IceUtil::Handle<MatroskaMediaSource> MatroskaMediaSourcePtr;
+
+/**
+ * This servant is meant to act in tandem with a Media source implementation. 
+ * it forward calls from the source remote control interfaces to a media source
+ * implemented by this service. 
+ **/
+class MatroskaSourceRemoteControl : public AsteriskSCF::TestChannel::V1::Source
+{
+public:
+    MatroskaSourceRemoteControl(const MatroskaMediaSourcePtr& source,
+      const AsteriskSCF::System::Logging::Logger& logger) :
+        mLogger(logger),
+        mSource(source)
+    {
+    }
+    
+    void start(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        mSource->startThread();
+    }
+
+    void pause(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        mSource->pauseThread();
+    }
+    
+    void setController(const AsteriskSCF::TestChannel::V1::SourceControllerPrx& controller, 
+      const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        mSource->setController(controller);
+    }
+
+    Ice::StringSeq listTracks(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        return mSource->getTracks();
+    }
+
+    void playTrack(const std::string& trackName, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        mSource->playTrack(trackName, current);
+    }
+
+    AsteriskSCF::Media::V1::StreamSinkPrx getTrackInput(const std::string& trackName, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        return 0; // XXX 
+    }
+
+    //
+    // there isn't too much to do here except remove the reference to the relevant source object.
+    //
+    void destroy(const Ice::Current& current)
+    {
+        mSource->destroyImpl();
+        mSource = 0;
+    }
+private:
+    AsteriskSCF::System::Logging::Logger mLogger;
+    MatroskaMediaSourcePtr mSource;
+};
+typedef IceUtil::Handle<MatroskaSourceRemoteControl> MatroskaSourceRemoteControlPtr;
+
+/**
+ * MatroskaMediaSink - a Media StreamSink object implementation.
+ * This sink implementation's primary purpose is to act as a cache for
+ * frames written to a media session hosted by this service. The 
+ * cached frames can be "copied" out to a Remote control source object.
+ */
+class MatroskaMediaSink : public AsteriskSCF::Media::V1::StreamSink
+{
+public:
+    MatroskaMediaSink(const AsteriskSCF::System::Logging::Logger& logger, const std::string& id, 
+      const AsteriskSCF::TestChannel::V1::SinkControllerPrx& controller) :
+        mLogger(logger),
+        mId(id),
+        mController(controller)
+    {
+    }
+
+    void write(const AsteriskSCF::Media::V1::FrameSeq& frames, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        mReceivedFrames.insert(mReceivedFrames.end(), frames.begin(), frames.end());
+    }
+
+    void setSource(const AsteriskSCF::Media::V1::StreamSourcePrx& source, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        mSource = source;
+    }
+
+    AsteriskSCF::Media::V1::StreamSourcePrx getSource(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        return mSource;
+    }
+
+    AsteriskSCF::Media::V1::FormatSeq getFormats(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        return mFormats;
+    }
+
+    std::string getId(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
+            " for " << AsteriskSCF::FilePlayback::getId(current);
+        return mId;
+    }
+
+
+private:
+
+    // Lock for the internal state.
+    IceUtil::Mutex mMutex;
+
+    // Logger object.
+    AsteriskSCF::System::Logging::Logger mLogger;
+
+    // Id string, required for the StreamSink interface implementation.
+    std::string mId;
+
+    // Remote control object to modify behavior. 
+    AsteriskSCF::TestChannel::V1::SinkControllerPrx mController;
+
+    // The media source the sink accepts media from.
+    AsteriskSCF::Media::V1::StreamSourcePrx mSource;
+
+    // The formats supported by the sinks.
+    AsteriskSCF::Media::V1::FormatSeq mFormats;
+
+    // The frame cache received by the sink
+    AsteriskSCF::Media::V1::FrameSeq mReceivedFrames;
+};
+typedef IceUtil::Handle<MatroskaMediaSink> MatroskaMediaSinkPtr;
+
+class MatroskaSinkRemoteControl : public AsteriskSCF::TestChannel::V1::Sink
+{
+public:
+    MatroskaSinkRemoteControl(const MatroskaMediaSinkPtr& sink, const AsteriskSCF::System::Logging::Logger& logger) :
+        mSink(sink),
+        mLogger(logger)
+    {
+    }
+
+    void setController(const AsteriskSCF::TestChannel::V1::SinkControllerPrx& controller, const Ice::Current& current)
+    {
+    }
+
+    void startRecording(const Ice::Current& current)
+    {
+    }
+
+    void stopRecording(const Ice::Current& current)
+    {
+    }
+
+    void copyToSink(const AsteriskSCF::Media::V1::StreamSinkPrx& destinationSink, const Ice::Current& current)
+    {
+    }
+    
+    void reset(const Ice::Current& current)
+    {
+    }
+
+    void destroy(const Ice::Current& current)
+    {
+        mSink = 0;
+    }
+
+private:
+    MatroskaMediaSinkPtr mSink;
+    AsteriskSCF::System::Logging::Logger mLogger;
+};
+typedef IceUtil::Handle<MatroskaSinkRemoteControl> MatroskaSinkRemoteControlPtr;
+
+class MatroskaMediaSession : public AsteriskSCF::Media::V1::Session
+{
+public:
+    MatroskaMediaSession(const Ice::ObjectAdapterPtr& adapter, 
+      const AsteriskSCF::System::Logging::Logger& logger,
+      const std::string& file, 
+      const std::string& id) :
+        mAdapter(adapter),
+        mLogger(logger),
+        mFilename(file),
+        mId(id),
+        mDestroyed(false)
+    {
+    }
+
+    ~MatroskaMediaSession()
+    {
+        destroyImpl();
+    }
+
+    void initialize()
+    {
+        mSink = new MatroskaMediaSink(mLogger, mId + ".Sink", 0);
+        mSinkRemoteControl = new MatroskaSinkRemoteControl(mSink, mLogger);
+        mSource = new MatroskaMediaSource(mLogger, mId + ".Source", 0, mFilename);
+        mSourceRemoteControl = new MatroskaSourceRemoteControl(mSource, mLogger);
+
+        Ice::CommunicatorPtr comm = mAdapter->getCommunicator();
+        Ice::Identity id = comm->stringToIdentity(mId + ".Sink");
+        mSinkPrx = AsteriskSCF::Media::V1::StreamSinkPrx::uncheckedCast(mAdapter->add(mSink, id));
+        mSinkControlPrx = AsteriskSCF::TestChannel::V1::SinkPrx::uncheckedCast(
+          mAdapter->addFacet(mSinkRemoteControl, id, "Control"));
+        id = comm->stringToIdentity(mId + ".Source");
+        mSourcePrx = AsteriskSCF::Media::V1::StreamSourcePrx::uncheckedCast(mAdapter->add(mSource, id));
+        mSourceControlPrx = AsteriskSCF::TestChannel::V1::SourcePrx::uncheckedCast(
+          mAdapter->addFacet(mSourceRemoteControl, id, "Control"));
+    }
+
+    void destroyImpl()
+    {
+        {
+            IceUtil::Mutex::Lock lock(mMutex);
+            if(mDestroyed)
+            {
+                return;
+            }
+            mDestroyed = true;
+        }
+        try
+        {
+            mSinkControlPrx->destroy();
+            mSourceControlPrx->destroy();
+            mAdapter->remove(mSinkPrx->ice_getIdentity());
+            mAdapter->remove(mSourcePrx->ice_getIdentity());
+        }
+        catch(const Ice::Exception& ex)
+        {
+            mLogger(Debug) << __FILE__ << ':' << __LINE__ << '(' << __FUNCTION__ << ')' <<
+                ex.what();
+        }
+    }
+
+    AsteriskSCF::Media::V1::StreamSourceSeq getSources(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        if(mDestroyed)
+        {
+            throw Ice::ObjectNotExistException(__FILE__, __LINE__);
+        }
+        AsteriskSCF::Media::V1::StreamSourceSeq result;
+        result.push_back(mSourcePrx);
+        return result;
+    }
+
+    AsteriskSCF::Media::V1::StreamSinkSeq getSinks(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        IceUtil::Mutex::Lock lock(mMutex);
+        if(mDestroyed)
+        {
+            throw Ice::ObjectNotExistException(__FILE__, __LINE__);
+        }
+        AsteriskSCF::Media::V1::StreamSinkSeq result;
+        result.push_back(mSinkPrx);
+        return result;
+    }
+
+    std::string getId(const Ice::Current& current)
+    {
+        IceUtil::Mutex::Lock lock(mMutex);
+        if(mDestroyed)
+        {
+            throw Ice::ObjectNotExistException(__FILE__, __LINE__);
+        }
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " 
+            << AsteriskSCF::FilePlayback::getId(current);
+        return mId;
+    }
+
+private:
+    IceUtil::Mutex mMutex;
+    Ice::ObjectAdapterPtr mAdapter;
+    AsteriskSCF::System::Logging::Logger mLogger;
+    const std::string mFilename;
+    const std::string mId;
+    MatroskaMediaSinkPtr mSink;
+    MatroskaSinkRemoteControlPtr mSinkRemoteControl;
+    AsteriskSCF::Media::V1::StreamSinkPrx mSinkPrx;
+    AsteriskSCF::TestChannel::V1::SinkPrx mSinkControlPrx;
+
+    MatroskaMediaSourcePtr mSource;
+    MatroskaSourceRemoteControlPtr mSourceRemoteControl;
+    AsteriskSCF::Media::V1::StreamSourcePrx mSourcePrx;
+    AsteriskSCF::TestChannel::V1::SourcePrx mSourceControlPrx;
+    bool mDestroyed;
+};
+typedef IceUtil::Handle<MatroskaMediaSession> MatroskaMediaSessionPtr;
+
+typedef AsteriskSCF::TestUtil::ListenerManagerT<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> 
+    SessionListenerMgr;
+
+class FileSession : virtual public AsteriskSCF::SessionCommunications::V1::Session, 
+    virtual public SessionListenerMgr
+{
+public:
+    FileSession(const Ice::ObjectAdapterPtr& adapter, const std::string& id, const std::string& name, 
+      const AsteriskSCF::System::Logging::Logger& logger) : 
+        SessionListenerMgr(adapter->getCommunicator(), id, true),
+        mAdapter(adapter),
+        mId(id),
+        mName(name),
+        mLogger(logger),
+        mDestroyed(false),
+        mMediaSession(new MatroskaMediaSession(adapter, logger, mName, id + ".Media")),
+        mInfo(new AsteriskSCF::SessionCommunications::V1::SessionInfo),
+        mStartTime(static_cast<time_t>(0))
+    {
+        mInfo->role = "callee";
+    }
+
+    void publishProxy(const AsteriskSCF::SessionCommunications::V1::SessionPrx& prx)
+    {
+        mProxy = prx;
+    }
+    
+    void endpointProxy(const AsteriskSCF::SessionCommunications::V1::SessionEndpointPrx& prx)
+    {
+        mInfo->caller = prx;
+        mInfo->destination = prx;
+    }
+
+    void addListener_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_addListenerPtr& cb,
+            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        addListenerImpl(listener);
+        cb->ice_response(updateInfo());
+    }
+
+    void addListenerImpl(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener)
+    {
+        SessionListenerMgr::addListener(listener);
+    }
+
+    void indicate_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_indicatePtr& cb,
+            const AsteriskSCF::SessionCommunications::V1::IndicationPtr& value,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        cb->ice_response();
+    }
+
+    void removeListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, 
+      const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        SessionListenerMgr::removeListener(listener);
+    }
+
+    void connect(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        mStartTime = time(0);
+	mPublisher->indicated(mProxy, new AsteriskSCF::SessionCommunications::V1::ConnectedIndication(),
+                              AsteriskSCF::SessionCommunications::V1::SessionCookies());
+    }
+
+    void flash(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+    }
+
+    void getEndpoint_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_getEndpointPtr& cb,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        cb->ice_response(mInfo->caller);
+    }
+
+    void getInfo_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_getInfoPtr& cb,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        cb->ice_response(updateInfo());
+    }
+
+    void getMediaSession_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_getMediaSessionPtr& cb,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        cb->ice_response(mMediaPrx);
+    }
+
+    void hold(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+	mPublisher->indicated(mProxy, new AsteriskSCF::SessionCommunications::V1::HeldIndication(),
+                              AsteriskSCF::SessionCommunications::V1::SessionCookies());
+    }
+
+    void progress(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr& responseCode, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+    }
+
+    void ring(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+	mPublisher->indicated(mProxy, new AsteriskSCF::SessionCommunications::V1::RingingIndication(),
+                              AsteriskSCF::SessionCommunications::V1::SessionCookies());
+    }
+
+    void start(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        //
+        // Initialize the media sessions now or later? I think I will create the media sessions when I create
+        // the file session but do something a little different once the session is started.
+        // 
+	mPublisher->indicated(mProxy, new AsteriskSCF::SessionCommunications::V1::ConnectedIndication(),
+                              AsteriskSCF::SessionCommunications::V1::SessionCookies());
+    }
+
+    void stop(const AsteriskSCF::SessionCommunications::V1::ResponseCodePtr& responseCode, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+	AsteriskSCF::SessionCommunications::V1::StoppedIndicationPtr indication(new AsteriskSCF::SessionCommunications::V1::StoppedIndication());
+	indication->response = responseCode;
+	mPublisher->indicated(mProxy, indication, AsteriskSCF::SessionCommunications::V1::SessionCookies());
+        mMediaSession->destroyImpl();
+    }
+
+    void unhold(const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+	mPublisher->indicated(mProxy, new AsteriskSCF::SessionCommunications::V1::UnheldIndication(),
+                              AsteriskSCF::SessionCommunications::V1::SessionCookies());
+    }
+
+    void getBridge_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_getBridgePtr& cb,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        cb->ice_response(mBridge);
+    }
+
+    AsteriskSCF::SessionCommunications::V1::SessionInfoPtr setBridge(const AsteriskSCF::SessionCommunications::V1::BridgePrx& bridge, 
+      const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        SessionListenerMgr::addListener(listener);
+        mBridge = bridge;
+        return updateInfo();
+    }
+
+    void setBridge_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_setBridgePtr& cb,
+            const AsteriskSCF::SessionCommunications::V1::BridgePrx& newBridge,
+            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        SessionListenerMgr::addListener(listener);
+        mBridge = newBridge;
+        cb->ice_response(updateInfo());
+    }
+
+    void removeBridge_async(
+            const AsteriskSCF::SessionCommunications::V1::AMD_Session_removeBridgePtr& cb,
+            const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+            const Ice::Current& current)
+    {
+        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+        SessionListenerMgr::removeListener(listener);
+        mBridge = 0;
+        cb->ice_response();
+    }
+
+    void initialize()
+    {
+        mMediaSession->initialize();
+        mMediaPrx = AsteriskSCF::Media::V1::SessionPrx::uncheckedCast(mAdapter->add(mMediaSession,
+              mAdapter->getCommunicator()->stringToIdentity(mId + ".Media")));
+    }
+
+    void destroy()
+    {
+        mMediaSession->destroyImpl();
+    }
+
+    bool destroyed() const
+    {
+        IceUtil::Mutex::Lock lock(mMutex);
+        return mDestroyed;
+    }
+
+    AsteriskSCF::SessionCommunications::V1::SessionInfoPtr updateInfo()
+    {
+        IceUtil::Mutex::Lock lock(mMutex);
+        AsteriskSCF::SessionCommunications::V1::SessionInfoPtr result(
+            AsteriskSCF::SessionCommunications::V1::SessionInfoPtr::dynamicCast(mInfo->ice_clone()));
+        mInfo->connectedTime = (unsigned long)time(0) - (unsigned long)mStartTime;
+        mInfo->startTime = new AsteriskSCF::System::Time::V1::TimeMarker((long)mStartTime, 1.0);
+        return result;
+    }
+
+    void setCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&)
+    {
+    }
+
+    void removeCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&)
+    {
+    }
+
+    AsteriskSCF::SessionCommunications::V1::SessionCookies getCookies(const AsteriskSCF::SessionCommunications::V1::SessionCookies&, const Ice::Current&)
+    {
+	return AsteriskSCF::SessionCommunications::V1::SessionCookies();
+    }
+
+private:
+    IceUtil::Mutex mMutex;
+    Ice::ObjectAdapterPtr mAdapter;
+    std::string mId;
+    std::string mName;
+    AsteriskSCF::System::Logging::Logger mLogger;
+    bool mDestroyed;
+    AsteriskSCF::SessionCommunications::V1::SessionPrx mProxy;
+    AsteriskSCF::SessionCommunications::V1::BridgePrx mBridge;
+    MatroskaMediaSessionPtr mMediaSession;
+    AsteriskSCF::Media::V1::SessionPrx mMediaPrx;
+    AsteriskSCF::SessionCommunications::V1::SessionInfoPtr mInfo;
+    time_t mStartTime;
+};
+
+typedef IceUtil::Handle<FileSession> FileSessionPtr;
+
+struct FileSessionInfo
+{
+    FileSessionPtr servant;
+    AsteriskSCF::SessionCommunications::V1::SessionPrx proxy;
+};
+
+AsteriskSCF::SessionCommunications::V1::SessionPrx getProxies(const FileSessionInfo& info)
+{
+    return info.proxy;
+}
+
+}
+using namespace FBSPNS;
+
+namespace AsteriskSCF
+{
+namespace FilePlayback
+{
+class FilePlaybackEndpointImpl
+{
+public:
+    FilePlaybackEndpointImpl(const Ice::ObjectAdapterPtr& adapter, const AsteriskSCF::System::Logging::Logger& logger);
+    AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(const std::string& destination, 
+      const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current&);
+    AsteriskSCF::SessionCommunications::V1::SessionSeq getSessions(const Ice::Current&);
+    void addDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current);
+    void removeDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current);
+private:
+
+    AsteriskSCF::System::Logging::Logger mLogger;
+    Ice::ObjectAdapterPtr mAdapter;
+    std::vector<FileSessionInfo> mSessions;
+    std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx> mDefaultListeners;
+    IceUtil::Mutex mMutex;
+
+    void reap();
+};
+}
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// FilePlaybackEndpointImpl
+//
+AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::FilePlaybackEndpointImpl(const Ice::ObjectAdapterPtr& adapter,
+  const AsteriskSCF::System::Logging::Logger& logger):
+    mLogger(logger),
+    mAdapter(adapter)
+{
+}
+
+static bool
+nonIdChar(const char c)
+{
+    return !isalnum(c);
+}
+
+static std::string
+pathToId(const std::string& path)
+{
+    std::string result = path;
+    std::replace_if(result.begin(), result.end(), nonIdChar, '.');
+    return result;
+}
+
+AsteriskSCF::SessionCommunications::V1::SessionPrx AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::createSession(
+  const std::string& destination, const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, 
+  const Ice::Current& current)
+{
+    std::string myId = AsteriskSCF::FilePlayback::getId(current);
+    mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << myId;
+    std::string file;
+    try
+    {
+        file = getFilename(current.adapter->getCommunicator(), destination, mLogger);
+    }
+    catch(const AsteriskSCF::TestChannel::V1::FileNotFoundException&)
+    {
+        throw AsteriskSCF::SessionCommunications::V1::SessionCreationException();
+    }
+    myId += '.';
+    myId += destination;
+    myId = pathToId(myId);
+    myId += '.';
+    myId += IceUtil::generateUUID();
+
+    FileSessionPtr newSession(new FileSession(mAdapter, myId, file, mLogger));
+    //
+    // The only place that is liable to throw after newSession is created is
+    // the addition to the object adapter. If that occurs, the adapter will not
+    // have a reference and the servant will be deleted when newSession goes
+    // out of scope.
+    //
+    try
+    {
+        //
+        // Order of calls is a little important here. "initialize()" is called
+        // on the new session before anything else as a kind of "check" to make
+        // sure nothing in the initialization of the session depends on the
+        // session being activated. That being said, calling initialize before
+        // adding it means that the objects are all ready to start receiving
+        // requests.
+        //
+        newSession->initialize();
+        for(std::vector<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>::const_iterator i = mDefaultListeners.begin();
+          i != mDefaultListeners.end(); ++i)
+        {
+            newSession->addListenerImpl(*i);
+        }
+        AsteriskSCF::SessionCommunications::V1::SessionPrx prx(
+          AsteriskSCF::SessionCommunications::V1::SessionPrx::uncheckedCast(
+              mAdapter->add(newSession, mAdapter->getCommunicator()->stringToIdentity(myId))));
+        newSession->publishProxy(prx);
+        if(listener)
+        {
+            newSession->addListenerImpl(listener);
+        }
+        FileSessionInfo info;
+        info.servant = newSession;
+        info.proxy = prx;
+
+        IceUtil::Mutex::Lock lock(mMutex);
+        mSessions.push_back(info);
+        return prx;
+    }
+    catch (const Ice::Exception& ex)
+    {
+        mLogger(Error) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " exception caught " << ex.what();
+        throw AsteriskSCF::SessionCommunications::V1::SessionCreationException(destination);
+    }
+}
+
+AsteriskSCF::SessionCommunications::V1::SessionSeq AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::getSessions(
+  const Ice::Current& current)
+{
+    mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+    IceUtil::Mutex::Lock lock(mMutex);
+    reap();
+    AsteriskSCF::SessionCommunications::V1::SessionSeq result(mSessions.size());
+    std::transform(mSessions.begin(), mSessions.end(), result.begin(), getProxies);
+    return result;
+}
+
+void AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::addDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current)
+{
+    mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+    if(!listener)
+    {
+        mLogger(Debug) << __FUNCTION__ << ":" << 
+            current.adapter->getCommunicator()->identityToString(current.id) <<  " attempting to add a null proxy";
+        throw AsteriskSCF::System::V1::NullProxyException();
+    }
+    IceUtil::Mutex::Lock lock(mMutex);
+    if(mDefaultListeners.end() == std::find_if(mDefaultListeners.begin(), mDefaultListeners.end(), 
+          IdentityComparePred<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>(listener)))
+    {
+        mDefaultListeners.push_back(listener);
+    }
+}
+
+void AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::removeDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current)
+{
+    mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " for " << AsteriskSCF::FilePlayback::getId(current);
+    std::cerr << __FUNCTION__ << ":" << current.adapter->getCommunicator()->identityToString(current.id) << std::endl;
+    if(!listener)
+    {
+        mLogger(Debug) << __FUNCTION__ << ":" << current.adapter->getCommunicator()->identityToString(current.id) 
+            <<  " attempting to remove a null proxy";
+        throw AsteriskSCF::System::V1::NullProxyException();
+    }
+    IceUtil::Mutex::Lock lock(mMutex);
+    std::remove_if(mDefaultListeners.begin(), mDefaultListeners.end(), 
+      IdentityComparePred<AsteriskSCF::SessionCommunications::V1::SessionListenerPrx>(listener)); 
+}
+
+void AsteriskSCF::FilePlayback::FilePlaybackEndpointImpl::reap()
+{
+    mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << " reaping.";
+    std::vector<FileSessionInfo> remainingSessions;
+    for (std::vector<FileSessionInfo>::iterator i = mSessions.begin(); i != mSessions.end(); ++i)
+    {
+        if (!i->servant->destroyed())
+        {
+            remainingSessions.push_back(*i);
+        }
+        else
+        {
+            i->servant = 0;
+            mAdapter->remove(i->proxy->ice_getIdentity());
+        }
+    }
+    mSessions = remainingSessions;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// FilePlaybackEndpoint
+//
+AsteriskSCF::FilePlayback::FilePlaybackEndpoint::FilePlaybackEndpoint(const Ice::ObjectAdapterPtr& adapter, 
+  const AsteriskSCF::System::Logging::Logger& logger) :
+    mImpl(new FilePlaybackEndpointImpl(adapter, logger)),
+    mId("fileplayback")
+{
+}
+
+AsteriskSCF::FilePlayback::FilePlaybackEndpoint::~FilePlaybackEndpoint()
+{
+    delete mImpl;
+}
+
+AsteriskSCF::SessionCommunications::V1::SessionPrx AsteriskSCF::FilePlayback::FilePlaybackEndpoint::createSession(const std::string& destination, 
+  const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current)
+{
+    return mImpl->createSession(destination, listener, current);
+}
+
+AsteriskSCF::SessionCommunications::V1::SessionSeq AsteriskSCF::FilePlayback::FilePlaybackEndpoint::getSessions(const Ice::Current& current)
+{
+    return mImpl->getSessions(current);
+}
+
+std::string AsteriskSCF::FilePlayback::FilePlaybackEndpoint::getId(const Ice::Current&)
+{
+    return mId;
+}
+
+void AsteriskSCF::FilePlayback::FilePlaybackEndpoint::addDefaultSessionListener(
+  const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+  const Ice::Current& current)
+{
+    mImpl->addDefaultSessionListener(listener, current);
+}
+
+void AsteriskSCF::FilePlayback::FilePlaybackEndpoint::removeDefaultSessionListener(
+  const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener,
+  const Ice::Current& current)
+{
+    mImpl->removeDefaultSessionListener(listener, current);
+}
diff --git a/src/FilePlaybackSessionEndpoint.h b/src/FilePlaybackSessionEndpoint.h
new file mode 100644
index 0000000..d3b830b
--- /dev/null
+++ b/src/FilePlaybackSessionEndpoint.h
@@ -0,0 +1,50 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#pragma once
+
+#include "FilePlaybackService.h"
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include <AsteriskSCF/TestChannel/RemoteControlIf.h>
+#include <string>
+#include <Ice/Ice.h>
+#include <AsteriskSCF/logger.h>
+
+namespace AsteriskSCF
+{
+namespace FilePlayback
+{
+    class FilePlaybackEndpointImpl;
+
+    class FilePlaybackEndpoint : public AsteriskSCF::TestChannel::V1::SessionFactory
+    {
+    public:
+        FilePlaybackEndpoint(const Ice::ObjectAdapterPtr& adapter, const AsteriskSCF::System::Logging::Logger&);
+        ~FilePlaybackEndpoint();
+
+        AsteriskSCF::SessionCommunications::V1::SessionPrx createSession(const std::string& destination, 
+          const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& callback, const Ice::Current&);
+        AsteriskSCF::SessionCommunications::V1::SessionSeq getSessions(const Ice::Current&);
+        std::string getId(const Ice::Current&);
+
+        void addDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current);
+        void removeDefaultSessionListener(const AsteriskSCF::SessionCommunications::V1::SessionListenerPrx& listener, const Ice::Current& current);
+    private:
+        FilePlaybackEndpointImpl* mImpl;
+        std::string mId;
+    };
+} // End of namespace FileplayBack
+} // End of namespace AsteriskSCF
diff --git a/src/ListenerManager.h b/src/ListenerManager.h
index 17f3932..8182b9a 100644
--- a/src/ListenerManager.h
+++ b/src/ListenerManager.h
@@ -10,10 +10,12 @@
 #include <Ice/Ice.h>
 #include <IceStorm/IceStorm.h>
 #include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
 #include <string>
 #include <algorithm>
 #include <vector>
 #include "InternalExceptions.h"
+#include <IceUtil/Thread.h>
 
 namespace AsteriskSCF
 {
@@ -23,66 +25,64 @@ namespace TestUtil
 // Helper template for classes that need to implement listener style interfaces.
 //
 template <class T>
-class ListenerManagerT : public IceUtil::Shared
+class ListenerManagerT 
 {
     typedef std::vector<T> ListenerSeq;
     typename std::vector<T>::iterator ListenerIter;
-public:
-    ListenerManagerT(const Ice::CommunicatorPtr& communicator, const std::string& topicName) :
-        mCommunicator(communicator),
-        mTopicName(topicName)
+
+    class InitializationThread : public IceUtil::Thread
     {
-        //
-        // TODO: While this is being concocted for a single component, it would make more sense
-        // to have the topic manager passed in during construction for more general usage.
-        //
-        const std::string propertyName = "TopicManager.Proxy";
-        std::string topicManagerProperty = mCommunicator->getProperties()->getProperty(propertyName);
-        if(topicManagerProperty.size() == 0)
+    public:
+        InitializationThread(ListenerManagerT* mgr) :
+            mMgr(mgr),
+            mStopped(false)
         {
-            throw ConfigException(propertyName, "Topic manager proxy property missing. "
-                "Unable to initialize listener support.");
         }
 
-        try
-        {
-            mTopicManager = IceStorm::TopicManagerPrx::checkedCast(mCommunicator->stringToProxy(topicManagerProperty));
-        }
-        catch(const Ice::Exception&)
+        void run()
         {
+            bool initialized = false;
+            IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+            while(!mStopped && !initialized)
+            {
+                //
+                // TODO: Make configurable.
+                //
+                mMonitor.timedWait(IceUtil::Time::seconds(15));
+                initialized = mMgr->init();
+            }
         }
-        if(!mTopicManager)
+
+        void stop()
         {
-            throw ConfigException(propertyName, "Topic manager proxy is not a valid proxy or is unreachable");
+            IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+            mStopped = true;
+            mMonitor.notify();
         }
 
+    private:
+        IceUtil::Monitor<IceUtil::Mutex> mMonitor;
+        ListenerManagerT* mMgr;
+        bool mStopped;
+    };
+
+public:
+    ListenerManagerT(const Ice::CommunicatorPtr& communicator, const std::string& topicName, bool enableBackgroundInit) :
+        mCommunicator(communicator),
+        mTopicName(topicName),
+        mInitialized(false)
+    {
         try
         {
-            mTopic = mTopicManager->retrieve(mTopicName);
+            init();
         }
-        catch(const IceStorm::NoSuchTopic&)
+        catch(const Ice::Exception&)
         {
         }
-
-        if(!mTopic)
+        if(!mInitialized && enableBackgroundInit)
         {
-            try
-            {
-                mTopic = mTopicManager->create(mTopicName);
-            }
-            catch(const IceStorm::TopicExists&)
-            {
-                //
-                // In case there is a race condition when creating the topic.
-                //
-                mTopic = mTopicManager->retrieve(mTopicName);
-            }
-        }
-
-        if(!mTopic)
-        {
-            throw ConfigException(propertyName,
-                std::string("unable to create topic with the provided configuration :") + mTopicName);
+            mInitThread = new InitializationThread(this);
+            mInitThread->start();
         }
     }
 
@@ -101,6 +101,9 @@ public:
                 //
             }
         }
+        ///
+        // TODO: join on initialization thread for destruction.
+        //
     }
 
     //
@@ -114,17 +117,22 @@ public:
         {
             mListeners.push_back(listener);
         }
-        IceStorm::QoS qos;
-        qos["reliability"] = "ordered";
-        try
-        {
-            mTopic->subscribeAndGetPublisher(qos, listener);
-        }
-        catch(const IceStorm::AlreadySubscribed&)
+
+        if(mInitialized)
         {
-            //
-            // This indicates some kind of inconsistent state.
-            //
+            IceStorm::QoS qos;
+            qos["reliability"] = "ordered";
+
+            try
+            {
+                mTopic->subscribeAndGetPublisher(qos, listener);
+            }
+            catch(const IceStorm::AlreadySubscribed&)
+            {
+                //
+                // This indicates some kind of inconsistent state.
+                //
+            }
         }
     }
 
@@ -135,7 +143,10 @@ public:
         if(i != mListeners.end())
         {
             mListeners.erase(i);
-            mTopic->unsubscribe(listener);
+            if(mInitialized)
+            {
+                mTopic->unsubscribe(listener);
+            }
         }
     }
 
@@ -146,13 +157,112 @@ public:
         return result;
     }
 
+    bool isSuspended()
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        return !mInitialized;
+    }
+
+    void stop()
+    {
+        if(mInitThread)
+        {
+            mInitThread->stop();
+        }
+    }
+
 protected:
     boost::shared_mutex mLock;
     Ice::CommunicatorPtr mCommunicator;
     std::string mTopicName;
     IceStorm::TopicPrx mTopic;
     IceStorm::TopicManagerPrx mTopicManager;
+    T mPublisher;
     ListenerSeq mListeners;
+    IceUtil::Handle<InitializationThread> mInitThread;
+
+    bool mInitialized;
+
+    bool init()
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        if(mInitialized)
+        {
+            return mInitialized;
+        }
+
+        //
+        // TODO: While this is being concocted for a single component, it would make more sense
+        // to have the topic manager passed in during construction for more general usage.
+        //
+        const std::string propertyName = "TopicManager.Proxy";
+        std::string topicManagerProperty = mCommunicator->getProperties()->getProperty(propertyName);
+        if(topicManagerProperty.size() == 0)
+        {
+            throw ConfigException(propertyName, "Topic manager proxy property missing. "
+                "Unable to initialize listener support.");
+        }
+
+        try
+        {
+            mTopicManager = IceStorm::TopicManagerPrx::checkedCast(mCommunicator->stringToProxy(topicManagerProperty));
+        }
+        catch(const Ice::Exception&)
+        {
+            return false;
+        }
+
+        try
+        {
+            mTopic = mTopicManager->retrieve(mTopicName);
+        }
+        catch(const IceStorm::NoSuchTopic&)
+        {
+        }
+
+        if(!mTopic)
+        {
+            try
+            {
+                mTopic = mTopicManager->create(mTopicName);
+            }
+            catch(const IceStorm::TopicExists&)
+            {
+                //
+                // In case there is a race condition when creating the topic.
+                //
+                mTopic = mTopicManager->retrieve(mTopicName);
+            }
+        }
+
+        if(!mTopic)
+        {
+            return mInitialized;
+        }
+        mPublisher = T::uncheckedCast(mTopic->getPublisher());
+
+        if(mListeners.size() > 0)
+        {
+            for(typename std::vector<T>::iterator i = mListeners.begin(); i != mListeners.end(); ++i)
+            {
+                IceStorm::QoS qos;
+                qos["reliability"] = "ordered";
+
+                try
+                {
+                    mTopic->subscribeAndGetPublisher(qos, *i);
+                }
+                catch(const IceStorm::AlreadySubscribed&)
+                {
+                    //
+                    // This indicates some kind of inconsistent state.
+                    //
+                }
+            }
+        }
+        mInitialized = true;
+        return mInitialized;
+    }
 };
 }
 }
diff --git a/src/Logger.h b/src/Logger.h
deleted file mode 100644
index e045b41..0000000
--- a/src/Logger.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Asterisk Scalable Communications Framework
- *
- * Copyright (C) 2010 -- Digium, Inc.
- *
- * All rights reserved.
- */
-#pragma once
-
-#include <iostream>
-
-namespace AsteriskSCF
-{
-namespace TestUtil
-{
-//
-// Place holder log stream holder.
-//
-class Logger
-{
-public:
-    Logger() :
-        mTraceDebug(true)
-    {
-    }
-
-    std::ostream& getTraceStream()
-    {
-        return std::cerr;
-    }
-
-    std::ostream& getErrorStream()
-    {
-        return std::cerr;
-    }
-
-    std::ostream& getDebugStream()
-    {
-        return std::cerr;
-    }
-
-    bool debugTracing() { return mTraceDebug; }
-
-    std::ostream& getInfoStream()
-    {
-        return std::cerr;
-    }
-
-private:
-    bool mTraceDebug;
-};
-} // End of namespace TestUtil
-} // End of namespace AsteriskSCF
diff --git a/src/MediaEchoThread.cpp b/src/MediaEchoThread.cpp
index c9eccf1..dcd2ee7 100644
--- a/src/MediaEchoThread.cpp
+++ b/src/MediaEchoThread.cpp
@@ -19,37 +19,94 @@ using namespace AsteriskSCF::TestUtil;
 
 MediaEchoThread::MediaEchoThread():
     mDone(false),
-    mPaused(true)
... 466 lines suppressed ...


-- 
asterisk-scf/integration/test_channel.git



More information about the asterisk-scf-commits mailing list