[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