[asterisk-scf-commits] asterisk-scf/integration/media_rtp_pjmedia.git branch "telephony-events2" updated.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Mon Aug 8 17:06:56 CDT 2011
branch "telephony-events2" has been updated
via cd50386c941baa0c1661ccfefaeb3ef1dd51a291 (commit)
via 68e7ebfd67f8a6f899011f6c07297e284a4a19dd (commit)
via 018c66abb6b5a4dec2f4d4ff64f7cb3d87055ad8 (commit)
from bebb64eeace7496c0da09b238f293ae35b296d36 (commit)
Summary of changes:
src/RTPSource.cpp | 7 ++
src/RTPTelephonyEventSink.cpp | 18 ++++-
src/RTPTelephonyEventSource.cpp | 159 ++++++++++++++++++++++++++++++++++++++-
src/RTPTelephonyEventSource.h | 40 ++++++++++
4 files changed, 220 insertions(+), 4 deletions(-)
- Log -----------------------------------------------------------------
commit cd50386c941baa0c1661ccfefaeb3ef1dd51a291
Author: Mark Michelson <mmichelson at digium.com>
Date: Mon Aug 8 17:01:30 2011 -0500
A day's worth of changes.
Parsing events more completely, distributing to sinks, etc. is now
done.
diff --git a/src/RTPSource.cpp b/src/RTPSource.cpp
index ca1346b..e3fc845 100644
--- a/src/RTPSource.cpp
+++ b/src/RTPSource.cpp
@@ -421,7 +421,7 @@ static void receiveRTP(void *userdata, void *packet, pj_ssize_t size)
}
else if ((rfc4733 = RFC4733Ptr::dynamicCast(mediaformat)))
{
- source->mImpl->mTelephonyEventSource->read(payload);
+ source->mImpl->mTelephonyEventSource->read(header, payload);
}
if (frames.empty())
diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index c15f4f9..7246e52 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -20,9 +20,25 @@ using namespace AsteriskSCF::SessionCommunications::V1;
void RTPTelephonyEventSink::write_async(
const AMD_TelephonyEventSink_writePtr& cb,
- const TelephonyEventPtr&,
+ const TelephonyEventPtr& event,
const Ice::Current&)
{
+ BeginDTMFEventPtr beginDTMF;
+ EndDTMFEventPtr endDTMF;
+ ContinueDTMFEventPtr continueDTMF;
+ FlashEventPtr flash;
+ if ((beginDTMF = BeginDTMFEventPtr::dynamicCast(event)))
+ {
+ }
+ else if (endDTMF = EndDTMFEventPtr::dynamicCast(event))
+ {
+ }
+ else if (continueDTMF = ContinueDTMFEventPtr::dynamicCast(event))
+ {
+ }
+ else if (flash = FlashEventPtr::dynamicCast(event))
+ {
+ }
cb->ice_response();
}
diff --git a/src/RTPTelephonyEventSource.cpp b/src/RTPTelephonyEventSource.cpp
index 30563c6..478db39 100644
--- a/src/RTPTelephonyEventSource.cpp
+++ b/src/RTPTelephonyEventSource.cpp
@@ -27,7 +27,7 @@ Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
}
RTPTelephonyEventSource::RTPTelephonyEventSource(pjmedia_rtp_session *session)
- : mSession(session)
+ : mSession(session), mOnEnd(false), mCachedEvent(255), mLastSeqno(0), mEventDuration(0)
{
}
@@ -37,9 +37,14 @@ RTPTelephonyEventSource::~RTPTelephonyEventSource()
void RTPTelephonyEventSource::addSink_async(
const AMD_TelephonyEventSource_addSinkPtr& cb,
- const TelephonyEventSinkPrx&,
+ const TelephonyEventSinkPrx& sink,
const Ice::Current&)
{
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ if (std::find(mSinks.begin(), mSinks.end(), sink) == mSinks.end())
+ {
+ mSinks.push_back(sink);
+ }
cb->ice_response();
}
@@ -47,7 +52,8 @@ void RTPTelephonyEventSource::getSinks_async(
const AMD_TelephonyEventSource_getSinksPtr& cb,
const Ice::Current&)
{
- cb->ice_response(TelephonyEventSinkSeq());
+ boost::shared_lock<boost::shared_mutex> lock(mLock);
+ cb->ice_response(mSinks);
}
TelephonyEventSourcePrx RTPTelephonyEventSource::getProxy()
@@ -55,20 +61,141 @@ TelephonyEventSourcePrx RTPTelephonyEventSource::getProxy()
return mProxy;
}
-void RTPTelephonyEventSource::read(const Ice::Byte* payload)
+void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr *header, const Ice::Byte* payload)
{
- pjmedia_rtp_dtmf_event* dtmf = (pjmedia_rtp_dtmf_event *) payload;
+ if (header->seq < mLastSeqno && mLastSeqno - header->seq < 50)
+ {
+ //Out of order packet. Don't process it.
+ return;
+ }
+ mLastSeqno = header->seq;
+
+ //Even though this structure has "dtmf" in its name, it is used for
+ //other RFC 4733 events, since they all have the same payload
+ //structure.
+ pjmedia_rtp_dtmf_event* event = (pjmedia_rtp_dtmf_event *) payload;
// For now, we can just do some sanity checks to be sure that
// what we're reading is what we expect to see.
lg(Debug) << "RFC 4733 DTMF received.";
- lg(Debug) << "The event is " << (int) dtmf->event;
- lg(Debug) << "The volume is " << (int) (dtmf->e_vol & ~0x80);
- lg(Debug) << "The duration is " << pj_ntohs(dtmf->duration);
- lg(Debug) << "This is " << (dtmf->e_vol & 0x80 ? "" : "not ") << "an end";
-
- //We need to cache the last DTMF we read, whether it was
- //a begin or end, and the sequence number of the RTP packet.
- //
- //If this DTMF is an end then we can clear the cache of the last
- //DTMF we read.
+ lg(Debug) << "The event is " << (int) event->event;
+ lg(Debug) << "The volume is " << (int) (event->e_vol & 0x7F);
+ lg(Debug) << "The duration is " << pj_ntohs(event->duration);
+ lg(Debug) << "This is " << (event->e_vol & 0x80 ? "" : "not ") << "an end";
+
+ bool isEnd = (event->e_vol & 0x80);
+ //We'll typically get three end frames. We don't need to send
+ //multiple end events though, which is why we check to see if
+ //we already are processing end frames.
+ if (isEnd && !mOnEnd)
+ {
+ sendEndEvent(event);
+ mOnEnd = true;
+ mEventDuration = 0;
+ }
+ else if (!isEnd)
+ {
+ //Either beginning or continuing.
+
+ //If we just processed an end, then it's clearly beginning
+ //a new event. Alternatively, we could have missed the end
+ //of the last event due to bad network conditions and now
+ //are getting the beginning of a new event.
+ if (mOnEnd || mCachedEvent != event->event)
+ {
+ sendBeginEvent(event);
+ mOnEnd = false;
+ mCachedEvent = event->event;
+ //Duration is expressed in timestamp units, i.e. samples.
+ //Since we want to express duration in milliseconds, we multiply
+ //by the number of milliseconds in a second and divide by the
+ //number of samples per second.
+ //
+ //XXX Is it safe to hardcode 8000 here?
+ //XXX Need to account for when duration rolls over (events greater than ~8 secs)
+ mEventDuration = (pj_ntohs(event->duration) * 1000) / 8000;
+ }
+ sendContinuationEvent(event);
+ }
+ //The implied else here is an end that we already know about. No
+ //need to take further action.
+}
+
+void RTPTelephonyEventSource::sendBeginEvent(const pjmedia_rtp_dtmf_event *event)
+{
+ //DTMF
+ if (event->event <= 15)
+ {
+ BeginDTMFEventPtr dtmf(new BeginDTMFEvent);
+ dtmf->signal = translateDTMF(event->event);
+ distributeToSinks(dtmf);
+ }
+}
+
+void RTPTelephonyEventSource::sendContinuationEvent(const pjmedia_rtp_dtmf_event *event)
+{
+ //DTMF
+ if (event->event <= 15)
+ {
+ ContinueDTMFEventPtr dtmf(new ContinueDTMFEvent);
+ dtmf->signal = translateDTMF(event->event);
+ dtmf->duration = mEventDuration;
+ distributeToSinks(dtmf);
+ }
+}
+
+void RTPTelephonyEventSource::sendEndEvent(const pjmedia_rtp_dtmf_event *event)
+{
+ //DTMF
+ if (event->event <= 15)
+ {
+ EndDTMFEventPtr dtmf(new EndDTMFEvent);
+ dtmf->signal = translateDTMF(event->event);
+ dtmf->duration = mEventDuration;
+ distributeToSinks(dtmf);
+ }
+ //Flash
+ else if (event->event == 16)
+ {
+ FlashEventPtr flash(new FlashEvent);
+ distributeToSinks(flash);
+ }
+}
+
+void RTPTelephonyEventSource::distributeToSinks(const TelephonyEventPtr& event)
+{
+ boost::unique_lock<boost::shared_mutex> lock(mLock);
+ for (TelephonyEventSinkSeq::iterator iter = mSinks.begin();
+ iter != mSinks.end(); ++iter)
+ {
+ try
+ {
+ (*iter)->write(event);
+ }
+ catch (const Ice::Exception&)
+ {
+ lg(Error) << "Error while trying to write telephony event to a sink";
+ }
+ }
+}
+
+// This function does no bounds checking and assumes that whoever
+// calls it will not call into it with invalid input (i.e. event > 15)
+Ice::Byte RTPTelephonyEventSource::translateDTMF(pj_uint8_t event)
+{
+ if (event < 10)
+ {
+ return (Ice::Byte) (event + '0');
+ }
+ else if (event == 10)
+ {
+ return '*';
+ }
+ else if (event == 11)
+ {
+ return '#';
+ }
+ else
+ {
+ return (Ice::Byte) ((event - 12) + 'A');
+ }
}
diff --git a/src/RTPTelephonyEventSource.h b/src/RTPTelephonyEventSource.h
index f95e0bb..4878b57 100644
--- a/src/RTPTelephonyEventSource.h
+++ b/src/RTPTelephonyEventSource.h
@@ -16,6 +16,8 @@
#pragma once
+#include <boost/thread.hpp>
+
#include <AsteriskSCF/SessionCommunications/TelephonyEventsIf.h>
#include "pjmedia.h"
@@ -36,14 +38,50 @@ public:
AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx getProxy();
- void read(const Ice::Byte* payload);
+ void read(const pjmedia_rtp_hdr *hdr, const Ice::Byte* payload);
protected:
~RTPTelephonyEventSource();
private:
+ void sendBeginEvent(const pjmedia_rtp_dtmf_event *event);
+ void sendContinuationEvent(const pjmedia_rtp_dtmf_event *event);
+ void sendEndEvent(const pjmedia_rtp_dtmf_event *event);
+ void distributeToSinks(const AsteriskSCF::SessionCommunications::V1::TelephonyEventPtr& event);
+ Ice::Byte translateDTMF(pj_uint8_t event);
+
pjmedia_rtp_session *mSession;
AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx mProxy;
+
+ /**
+ * True if the last packet we processed was an event end. Since 3 ends
+ * are typically expected, we need to cache whether we've already seen
+ * one so that we don't end up sending multiple end events to the sinks.
+ */
+ bool mOnEnd;
+ /**
+ * Keep track of the last event we received. This way if we miss the end
+ * of an event, we can see if the new incoming event is actually a
+ * continuation of the previous event or if it is actually a new event.
+ */
+ pj_uint8_t mCachedEvent;
+ /**
+ * We keep track of the sequence number of the previous event we received
+ * so we can detect out of order frames. If we do not ensure the integrity
+ * of the sequence number, it is possible under odd circumstances to
+ * improperly report duplicate events.
+ */
+ pj_uint16_t mLastSeqno;
+ /**
+ * The duration of the event in milliseconds. We use the duration field
+ * of the event to keep a running total of the duration of the event.
+ */
+ pj_uint32_t mEventDuration;
+ /**
+ * Sinks to send events to
+ */
+ AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkSeq mSinks;
+ boost::shared_mutex mLock;
};
typedef IceUtil::Handle<RTPTelephonyEventSource> RTPTelephonyEventSourcePtr;
commit 68e7ebfd67f8a6f899011f6c07297e284a4a19dd
Author: Mark Michelson <mmichelson at digium.com>
Date: Fri Aug 5 16:39:04 2011 -0500
Log the RFC 4733 DTMF digits we're reading.
It works, btw :)
diff --git a/src/RTPTelephonyEventSource.cpp b/src/RTPTelephonyEventSource.cpp
index 56a6445..30563c6 100644
--- a/src/RTPTelephonyEventSource.cpp
+++ b/src/RTPTelephonyEventSource.cpp
@@ -15,8 +15,16 @@
*/
#include "RTPTelephonyEventSource.h"
+#include <AsteriskSCF/logger.h>
+#include <pjmedia.h>
using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::System::Logging;
+
+namespace
+{
+Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
+}
RTPTelephonyEventSource::RTPTelephonyEventSource(pjmedia_rtp_session *session)
: mSession(session)
@@ -47,7 +55,20 @@ TelephonyEventSourcePrx RTPTelephonyEventSource::getProxy()
return mProxy;
}
-void RTPTelephonyEventSource::read(const Ice::Byte*)
+void RTPTelephonyEventSource::read(const Ice::Byte* payload)
{
- //stub;
+ pjmedia_rtp_dtmf_event* dtmf = (pjmedia_rtp_dtmf_event *) payload;
+ // For now, we can just do some sanity checks to be sure that
+ // what we're reading is what we expect to see.
+ lg(Debug) << "RFC 4733 DTMF received.";
+ lg(Debug) << "The event is " << (int) dtmf->event;
+ lg(Debug) << "The volume is " << (int) (dtmf->e_vol & ~0x80);
+ lg(Debug) << "The duration is " << pj_ntohs(dtmf->duration);
+ lg(Debug) << "This is " << (dtmf->e_vol & 0x80 ? "" : "not ") << "an end";
+
+ //We need to cache the last DTMF we read, whether it was
+ //a begin or end, and the sequence number of the RTP packet.
+ //
+ //If this DTMF is an end then we can clear the cache of the last
+ //DTMF we read.
}
commit 018c66abb6b5a4dec2f4d4ff64f7cb3d87055ad8
Author: Mark Michelson <mmichelson at digium.com>
Date: Fri Aug 5 09:30:12 2011 -0500
Check for RFC 4733 event and send to the RTP telephony event source if so.
diff --git a/src/RTPSource.cpp b/src/RTPSource.cpp
index 7f31dea..ca1346b 100644
--- a/src/RTPSource.cpp
+++ b/src/RTPSource.cpp
@@ -30,6 +30,7 @@
#include <AsteriskSCF/Media/MediaIf.h>
#include <AsteriskSCF/Media/RTP/MediaRTPIf.h>
#include <AsteriskSCF/Media/RTP/MediaRTCPIf.h>
+#include <AsteriskSCF/Media/Formats/OtherFormats.h>
#include <AsteriskSCF/logger.h>
#include <AsteriskSCF/System/Component/ReplicaIf.h>
@@ -41,6 +42,7 @@ using namespace AsteriskSCF::Media::RTP::V1;
using namespace AsteriskSCF::Replication::MediaRTPPJMedia::V1;
using namespace AsteriskSCF::System::Logging;
using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::Media::Formats::Other::V1;
namespace
{
@@ -391,6 +393,7 @@ static void receiveRTP(void *userdata, void *packet, pj_ssize_t size)
AudioFormatPtr audioformat;
VideoFormatPtr videoformat;
+ RFC4733Ptr rfc4733;
if ((audioformat = AudioFormatPtr::dynamicCast(mediaformat)))
{
@@ -416,6 +419,10 @@ static void receiveRTP(void *userdata, void *packet, pj_ssize_t size)
copy(payload, payload + payload_size, std::back_inserter(frame->payload));
frames.push_back(frame);
}
+ else if ((rfc4733 = RFC4733Ptr::dynamicCast(mediaformat)))
+ {
+ source->mImpl->mTelephonyEventSource->read(payload);
+ }
if (frames.empty())
{
diff --git a/src/RTPTelephonyEventSource.cpp b/src/RTPTelephonyEventSource.cpp
index 7b1d40c..56a6445 100644
--- a/src/RTPTelephonyEventSource.cpp
+++ b/src/RTPTelephonyEventSource.cpp
@@ -46,3 +46,8 @@ TelephonyEventSourcePrx RTPTelephonyEventSource::getProxy()
{
return mProxy;
}
+
+void RTPTelephonyEventSource::read(const Ice::Byte*)
+{
+ //stub;
+}
diff --git a/src/RTPTelephonyEventSource.h b/src/RTPTelephonyEventSource.h
index 67a7ed1..f95e0bb 100644
--- a/src/RTPTelephonyEventSource.h
+++ b/src/RTPTelephonyEventSource.h
@@ -36,6 +36,8 @@ public:
AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx getProxy();
+ void read(const Ice::Byte* payload);
+
protected:
~RTPTelephonyEventSource();
-----------------------------------------------------------------------
--
asterisk-scf/integration/media_rtp_pjmedia.git
More information about the asterisk-scf-commits
mailing list