[asterisk-scf-commits] asterisk-scf/integration/media_operations_core.git branch "jitterbuffer" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Mon Nov 14 10:36:06 CST 2011
branch "jitterbuffer" has been updated
via d688cccf61498546f2419261e4578fe2967ab3e5 (commit)
via d1ff81b7848d19669b22630e37fbd4ac148b6505 (commit)
via 705d117af0087447f35b826feeb5110cdd056b6f (commit)
via 4a297faec4f2faf44088e56df614b07dfac8ae9f (commit)
via ef935f6bba16a10d058509b2914db614ac30ae38 (commit)
via 6e03e3a0e1c92bd3d3fc2e8ab0d6ee6bb06f9f20 (commit)
from 4bf05f7f12720a4bf19e4c50f3e6b56c4e5e86c5 (commit)
Summary of changes:
src/BufferedTranslator.cpp | 4 +-
src/BufferedTranslator.h | 2 +-
src/JitterBufferOperation.cpp | 99 ++++++++++++++++++++++++++++++++---------
src/NetEqWrapper.cpp | 17 +++++++-
src/NonBufferedTranslator.cpp | 3 +-
src/NonBufferedTranslator.h | 2 +-
src/Translator.cpp | 52 ---------------------
src/g722.cpp | 2 +-
src/resample.cpp | 2 +-
src/ulaw_alaw.cpp | 2 +-
test/TestMediaOperations.cpp | 56 +++++++++++++++--------
11 files changed, 139 insertions(+), 102 deletions(-)
delete mode 100644 src/Translator.cpp
- Log -----------------------------------------------------------------
commit d688cccf61498546f2419261e4578fe2967ab3e5
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Nov 14 10:34:15 2011 -0600
Incorporated review feedback.
diff --git a/src/BufferedTranslator.cpp b/src/BufferedTranslator.cpp
index 7abe85b..8600098 100644
--- a/src/BufferedTranslator.cpp
+++ b/src/BufferedTranslator.cpp
@@ -14,6 +14,8 @@
* at the top of the source tree.
*/
+#include <boost/bind.hpp>
+
#include "BufferedTranslator.h"
namespace AsteriskSCF
@@ -42,7 +44,7 @@ BufferedTranslator::~BufferedTranslator()
void BufferedTranslator::translateFrames(const FrameSeq& frames)
{
- std::for_each(frames.begin(), frames.end(), std::bind1st(std::mem_fun(&BufferedTranslator::buffer), this));
+ std::for_each(frames.begin(), frames.end(), boost::bind(&BufferedTranslator::buffer, this, _1));
}
}
diff --git a/src/BufferedTranslator.h b/src/BufferedTranslator.h
index 6056973..788d030 100644
--- a/src/BufferedTranslator.h
+++ b/src/BufferedTranslator.h
@@ -50,7 +50,7 @@ public:
* a check to be certain that the format of the frame
* being buffered is what is expected for this translator
*/
- virtual void buffer(const AsteriskSCF::Media::V1::FramePtr inFrame) = 0;
+ virtual void buffer(const AsteriskSCF::Media::V1::FramePtr& inFrame) = 0;
/**
* @Override
diff --git a/src/JitterBufferOperation.cpp b/src/JitterBufferOperation.cpp
index ff5721d..bd00938 100644
--- a/src/JitterBufferOperation.cpp
+++ b/src/JitterBufferOperation.cpp
@@ -44,6 +44,8 @@ namespace AsteriskSCF
namespace MediaOperationsCore
{
+const IceUtil::Time SEND_INTERVAL(IceUtil::Time::milliSeconds(10));
+
class JitterBufferOperation : public TranslatorOperation
{
private:
@@ -55,35 +57,43 @@ private:
const AudioFormatPtr& outFormat,
boost::shared_mutex& mutex,
int numPayloadsToGet,
- const NetEqWrapperPtr& netEqWrapper)
+ const NetEqWrapperPtr& netEqWrapper,
+ const IceUtil::TimerPtr& timer,
+ IceUtil::Time& scheduledTime)
: mSource(source),
mOutFormat(outFormat),
+ mSeqNumber(1),
mLock(mutex),
mNumPayloadsToGet(numPayloadsToGet),
- mNetEq(netEqWrapper)
+ mNetEq(netEqWrapper),
+ mTimer(timer),
+ mScheduledTime(scheduledTime)
{
}
- Ice::ShortSeq getNextPayload()
+ int getNextPayload(Ice::ShortSeq& payload)
{
- Ice::ShortSeq payload(NETEQ_MAX_FRAME_SIZE);
- WebRtc_Word16 samples;
-
+ WebRtc_Word16 length(0);
+ int webrtc_result(0);
{
boost::unique_lock<boost::shared_mutex> lock(mLock);
- WebRtcNetEQ_RecOut(mNetEq->getInstance(),
+ webrtc_result = WebRtcNetEQ_RecOut(mNetEq->getInstance(),
&payload.front(),
- &samples);
+ &length);
}
- // Remove any contents which were not populated
- payload.resize(samples);
+ if (webrtc_result == 0)
+ {
+ // Remove any contents which were not populated
+ payload.resize(length);
+ return length;
+ }
- return payload;
+ return 0;
}
- void runTimerTask()
+ void pushFrames()
{
FrameSeq frameSeq;
@@ -97,19 +107,49 @@ private:
frame->seqno = mSeqNumber++;
ShortSeqPayloadPtr payload = new ShortSeqPayload();
-
+ int payloadSize(0);
for (int i=0; i < mNumPayloadsToGet; ++i)
{
- Ice::ShortSeq nextPayload = getNextPayload();
+ Ice::ShortSeq nextPayload(NETEQ_MAX_FRAME_SIZE);
+ payloadSize = getNextPayload(nextPayload);
payload->payload.insert(payload->payload.end(), nextPayload.begin(), nextPayload.end());
}
- frame->payload = payload;
+ if (payloadSize != 0)
+ {
+ frame->payload = payload;
- frameSeq.push_back(frame);
+ frameSeq.push_back(frame);
- mSource->distributeToSinks(frameSeq);
+ mSource->distributeToSinks(frameSeq);
+ }
+ }
+
+ IceUtil::Time calculateRescheduleDelay()
+ {
+ // Scheduled time is always based on the previous planned time in order to avoid
+ // drift in the send rate.
+ mScheduledTime += SEND_INTERVAL;
+ IceUtil::Time now = IceUtil::Time::now();
+ return (SEND_INTERVAL - (now - mScheduledTime));
+ }
+
+ void runTimerTask()
+ {
+ pushFrames();
+ IceUtil::Time delay = calculateRescheduleDelay();
+
+ while (delay.milliSeconds < 0)
+ {
+ // If we get here, either our timer didn't fire soon enough or the processing time
+ // exceeded the delay interval (or both).
+ pushFrames();
+
+ delay = calculateRescheduleDelay();
+ }
+
+ mTimer->schedule(this, delay);
}
private:
@@ -119,6 +159,8 @@ private:
boost::shared_mutex &mLock;
int mNumPayloadsToGet;
NetEqWrapperPtr mNetEq;
+ IceUtil::TimerPtr mTimer;
+ IceUtil::Time mScheduledTime;
};
class JitterBuffer : public BufferedTranslator
@@ -147,7 +189,7 @@ private:
}
}
- void buffer(const FramePtr inFrame)
+ void buffer(const FramePtr& inFrame)
{
if (!TranslatorOperationFactory::formatsEqual(inFrame->mediaFormat, mInputFormat))
{
@@ -166,14 +208,20 @@ private:
rtpInfo.sequenceNumber = (WebRtc_UWord16)streamFrame->seqno;
rtpInfo.SSRC = mSsrc;
rtpInfo.timeStamp = (WebRtc_UWord32)streamFrame->timestamp;
- //rtpInfo.markerBit = // Assuming this one is safe to leave unset.
+ rtpInfo.markerBit = 0;
// WebRTC expects the payload to come straight from the network so we need to put it back in that state
ShortSeqPayloadPtr inPayload = ShortSeqPayloadPtr::dynamicCast(inFrame->payload);
+
+ if (inPayload == 0)
+ {
+ throw UnsupportedMediaFormatException();
+ }
+
std::transform(inPayload->payload.begin(), inPayload->payload.end(),
inPayload->payload.begin(), boost::asio::detail::socket_ops::host_to_network_short);
Ice::ByteSeq bytes((Ice::Byte*) &inPayload->payload.front(),
- (Ice::Byte*) &inPayload->payload[inPayload->payload.size()]);
+ (Ice::Byte*) (&inPayload->payload.back()+1));
{
boost::unique_lock<boost::shared_mutex> lock(mLock);
@@ -190,13 +238,20 @@ private:
{
mBufferSending = true;
+ //AsteriskSCF::Media::V1::StreamSinkSeq sinks = mSource->getSinks();
+
+ IceUtil::Time scheduledTime = IceUtil::Time::now() + SEND_INTERVAL;
+
// Start a timer to push buffered frames.
IceUtil::TimerTaskPtr sendTask = new JitterBufferSendTask(mSource,
mOutAudioFormat,
mLock,
1,
- mNetEq);
- mTimer->scheduleRepeated(sendTask, IceUtil::Time::milliSeconds(mOutAudioFormat->frameSize / (mOutAudioFormat->sampleRate / 1000)));
+ mNetEq,
+ mTimer,
+ scheduledTime);
+
+ mTimer->schedule(sendTask, SEND_INTERVAL);
}
}
diff --git a/src/NetEqWrapper.cpp b/src/NetEqWrapper.cpp
index 5ee5b93..4a7b12e 100644
--- a/src/NetEqWrapper.cpp
+++ b/src/NetEqWrapper.cpp
@@ -50,9 +50,10 @@ private:
NetEqWrapperImpl::NetEqWrapperImpl(int sampleRate, bool forFax)
{
int memSize;
- int resultCode;
+ int resultCode(0);
WebRtcNetEQDecoder defaultDecoder(kDecoderPCM16B);
+ std::string test = "WebRtcNetEQ returned error from WebRtcNetEQ_AssignSize: " + resultCode;
if((resultCode = WebRtcNetEQ_AssignSize(&memSize)) < 0)
{
throw NetEqInitException("WebRtcNetEQ returned error from WebRtcNetEQ_AssignSize: " + resultCode);
@@ -72,6 +73,8 @@ NetEqWrapperImpl::NetEqWrapperImpl(int sampleRate, bool forFax)
if((resultCode = WebRtcNetEQ_Init(mNetEqInstance, (WebRtc_Word16)sampleRate)) < 0)
{
+ delete instMemory;
+
std::string msg = "WebRtcNetEQ returned error initializing our instance: " + resultCode;
msg += (" with a sampleRate of " + sampleRate);
throw NetEqInitException(msg);
@@ -86,6 +89,8 @@ NetEqWrapperImpl::NetEqWrapperImpl(int sampleRate, bool forFax)
if((resultCode = WebRtcNetEQ_SetPlayoutMode(mNetEqInstance, playoutMode)) < 0)
{
+ delete instMemory;
+
throw NetEqInitException("WebRtcNetEQ returned error setting playout mode: " + resultCode);
}
@@ -101,17 +106,21 @@ NetEqWrapperImpl::NetEqWrapperImpl(int sampleRate, bool forFax)
&mNetEqBufferMaxPackets,
&mBufferSizeInBytes)) < 0)
{
+ delete instMemory;
throw NetEqInitException("WebRtcNetEQ error getting recommended buffer size: " + resultCode);
}
mNetEqPacketBuffer = new WebRtc_Word16[MAX_NETEQ_BUFFERSIZE>>1];
if (mNetEqPacketBuffer == 0)
{
+ delete instMemory;
throw NetEqInitException("Unable to allocate memory for NetEQ packet buffer.");
}
if((resultCode = WebRtcNetEQ_AssignBuffer(mNetEqInstance, mNetEqBufferMaxPackets, mNetEqPacketBuffer, mBufferSizeInBytes)) < 0)
{
+ delete instMemory;
+ delete mNetEqPacketBuffer;
throw NetEqInitException("WebRtcNetEQ returned error from WebRtcNetEQ_AssignBuffer: " + resultCode);
}
@@ -128,6 +137,12 @@ NetEqWrapperImpl::NetEqWrapperImpl(int sampleRate, bool forFax)
SET_CODEC_PAR(mCodecDef,kDecoderPCM16Bwb,NETEQ_CODEC_PCM16B_PT,NULL,(WebRtc_Word16)sampleRate);
SET_PCM16B_FUNCTIONS(mCodecDef);
}
+ else
+ {
+ delete instMemory;
+ delete mNetEqPacketBuffer;
+ throw NetEqInitException("Invalid sample rate for NetEQ instance.");
+ }
WebRtcNetEQ_CodecDbAdd(mNetEqInstance, &mCodecDef);
// Note: Not setting master/slave relations, since we currently don't have way to associate
diff --git a/src/NonBufferedTranslator.cpp b/src/NonBufferedTranslator.cpp
index 5803fe1..2e58542 100644
--- a/src/NonBufferedTranslator.cpp
+++ b/src/NonBufferedTranslator.cpp
@@ -13,6 +13,7 @@
* the GNU General Public License Version 2. See the LICENSE.txt file
* at the top of the source tree.
*/
+#include <boost/bind.hpp>
#include "NonBufferedTranslator.h"
@@ -44,7 +45,7 @@ void NonBufferedTranslator::translateFrames(const FrameSeq& frames)
{
FrameSeq translated;
translated.resize(frames.size());
- std::transform(frames.begin(), frames.end(), translated.begin(), std::bind1st(std::mem_fun(&NonBufferedTranslator::translate), this));
+ std::for_each(frames.begin(), frames.end(), boost::bind(&NonBufferedTranslator::translate, this, _1));
mSource->distributeToSinks(translated);
}
diff --git a/src/NonBufferedTranslator.h b/src/NonBufferedTranslator.h
index 97b85a0..c07d8e6 100644
--- a/src/NonBufferedTranslator.h
+++ b/src/NonBufferedTranslator.h
@@ -51,7 +51,7 @@ public:
* a check to be certain that the format of the frame
* being translated is what is expected for this translator
*/
- virtual AsteriskSCF::Media::V1::FramePtr translate(const AsteriskSCF::Media::V1::FramePtr inFrame) = 0;
+ virtual AsteriskSCF::Media::V1::FramePtr translate(const AsteriskSCF::Media::V1::FramePtr& inFrame) = 0;
/**
* @Override
diff --git a/src/g722.cpp b/src/g722.cpp
index 0135f03..49376b2 100644
--- a/src/g722.cpp
+++ b/src/g722.cpp
@@ -111,7 +111,7 @@ private:
return new Frame(outFormat, outPayload);
}
- FramePtr translate(const FramePtr inFrame)
+ FramePtr translate(const FramePtr& inFrame)
{
if (!TranslatorOperationFactory::formatsEqual(inFrame->mediaFormat, mInputFormat))
{
diff --git a/src/resample.cpp b/src/resample.cpp
index 1571e3b..ed2e43e 100644
--- a/src/resample.cpp
+++ b/src/resample.cpp
@@ -69,7 +69,7 @@ private:
}
}
- FramePtr translate(const FramePtr inFrame)
+ FramePtr translate(const FramePtr& inFrame)
{
//
// Lazy initialization to avoid issues with when the pjlib thread hook is installed.
diff --git a/src/ulaw_alaw.cpp b/src/ulaw_alaw.cpp
index 135c7e9..07213eb 100644
--- a/src/ulaw_alaw.cpp
+++ b/src/ulaw_alaw.cpp
@@ -64,7 +64,7 @@ private:
/**
* Override of Translator's translate function.
*/
- FramePtr translate(const FramePtr inFrame)
+ FramePtr translate(const FramePtr& inFrame)
{
if (inFrame->mediaFormat->name != mInputFormat->name)
{
diff --git a/test/TestMediaOperations.cpp b/test/TestMediaOperations.cpp
index 5d90059..6cb66b7 100644
--- a/test/TestMediaOperations.cpp
+++ b/test/TestMediaOperations.cpp
@@ -1042,48 +1042,64 @@ BOOST_FIXTURE_TEST_CASE(createJitterBufferOperations, PerTestFixture)
}
}
-BOOST_FIXTURE_TEST_CASE(dejitterSlin8, PerTestFixture)
+BOOST_FIXTURE_TEST_CASE(dejitterSlin16, PerTestFixture)
{
- size_t numFramesToDejitter = 10;
+ Testbed.slin16->frameSize = (Ice::Int) Testbed.sampleSlin16FrameSize;
+ Testbed.slin16nojitter->frameSize = (Ice::Int) Testbed.sampleSlin16FrameSize;
- Testbed.slin8->frameSize = (Ice::Int) Testbed.sampleSlin8FrameSize;
- Testbed.slin8nojitter->frameSize = (Ice::Int) Testbed.sampleSlin8FrameSize;
+ MediaOperationServiceLocatorParamsPtr slin16NoJitterParams = createLocatorParams(Testbed.slin16, Testbed.slin16nojitter);
- MediaOperationServiceLocatorParamsPtr slin8NoJitterParams = createLocatorParams(Testbed.slin8, Testbed.slin8nojitter);
+ MediaOperationFactoryPrx slin16NoJitterFactory =
+ MediaOperationFactoryPrx::checkedCast(Testbed.locator->locate(slin16NoJitterParams));
- MediaOperationFactoryPrx slin8NoJitterFactory =
- MediaOperationFactoryPrx::checkedCast(Testbed.locator->locate(slin8NoJitterParams));
+ MediaOperationPrx slin16NoJitterTranslator =
+ slin16NoJitterFactory->createMediaOperation(Testbed.slin16SourceProxy, Testbed.slin16NoJitterSinkProxy);
- MediaOperationPrx slin8NoJitterTranslator =
- slin8NoJitterFactory->createMediaOperation(Testbed.slin8SourceProxy, Testbed.slin8NoJitterSinkProxy);
+ StreamSinkPrx translatorSink = slin16NoJitterTranslator->getSink();
+ StreamSourcePrx translatorSource = slin16NoJitterTranslator->getSource();
- StreamSinkPrx translatorSink = slin8NoJitterTranslator->getSink();
- StreamSourcePrx translatorSource = slin8NoJitterTranslator->getSource();
+ Testbed.slin16SourceProxy->addSink(translatorSink);
+ Testbed.slin16NoJitterSinkProxy->setSource(translatorSource);
- Testbed.slin8SourceProxy->addSink(translatorSink);
- Testbed.slin8NoJitterSinkProxy->setSource(translatorSource);
+ translatorSource->addSink(Testbed.slin16NoJitterSinkProxy);
+ translatorSink->setSource(Testbed.slin16SourceProxy);
- translatorSource->addSink(Testbed.slin8NoJitterSinkProxy);
- translatorSink->setSource(Testbed.slin8SourceProxy);
+ // Create something to dejitter.
+ size_t numFramesToDejitter = 10;
+ int sequenceNumbers[] = {3, 2, 1, 6, 4, 5, 8, 7, 10, 9};
+
+ FrameSeq slin16Frames(numFramesToDejitter, Testbed.sampleSlin16Frame);
- FrameSeq slin8Frames(numFramesToDejitter, Testbed.sampleSlin8Frame);
+ int i(0);
+ for (FrameSeq::iterator iter = slin16Frames.begin();
+ iter != slin16Frames.end(); ++iter)
+ {
+ AudioFramePtr audioFrame = AudioFramePtr::dynamicCast(*iter);
+ audioFrame->seqno = sequenceNumbers[i];
+ ShortSeqPayloadPtr payload = ShortSeqPayloadPtr::dynamicCast(audioFrame->payload);
+
+ // For testing, we're shoving the sequence number into the first sample of the payload.
+ // Sneaky.
+ payload->payload[0] = (short)audioFrame->seqno;
+ ++i;
+ }
try
{
- Testbed.slin8Source->feedFramesToTranslator(slin8Frames);
+ Testbed.slin16Source->feedFramesToTranslator(slin16Frames);
}
catch (const Ice::Exception& ex)
{
std::stringstream str;
- str << "Exception caught trying to dejitter slin8 frames: " << ex.what();
+ str << "Exception caught trying to dejitter slin16 frames: " << ex.what();
BOOST_FAIL(str.str());
}
IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(5));
- FrameSeq framesWritten = Testbed.slin8NoJitterSink->getFrames();
+ FrameSeq framesWritten = Testbed.slin16NoJitterSink->getFrames();
BOOST_CHECK(framesWritten.size() == numFramesToDejitter);
- slin8NoJitterTranslator->destroy();
+ slin16NoJitterTranslator->destroy();
}
commit d1ff81b7848d19669b22630e37fbd4ac148b6505
Merge: 705d117 4bf05f7
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Oct 17 14:50:44 2011 -0500
Merge branch 'jitterbuffer' of git.asterisk.org:asterisk-scf/integration/media_operations_core into jitterbuffer
commit 705d117af0087447f35b826feeb5110cdd056b6f
Merge: 4a297fa 6905d72
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Oct 17 13:49:07 2011 -0500
Merge branch 'jitterbuffer' of git.asterisk.org:asterisk-scf/integration/media_operations_core into jitterbuffer
commit 4a297faec4f2faf44088e56df614b07dfac8ae9f
Merge: ef935f6 9ba0da0
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Oct 17 12:46:22 2011 -0500
Merge branch 'jitterbuffer' of git.asterisk.org:asterisk-scf/integration/media_operations_core into jitterbuffer
commit ef935f6bba16a10d058509b2914db614ac30ae38
Merge: 6e03e3a dbf8e0b
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Oct 17 10:56:13 2011 -0500
Merge branch 'jitterbuffer' of git.asterisk.org:asterisk-scf/integration/media_operations_core into jitterbuffer
commit 6e03e3a0e1c92bd3d3fc2e8ab0d6ee6bb06f9f20
Author: Ken Hunt <ken.hunt at digium.com>
Date: Mon Oct 17 10:38:42 2011 -0500
Removed Translator.cpp file.
diff --git a/src/Translator.cpp b/src/Translator.cpp
deleted file mode 100644
index 3e12631..0000000
--- a/src/Translator.cpp
+++ /dev/null
@@ -1,52 +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.
- */
-
-#include "Translator.h"
-
-namespace AsteriskSCF
-{
-
-namespace MediaOperationsCore
-{
-
-using namespace AsteriskSCF::Media::V1;
-using namespace AsteriskSCF::System::Logging;
-
-Translator::Translator(const TranslatorSourcePtr& source,
- const FormatPtr& inputFormat,
- const FormatPtr& outputFormat,
- const Logger& logger)
- : mSource(source),
- mInputFormat(inputFormat),
- mOutputFormat(outputFormat),
- mLogger(logger)
-{
-}
-
-Translator::~Translator()
-{
-}
-
-void Translator::translateFrames(const FrameSeq& frames)
-{
- FrameSeq translated;
- translated.resize(frames.size());
- std::transform(frames.begin(), frames.end(), translated.begin(), std::bind1st(std::mem_fun(&Translator::translate), this));
- mSource->distributeToSinks(translated);
-}
-
-}
-}
-----------------------------------------------------------------------
--
asterisk-scf/integration/media_operations_core.git
More information about the asterisk-scf-commits
mailing list