[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