[asterisk-scf-commits] team/beagles/fileplayback.git branch "master" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Fri Dec 17 15:42:22 UTC 2010


branch "master" has been updated
       via  97bed80cfe044d93986b39db6112e7ea4e1fd4f6 (commit)
      from  4aac66d00621005c7c2e6aeb7111c44e8c942359 (commit)

Summary of changes:
 src/CMakeLists.txt                  |    6 ++
 src/FilePlaybackSessionEndpoint.cpp |  146 +++++++++++++++++++++++++++++++---
 src/MediaEchoThread.cpp             |   10 ++-
 3 files changed, 146 insertions(+), 16 deletions(-)


- Log -----------------------------------------------------------------
commit 97bed80cfe044d93986b39db6112e7ea4e1fd4f6
Author: Brent Eagles <beagles at digium.com>
Date:   Fri Dec 17 12:10:46 2010 -0330

    Add pjmedia wav file handling and fixup audio format to use file values.
    Fixed pacing in media echo thread.

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a4bbbe5..281b69e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,6 +21,7 @@ asterisk_scf_component_add_ice_libraries(test_channel IceStorm)
 asterisk_scf_component_add_boost_libraries(test_channel thread)
 asterisk_scf_component_add_boost_libraries(test_channel date_time)
 asterisk_scf_component_add_boost_libraries(test_channel filesystem)
+asterisk_scf_component_add_boost_libraries(test_channel core thread)
 if(NOT logger_dir)
    message(FATAL_ERROR "The logger directory could not be found ${logger_dir}")
 endif()
@@ -28,6 +29,10 @@ include_directories(${logger_dir}/common)
 include_directories(${logger_dir}/client/src)
 asterisk_scf_component_build_icebox(test_channel)
 target_link_libraries(test_channel logging-client)
+pjproject_link(test_channel pjlib)
+pjproject_link(test_channel pjlib-util)
+pjproject_link(test_channel pjmedia)
+pjproject_link(test_channel pjnath)
 
 asterisk_scf_component_init(console_driver CXX)
 asterisk_scf_component_add_slice(console_driver CommandsIf)
@@ -36,3 +41,4 @@ asterisk_scf_component_add_file(console_driver ConsoleDriver.h)
 asterisk_scf_component_add_file(console_driver main.cpp)
 asterisk_scf_component_build_standalone(console_driver)
 
+
diff --git a/src/FilePlaybackSessionEndpoint.cpp b/src/FilePlaybackSessionEndpoint.cpp
index 023317b..56f5c82 100644
--- a/src/FilePlaybackSessionEndpoint.cpp
+++ b/src/FilePlaybackSessionEndpoint.cpp
@@ -24,6 +24,7 @@
 #include <RemoteControl.h>
 #include <IceUtil/Mutex.h>
 #include <IceUtil/Handle.h>
+#include <pjmedia.h>
 
 #include <fstream>
 #include <memory>
@@ -35,8 +36,6 @@
 //   kind of thing.
 // * finish implementing the "record" functionality provided by the sink.
 // * incorporate matroska catalogue file
-//   * this is probably going to require libsox to create temporary files since Matroska doesn't 
-//     really support ulaw, alaw, etc. This probably isn't that big of a deal.
 //   * 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.
@@ -271,20 +270,143 @@ public:
         bool done = false;
 
         std::ifstream input(filename, std::ios::binary | std::ios::in);
-        mLogger(Debug) << __FILE__ << ':' << __LINE__ << ' ' << __FUNCTION__ << 
-            " file opened successfully " << filename;
+        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;
+            }
+        }
 
         //
-        // These values aren't the greatest, they are just hacked in there
-        // to make sure that the pacing works right.
+        // 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);
+        }
+
         //
-        const size_t bufSize = 20;
+        // 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::unique_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);
+            input.get(buf.get(), bufSize +1);
             size_t bytesRead = input.gcount();
 
             if(bytesRead == 0)
@@ -296,10 +418,10 @@ public:
             // 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 = mCurrentFormat;
+            frame->mediaformat = mediaFormat;
             frame->seqno = sequence++;
-            frame->timestamp = bytesRead * frame->seqno;
-            frame->payload.assign(buf.get(), buf.get()+bufSize);
+            frame->timestamp = samplesPerFrame;
+            frame->payload.assign(buf.get(), buf.get()+bytesRead);
             frames.push_back(frame);
         }
         mThread->pushFrames(frames);
@@ -596,8 +718,6 @@ public:
             mSourceControlPrx->destroy();
             mAdapter->remove(mSinkPrx->ice_getIdentity());
             mAdapter->remove(mSourcePrx->ice_getIdentity());
-            mAdapter->remove(mSinkControlPrx->ice_getIdentity());
-            mAdapter->remove(mSourceControlPrx->ice_getIdentity());
         }
         catch(const Ice::Exception& ex)
         {
diff --git a/src/MediaEchoThread.cpp b/src/MediaEchoThread.cpp
index 2a5f9d5..dcd2ee7 100644
--- a/src/MediaEchoThread.cpp
+++ b/src/MediaEchoThread.cpp
@@ -20,7 +20,7 @@ using namespace AsteriskSCF::TestUtil;
 MediaEchoThread::MediaEchoThread():
     mDone(false),
     mPaused(true),
-    mInterval(IceUtil::Time::microSecondsDouble(1000000.0 / (8 * 1024)))
+    mInterval(IceUtil::Time::microSecondsDouble(1000000.0 / (8 * 1000)))
 {
 }
 
@@ -79,12 +79,16 @@ void MediaEchoThread::run()
             AsteriskSCF::Media::V1::FrameSeq buf(current, current+1);
             try
             {
+                AsteriskSCF::Media::V1::AudioFormatPtr format =
+                    AsteriskSCF::Media::V1::AudioFormatPtr::dynamicCast((*current)->mediaformat);
+                assert(format);
                 sink->write(buf);
-
                 //
                 // Waiting for the configured interval creates the proper frame "rate".
                 //
-                IceUtil::ThreadControl::sleep(mInterval);
+                
+                IceUtil::Time interval(IceUtil::Time::milliSeconds(format->frameSize));
+                IceUtil::ThreadControl::sleep(interval);
             }
             catch(const Ice::Exception&)
             {

-----------------------------------------------------------------------


-- 
team/beagles/fileplayback.git



More information about the asterisk-scf-commits mailing list