[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
Wed Aug 10 17:46:44 CDT 2011


branch "telephony-events2" has been updated
       via  aa81de303e27c5afb5d1d136581ead995c23d0ed (commit)
       via  5a88bcca5f0505c3f4176631315c327efe91ba11 (commit)
       via  f367da4739906648c80c678121756047a97213e8 (commit)
       via  432e98a60d5da408de623badd3cbbdd1b2d9974c (commit)
       via  27b6f831e45fcac62c47bc0a8e6346bceb41312f (commit)
       via  0950e6d32f6bdb665ad54090a324a5f93ace1b3b (commit)
      from  51a1d11783701bff96ba621e275824e0aae6454c (commit)

Summary of changes:
 .../MediaRTPPJMedia/RtpStateReplicationIf.ice      |   48 +++++++++++
 src/RTPSession.cpp                                 |   72 ++++++++++++++--
 src/RTPSink.cpp                                    |   14 +++
 src/RTPSink.h                                      |    5 +-
 src/RTPSource.cpp                                  |   16 ++++-
 src/RTPSource.h                                    |    5 +-
 src/RTPTelephonyEventSink.cpp                      |   86 ++++++++++++++++----
 src/RTPTelephonyEventSink.h                        |   25 ++++++-
 src/RTPTelephonyEventSource.cpp                    |   59 ++++++++++----
 src/RTPTelephonyEventSource.h                      |   64 +++++++++++----
 src/ReplicationAdapter.h                           |    2 +
 src/RtpStateReplicatorListener.cpp                 |   21 +++++
 src/SessionAdapter.h                               |    2 +
 13 files changed, 354 insertions(+), 65 deletions(-)


- Log -----------------------------------------------------------------
commit aa81de303e27c5afb5d1d136581ead995c23d0ed
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 17:47:32 2011 -0500

    Add returns in places where pjmedia library calls have failed.

diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index 2974fd3..e2108c3 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -140,7 +140,7 @@ void RTPTelephonyEventSink::write_async(
 
     if (status != PJ_SUCCESS)
     {
-        //fffffffuuuuuuuuuuuu
+        return;
     }
 
     char packet[1500];
@@ -152,7 +152,7 @@ void RTPTelephonyEventSink::write_async(
 
     if (status != PJ_SUCCESS)
     {
-        //fffffffuuuuuuuuuuuu
+        return;
     }
 
     if (replicationNeeded)

commit 5a88bcca5f0505c3f4176631315c327efe91ba11
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 17:38:53 2011 -0500

    Add documentation.

diff --git a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
index c0783d0..0ddeee5 100644
--- a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
@@ -109,14 +109,49 @@ module V1
 
     class RTPTelephonyEventSinkStateItem extends RtpStateItem
     {
+        /**
+         * RFC 4733 events' duration field is only 16-bits, and the
+         * duration is measured in timestamp units. This means that for
+         * 8000 Hz streams, the duration field is only capable of
+         * representing a duration of ~8 seconds.
+         * 
+         * RFC 4733's answer to this is to separate the event into "segments."
+         * When the duration exceeds 0xFFFF, then a packet is sent with duration
+         * 0xFFFF, first. Then a new packet is sent with the RTP timestamp
+         * increased by 0xFFFF. The duration is then reset and calculated
+         * relative to this new timestamp.
+         *
+         * This member indicates the number of 0xFFFF timestamp unit segments
+         * we have processed for the event we currently are writing.
+         */
         int segmentno;
+
+        /**
+         * Proxy for the source from which we're receiving events
+         */
         AsteriskSCF::SessionCommunications::V1::TelephonyEventSource* source;
     };
 
     class RTPTelephonyEventSourceStateItem extends RtpStateItem
     {
+        /**
+         * When processing incoming RFC 4733 events, typically 3 end packets
+         * will be received. To prevent duplicate end events from being sent
+         * to sinks, we keep track of whether we have already received an
+         * end for the event being read.
+         */
         bool onEnd;
+        /**
+         * The RTP timestamp of the beginning for the event we are processing.
+         * We use this when calculating the duration of events. See the explanation
+         * in RTPTelephonyEventSinkStateItem for how RFC 4733 deals with long
+         * events. We can always send an accurate duration by subracting the 
+         * original RTP timestamp from the RTP timestamp in the current packet.
+         */
         int timestamp;
+        /**
+         * Sinks to write events to
+         */
         AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkSeq sinks;
     };
 
diff --git a/src/RTPTelephonyEventSink.h b/src/RTPTelephonyEventSink.h
index 6768b7f..49aa3df 100644
--- a/src/RTPTelephonyEventSink.h
+++ b/src/RTPTelephonyEventSink.h
@@ -32,6 +32,9 @@ public:
             const AsteriskSCF::PJMediaRTP::PJMediaTransportPtr& transport,
             const AsteriskSCF::PJMediaRTP::SessionAdapterPtr& sessionAdapter);
 
+    /**
+     * Overrides of TelephonyEventSink interface
+     */
     void write_async(
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSink_writePtr&,
             const AsteriskSCF::SessionCommunications::V1::TelephonyEventPtr&,
@@ -46,12 +49,25 @@ public:
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSink_getSourcePtr&,
             const Ice::Current&);
 
+    /**
+     * Used by the state replicator listener to update the state of replicas
+     */
     void updateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr& item);
 
+    /**
+     * Accessor used to get the state item. Used during state replication
+     */
     AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr getStateItem();
 private:
 
+    /**
+     * Translate DTMF from ASCII into its RFC 4733-designated payload value
+     */
     pj_uint8_t translateDTMF(Ice::Byte signal);
+
+    /**
+     * Replicate state
+     */
     void replicateState();
 
     pjmedia_rtp_session *mSession;
diff --git a/src/RTPTelephonyEventSource.h b/src/RTPTelephonyEventSource.h
index 3749160..c5c4fc2 100644
--- a/src/RTPTelephonyEventSource.h
+++ b/src/RTPTelephonyEventSource.h
@@ -30,6 +30,9 @@ class RTPTelephonyEventSource : public AsteriskSCF::SessionCommunications::V1::T
 public:
     RTPTelephonyEventSource(const AsteriskSCF::PJMediaRTP::SessionAdapterPtr& sessionAdapter);
 
+    /**
+     * Overrides of TelephonyEventSource interface
+     */
     void addSink_async(
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSource_addSinkPtr& cb,
             const AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkPrx& sink,
@@ -39,22 +42,60 @@ public:
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSource_getSinksPtr& cb,
             const Ice::Current&);
 
+    /**
+     * Used to read a new RFC 4733 event in.
+     */
     void read(const pjmedia_rtp_hdr *hdr, const Ice::Byte* payload);
 
+    /**
+     * Used by the state replicator listener to update
+     * the state of a replica
+     */
     void updateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr&);
 
+    /**
+     * Accessor for the state item. Used in state replication
+     */
     AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr getStateItem();
 protected:
     ~RTPTelephonyEventSource();
 
 private:
 
+    /**
+     * Calculate the duration for the event.
+     *
+     * RFC 4733 event duration is expressed in timestamp units (i.e. samples). This function
+     * does two calculations to determine the duration in milliseconds.
+     *
+     * First, the duration expressed in the RFC 4733 event is converted to milliseconds.
+     * 
+     * Second, the RTP timestamp at the beginning of the event is subtracted from the RTP
+     * timestamp of the event being read and converted to milliseconds.
+     *
+     * These values are added together to determine the event duration.
+     */
     int calculateDuration(const pjmedia_rtp_hdr *header, const pjmedia_rtp_dtmf_event *event);
+    /**
+     * The following are methods for sending specific types of events to sinks
+     */
     void sendBeginEvent(const pjmedia_rtp_dtmf_event *event);
     void sendContinuationEvent(const pjmedia_rtp_dtmf_event *event, int duration);
     void sendEndEvent(const pjmedia_rtp_dtmf_event *event, int duration);
+
+    /**
+     * Send the resulting event to all sinks
+     */
     void distributeToSinks(const AsteriskSCF::SessionCommunications::V1::TelephonyEventPtr& event);
+
+    /**
+     * Translate DTMF from its RFC 4733 event payload to ASCII representation
+     */
     Ice::Byte translateDTMF(pj_uint8_t event);
+
+    /**
+     * Replicate state to replicas
+     */
     void replicateState();
 
     AsteriskSCF::PJMediaRTP::SessionAdapterPtr mSessionAdapter;

commit f367da4739906648c80c678121756047a97213e8
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 16:22:51 2011 -0500

    Add calls to actually replicate state.

diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index 74e109f..2974fd3 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -62,6 +62,7 @@ void RTPTelephonyEventSink::write_async(
     pjmedia_rtp_dtmf_event payload;
     bool setMarker = false;
     bool tsRollover = false;
+    bool replicationNeeded = false;
     if ((beginDTMF = BeginDTMFEventPtr::dynamicCast(event)))
     {
         payload.event = translateDTMF(beginDTMF->signal);
@@ -69,6 +70,7 @@ void RTPTelephonyEventSink::write_async(
         payload.duration = Duration;
         setMarker = true;
         mStateItem->segmentno = 0;
+        replicationNeeded = true;
     }
     else if (endDTMF = EndDTMFEventPtr::dynamicCast(event))
     {
@@ -79,6 +81,7 @@ void RTPTelephonyEventSink::write_async(
         if (tsRollover)
         {
             ++mStateItem->segmentno;
+            replicationNeeded = true;
         }
 
         payload.event = translateDTMF(endDTMF->signal);
@@ -94,6 +97,7 @@ void RTPTelephonyEventSink::write_async(
         if (tsRollover)
         {
             ++mStateItem->segmentno;
+            replicationNeeded = true;
         }
 
         payload.event = translateDTMF(continueDTMF->signal);
@@ -107,6 +111,7 @@ void RTPTelephonyEventSink::write_async(
         payload.duration = Duration;
         setMarker = true;
         mStateItem->segmentno = 0;
+        replicationNeeded = true;
     }
 
     const void *header;
@@ -150,6 +155,11 @@ void RTPTelephonyEventSink::write_async(
         //fffffffuuuuuuuuuuuu
     }
 
+    if (replicationNeeded)
+    {
+        mSessionAdapter->replicateState(mStateItem);
+    }
+
     cb->ice_response();
 }
 
@@ -159,6 +169,7 @@ void RTPTelephonyEventSink::setSource_async(
         const Ice::Current&)
 {
     mStateItem->source = source;
+    mSessionAdapter->replicateState(mStateItem);
     cb->ice_response();
 }
 
diff --git a/src/RTPTelephonyEventSource.cpp b/src/RTPTelephonyEventSource.cpp
index b7cb804..aee56f9 100644
--- a/src/RTPTelephonyEventSource.cpp
+++ b/src/RTPTelephonyEventSource.cpp
@@ -49,6 +49,7 @@ void RTPTelephonyEventSource::addSink_async(
     {
         mStateItem->sinks.push_back(sink);
     }
+    mSessionAdapter->replicateState(mStateItem);
     cb->ice_response();
 }
 
@@ -76,6 +77,7 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
 
     bool isEnd = (event->e_vol & 0x80);
 
+    bool replicationNeeded =false;
     //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.
@@ -84,6 +86,7 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
         int duration = calculateDuration(header, event);
         sendEndEvent(event, duration);
         mStateItem->onEnd = true;
+        replicationNeeded = true;
     }
     else if (!isEnd)
     {
@@ -97,6 +100,7 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
             sendBeginEvent(event);
             mStateItem->onEnd = false;
             mStateItem->timestamp = pj_ntohl(header->ts);
+            replicationNeeded = true;
         }
         else
         {
@@ -105,6 +109,11 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
             sendContinuationEvent(event, duration);
         }
     }
+
+    if (replicationNeeded)
+    {
+        mSessionAdapter->replicateState(mStateItem);
+    }
 }
 
 int RTPTelephonyEventSource::calculateDuration(const pjmedia_rtp_hdr *header, const pjmedia_rtp_dtmf_event *event)

commit 432e98a60d5da408de623badd3cbbdd1b2d9974c
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 16:16:28 2011 -0500

    Infrastructure for state replication is completely set up.
    
    Now all that's needed is for strategic calls to replicateState()
    to be called.

diff --git a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
index 4c44683..c0783d0 100644
--- a/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
+++ b/slice/AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.ice
@@ -107,6 +107,19 @@ module V1
 	AsteriskSCF::Media::V1::StreamSinkSeq sinks;
     };
 
+    class RTPTelephonyEventSinkStateItem extends RtpStateItem
+    {
+        int segmentno;
+        AsteriskSCF::SessionCommunications::V1::TelephonyEventSource* source;
+    };
+
+    class RTPTelephonyEventSourceStateItem extends RtpStateItem
+    {
+        bool onEnd;
+        int timestamp;
+        AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkSeq sinks;
+    };
+
 }; /* module V1 */
 
 }; /* module MediaRTPPJMedia */
diff --git a/src/RTPSession.cpp b/src/RTPSession.cpp
index 95da958..dd7ba39 100644
--- a/src/RTPSession.cpp
+++ b/src/RTPSession.cpp
@@ -191,12 +191,17 @@ public:
      */
     StreamSourceRTPImplPtr getSourceServant();
     StreamSinkRTPImplPtr getSinkServant();
+    RTPTelephonyEventSourcePtr getTelephonyEventSourceServant();
+    RTPTelephonyEventSinkPtr getTelephonyEventSinkServant();
     PJMediaTransportPtr getTransport();
 
 
-    void replicateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpSessionStateItemPtr&,
+    void replicateState(
+            const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpSessionStateItemPtr&,
             const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSinkStateItemPtr&,
-            const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr&);
+            const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr&,
+            const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr&,
+            const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr&);
     void removeState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpSessionStateItemPtr&,
             const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSinkStateItemPtr&,
             const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr&);
@@ -383,12 +388,22 @@ public:
 
     void replicateState(const RtpStreamSinkStateItemPtr& sinkStateItem) 
     {
-        mServant->replicateState(0, sinkStateItem, 0);
+        mServant->replicateState(0, sinkStateItem, 0, 0, 0);
     }
 
     void replicateState(const RtpStreamSourceStateItemPtr& sourceStateItem)
     {
-        mServant->replicateState(0, 0, sourceStateItem);
+        mServant->replicateState(0, 0, sourceStateItem, 0, 0);
+    }
+
+    void replicateState(const RTPTelephonyEventSinkStateItemPtr& item)
+    {
+        mServant->replicateState(0, 0, 0, item, 0);
+    }
+
+    void replicateState(const RTPTelephonyEventSourceStateItemPtr& item)
+    {
+        mServant->replicateState(0, 0, 0, 0, item);
     }
 
     AsteriskSCF::Media::V1::FormatPtr getFormat(int payload) 
@@ -621,7 +636,7 @@ void RTPSessionImpl::associatePayloads(const AsteriskSCF::Media::RTP::V1::Payloa
     associatePayloadsImpl(mappings);
 
     // Only the session has changed so push a single update out for it
-    replicateState(mSessionStateItem, 0, 0);
+    replicateState(mSessionStateItem, 0, 0, 0, 0);
 }
 
 
@@ -723,7 +738,7 @@ void RTPSessionImpl::setRemoteRtcpDetails(const std::string& address, Ice::Int p
 
     mStreamSource->setRemoteRtcpDetails(address, port);
 
-    replicateState(mSessionStateItem, 0, 0);
+    replicateState(mSessionStateItem, 0, 0, 0, 0);
 }
 
 /**
@@ -775,11 +790,25 @@ PJMediaTransportPtr RTPSessionImpl::getTransport()
     return mTransport;
 }
 
+RTPTelephonyEventSourcePtr RTPSessionImpl::getTelephonyEventSourceServant()
+{
+    return getSourceServant()->getTelephonyEventSource();
+}
+
+RTPTelephonyEventSinkPtr RTPSessionImpl::getTelephonyEventSinkServant()
+{
+    return getSinkServant()->getTelephonyEventSink();
+}
+
 /**
  * API call which replicates state items.
  */
-void RTPSessionImpl::replicateState(const RtpSessionStateItemPtr& session, const RtpStreamSinkStateItemPtr& sink,
-        const RtpStreamSourceStateItemPtr& source)
+void RTPSessionImpl::replicateState(
+        const RtpSessionStateItemPtr& session,
+        const RtpStreamSinkStateItemPtr& sink,
+        const RtpStreamSourceStateItemPtr& source,
+        const RTPTelephonyEventSinkStateItemPtr& telephonyEventSink,
+        const RTPTelephonyEventSourceStateItemPtr& telephonyEventSource)
 {
     // If state replication has been disabled do nothing
     if (!mStateReplicator || mReplicaService->isActive() == false)
@@ -804,6 +833,16 @@ void RTPSessionImpl::replicateState(const RtpSessionStateItemPtr& session, const
 	items.push_back(source);
     }
 
+    if (telephonyEventSink)
+    {
+        items.push_back(telephonyEventSink);
+    }
+
+    if (telephonyEventSource)
+    {
+        items.push_back(telephonyEventSource);
+    }
+
     if (items.size() == 0)
     {
 	return;
@@ -943,7 +982,12 @@ RTPSessionPrx RTPSessionImpl::activate(
             {
                 mSessionStateItem->port = 0;
             }
-            replicateState(mSessionStateItem, mStreamSink->getStateItem(), mStreamSource->getStateItem());
+            replicateState(
+                    mSessionStateItem,
+                    mStreamSink->getStateItem(),
+                    mStreamSource->getStateItem(),
+                    mStreamSink->getTelephonyEventSinkStateItem(),
+                    mStreamSource->getTelephonyEventSourceStateItem());
         }
         RTPSessionPrx result = RTPSessionPrx::uncheckedCast(mAdapter->add(this, id));
         mTransport->addFacets(mAdapter, id);
@@ -1001,6 +1045,16 @@ public:
         mImpl->getSourceServant()->setSinksImpl(item->sinks);
     }
 
+    void update(const RTPTelephonyEventSourceStateItemPtr& item)
+    {
+        mImpl->getTelephonyEventSourceServant()->updateState(item);
+    }
+
+    void update(const RTPTelephonyEventSinkStateItemPtr& item)
+    {
+        mImpl->getTelephonyEventSinkServant()->updateState(item);
+    }
+
     void destroy()
     {
         mImpl->destroy();
diff --git a/src/RTPSink.cpp b/src/RTPSink.cpp
index 4932182..3b37056 100644
--- a/src/RTPSink.cpp
+++ b/src/RTPSink.cpp
@@ -117,6 +117,11 @@ TelephonyEventSinkPrx StreamSinkRTPImpl::createTelephonyEventSink(Ice::ObjectAda
     return TelephonyEventSinkPrx::uncheckedCast(adapter->addWithUUID(mImpl->mTelephonyEventSink));
 }
 
+RTPTelephonyEventSinkPtr StreamSinkRTPImpl::getTelephonyEventSink()
+{
+    return mImpl->mTelephonyEventSink;
+}
+
 /**
  * Implementation of the write method as defined in MediaIf.ice
  */
@@ -272,6 +277,15 @@ RtpStreamSinkStateItemPtr StreamSinkRTPImpl::getStateItem()
     return mImpl->mSinkStateItem;
 }
 
+RTPTelephonyEventSinkStateItemPtr StreamSinkRTPImpl::getTelephonyEventSinkStateItem()
+{
+    if (mImpl->mTelephonyEventSink)
+    {
+        return mImpl->mTelephonyEventSink->getStateItem();
+    }
+    return 0;
+}
+
 void StreamSinkRTPImpl::setRemoteDetailsImpl(const std::string& host, Ice::Int port)
 {
     mImpl->mSinkStateItem->remoteAddress = host;
diff --git a/src/RTPSink.h b/src/RTPSink.h
index a40738c..4c08486 100644
--- a/src/RTPSink.h
+++ b/src/RTPSink.h
@@ -12,8 +12,7 @@
 #include "SessionAdapter.h"
 #include <boost/shared_ptr.hpp>
 #include <IceUtil/Handle.h>
-//Needed for TelephonySink
-#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include "RTPTelephonyEventSink.h"
 
 /**
  * Forward definition for our private implementation of StreamSinkRTP.
@@ -44,10 +43,12 @@ public:
     Ice::Int getRemotePort(const Ice::Current&);
 
     AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkPrx createTelephonyEventSink(Ice::ObjectAdapterPtr& adapter);
+    RTPTelephonyEventSinkPtr getTelephonyEventSink();
     /**
      * Internal implementation methods.
      */
     AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSinkStateItemPtr getStateItem();
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr getTelephonyEventSinkStateItem();
     void setRemoteDetailsImpl(const std::string& host, Ice::Int port);
     void setSourceImpl(const AsteriskSCF::Media::V1::StreamSourcePrx& proxy);
 
diff --git a/src/RTPSource.cpp b/src/RTPSource.cpp
index c12d023..81e4978 100644
--- a/src/RTPSource.cpp
+++ b/src/RTPSource.cpp
@@ -219,11 +219,16 @@ StreamSourceRTPImpl::StreamSourceRTPImpl(const SessionAdapterPtr& session,
 
 TelephonyEventSourcePrx StreamSourceRTPImpl::createTelephonyEventSource(Ice::ObjectAdapterPtr& adapter)
 {
-    mImpl->mTelephonyEventSource = new RTPTelephonyEventSource(&mImpl->mIncomingSession);
+    mImpl->mTelephonyEventSource = new RTPTelephonyEventSource(mImpl->mSessionAdapter);
 
     return TelephonyEventSourcePrx::uncheckedCast(adapter->addWithUUID(mImpl->mTelephonyEventSource));
 }
 
+RTPTelephonyEventSourcePtr StreamSourceRTPImpl::getTelephonyEventSource()
+{
+    return mImpl->mTelephonyEventSource;
+}
+
 /**
  * Implementation of the addSink method as defined in MediaIf.ice
  */
@@ -588,6 +593,15 @@ RtpStreamSourceStateItemPtr StreamSourceRTPImpl::getStateItem()
     return mImpl->mSourceStateItem;
 }
 
+RTPTelephonyEventSourceStateItemPtr StreamSourceRTPImpl::getTelephonyEventSourceStateItem()
+{
+    if (mImpl->mTelephonyEventSource)
+    {
+        return mImpl->mTelephonyEventSource->getStateItem();
+    }
+    return 0;
+}
+
 void StreamSourceRTPImpl::setSinksImpl(const AsteriskSCF::Media::V1::StreamSinkSeq& sinks)
 {
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mLock);
diff --git a/src/RTPSource.h b/src/RTPSource.h
index a69e722..aa57773 100644
--- a/src/RTPSource.h
+++ b/src/RTPSource.h
@@ -12,8 +12,7 @@
 #include "SessionAdapter.h"
 #include <boost/shared_ptr.hpp>
 #include <IceUtil/Handle.h>
-//Needed for TelephonySource 
-#include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include "RTPTelephonyEventSource.h"
 
 /**
  * Forward definition for our private implementation of StreamSourceRTP.
@@ -46,10 +45,12 @@ public:
     void setRemoteRtcpDetails(const std::string&, Ice::Int);
 
     AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr getStateItem();
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr getTelephonyEventSourceStateItem();
 
     void setSinkImpl(const AsteriskSCF::Media::V1::StreamSinkPrx& proxy);
 
     AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx createTelephonyEventSource(Ice::ObjectAdapterPtr& adapter);
+    RTPTelephonyEventSourcePtr getTelephonyEventSource();
 
     /**
      * Private implementation data for StreamSourceRTPImpl.
diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index d6f6404..74e109f 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -38,12 +38,16 @@ const pj_uint16_t Duration = 160;
 
 using namespace AsteriskSCF::SessionCommunications::V1;
 using namespace AsteriskSCF::PJMediaRTP;
+using namespace AsteriskSCF::Replication::MediaRTPPJMedia::V1;
 
 RTPTelephonyEventSink::RTPTelephonyEventSink(
         pjmedia_rtp_session *session,
         const PJMediaTransportPtr& transport,
         const SessionAdapterPtr& sessionAdapter)
-    : mSession(session), mTransport(transport), mSessionAdapter(sessionAdapter), mSegmentno(0) { }
+    : mSession(session), mTransport(transport), mSessionAdapter(sessionAdapter), mStateItem(new RTPTelephonyEventSinkStateItem)
+{
+    mStateItem->segmentno = 0;
+}
 
 void RTPTelephonyEventSink::write_async(
         const AMD_TelephonyEventSink_writePtr& cb,
@@ -64,17 +68,17 @@ void RTPTelephonyEventSink::write_async(
         payload.e_vol = DTMFVolume;
         payload.duration = Duration;
         setMarker = true;
-        mSegmentno = 0;
+        mStateItem->segmentno = 0;
     }
     else if (endDTMF = EndDTMFEventPtr::dynamicCast(event))
     {
         int durationSamples = (endDTMF->duration * 8000 / 1000);
         pj_uint16_t payloadDuration = (pj_uint16_t) (durationSamples % 0x10000);
-        tsRollover = (durationSamples / 0x10000) > mSegmentno;
+        tsRollover = (durationSamples / 0x10000) > mStateItem->segmentno;
 
         if (tsRollover)
         {
-            ++mSegmentno;
+            ++mStateItem->segmentno;
         }
 
         payload.event = translateDTMF(endDTMF->signal);
@@ -85,11 +89,11 @@ void RTPTelephonyEventSink::write_async(
     {
         int durationSamples = (continueDTMF->duration * 8000 / 1000);
         pj_uint16_t payloadDuration = (pj_uint16_t) (durationSamples % 0x10000);
-        tsRollover = (durationSamples / 0x10000) > mSegmentno;
+        tsRollover = (durationSamples / 0x10000) > mStateItem->segmentno;
 
         if (tsRollover)
         {
-            ++mSegmentno;
+            ++mStateItem->segmentno;
         }
 
         payload.event = translateDTMF(continueDTMF->signal);
@@ -102,7 +106,7 @@ void RTPTelephonyEventSink::write_async(
         payload.e_vol = DTMFVolume;
         payload.duration = Duration;
         setMarker = true;
-        mSegmentno = 0;
+        mStateItem->segmentno = 0;
     }
 
     const void *header;
@@ -154,7 +158,7 @@ void RTPTelephonyEventSink::setSource_async(
         const TelephonyEventSourcePrx& source,
         const Ice::Current&)
 {
-    mSource = source;
+    mStateItem->source = source;
     cb->ice_response();
 }
 
@@ -162,7 +166,7 @@ void RTPTelephonyEventSink::getSource_async(
         const AMD_TelephonyEventSink_getSourcePtr& cb,
         const Ice::Current&)
 {
-    cb->ice_response(mSource);
+    cb->ice_response(mStateItem->source);
 }
 
 pj_uint8_t RTPTelephonyEventSink::translateDTMF(Ice::Byte signal)
@@ -189,3 +193,19 @@ pj_uint8_t RTPTelephonyEventSink::translateDTMF(Ice::Byte signal)
         return 255;
     }
 }
+
+void RTPTelephonyEventSink::replicateState()
+{
+    mSessionAdapter->replicateState(mStateItem);
+}
+
+void RTPTelephonyEventSink::updateState(const RTPTelephonyEventSinkStateItemPtr& item)
+{
+    mStateItem->segmentno = item->segmentno;
+    mStateItem->source = item->source;
+}
+
+RTPTelephonyEventSinkStateItemPtr RTPTelephonyEventSink::getStateItem()
+{
+    return mStateItem;
+}
diff --git a/src/RTPTelephonyEventSink.h b/src/RTPTelephonyEventSink.h
index 551a72f..6768b7f 100644
--- a/src/RTPTelephonyEventSink.h
+++ b/src/RTPTelephonyEventSink.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <pjmedia.h>
+#include <AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.h>
 #include <AsteriskSCF/SessionCommunications/TelephonyEventsIf.h>
 
 #include "PJMediaTransport.h"
@@ -44,22 +45,20 @@ public:
     void getSource_async(
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSink_getSourcePtr&,
             const Ice::Current&);
+
+    void updateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr& item);
+
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr getStateItem();
 private:
 
     pj_uint8_t translateDTMF(Ice::Byte signal);
+    void replicateState();
 
     pjmedia_rtp_session *mSession;
     AsteriskSCF::PJMediaRTP::PJMediaTransportPtr mTransport;
     AsteriskSCF::PJMediaRTP::SessionAdapterPtr mSessionAdapter;
-    /**
-     * For long duration RFC 4733 events, the timestamp needs to be incremented every time
-     * 65535 timestamp units pass. We must therefore keep track of how long the event has
-     * lasted in order to determine when to increase the timestamp. This number indicates
-     * the number of 65535 timestamp unit "segments" we have processed. Each time it increases,
-     * we will update the RTP timestamp for the event we are sending.
-     */
-    int mSegmentno;
-    AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx mSource;
+
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr mStateItem;
 };
 
 typedef IceUtil::Handle<RTPTelephonyEventSink> RTPTelephonyEventSinkPtr;
diff --git a/src/RTPTelephonyEventSource.cpp b/src/RTPTelephonyEventSource.cpp
index fc08248..b7cb804 100644
--- a/src/RTPTelephonyEventSource.cpp
+++ b/src/RTPTelephonyEventSource.cpp
@@ -20,15 +20,19 @@
 
 using namespace AsteriskSCF::SessionCommunications::V1;
 using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::Replication::MediaRTPPJMedia::V1;
+using namespace AsteriskSCF::PJMediaRTP;
 
 namespace
 {
 Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaRTP");
 }
 
-RTPTelephonyEventSource::RTPTelephonyEventSource(pjmedia_rtp_session *session) 
-    : mSession(session), mOnEnd(false), mTimestamp(0)
+RTPTelephonyEventSource::RTPTelephonyEventSource(const SessionAdapterPtr& sessionAdapter) 
+    : mSessionAdapter(sessionAdapter), mStateItem(new RTPTelephonyEventSourceStateItem())
 {
+    mStateItem->onEnd = false;
+    mStateItem->timestamp = 0;
 }
 
 RTPTelephonyEventSource::~RTPTelephonyEventSource()
@@ -41,9 +45,9 @@ void RTPTelephonyEventSource::addSink_async(
         const Ice::Current&)
 {
     boost::unique_lock<boost::shared_mutex> lock(mLock);
-    if (std::find(mSinks.begin(), mSinks.end(), sink) == mSinks.end())
+    if (std::find(mStateItem->sinks.begin(), mStateItem->sinks.end(), sink) == mStateItem->sinks.end())
     {
-        mSinks.push_back(sink);
+        mStateItem->sinks.push_back(sink);
     }
     cb->ice_response();
 }
@@ -53,12 +57,7 @@ void RTPTelephonyEventSource::getSinks_async(
         const Ice::Current&)
 {
     boost::shared_lock<boost::shared_mutex> lock(mLock);
-    cb->ice_response(mSinks);
-}
-
-TelephonyEventSourcePrx RTPTelephonyEventSource::getProxy()
-{
-    return mProxy;
+    cb->ice_response(mStateItem->sinks);
 }
 
 void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byte* payload)
@@ -80,11 +79,11 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
     //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)
+    if (isEnd && !mStateItem->onEnd)
     {
         int duration = calculateDuration(header, event);
         sendEndEvent(event, duration);
-        mOnEnd = true;
+        mStateItem->onEnd = true;
     }
     else if (!isEnd)
     {
@@ -96,8 +95,8 @@ void RTPTelephonyEventSource::read(const pjmedia_rtp_hdr* header, const Ice::Byt
         if (header->m)
         {
             sendBeginEvent(event);
-            mOnEnd = false;
-            mTimestamp = pj_ntohl(header->ts);
+            mStateItem->onEnd = false;
+            mStateItem->timestamp = pj_ntohl(header->ts);
         }
         else
         {
@@ -126,7 +125,7 @@ int RTPTelephonyEventSource::calculateDuration(const pjmedia_rtp_hdr *header, co
     //By caching the original RTP timestamp at the beginning of the event, we
     //can subtract the timestamp in the beginning packet from the timestamp in
     //this one to determine the cumulative duration of the event.
-    int baseMS = ((pj_ntohl(header->ts) - mTimestamp) * 1000) / 8000;
+    int baseMS = ((pj_ntohl(header->ts) - mStateItem->timestamp) * 1000) / 8000;
 
     return (baseMS + timestampMS);
 }
@@ -175,8 +174,8 @@ void RTPTelephonyEventSource::sendEndEvent(const pjmedia_rtp_dtmf_event *event,
 void RTPTelephonyEventSource::distributeToSinks(const TelephonyEventPtr& event)
 {
     boost::unique_lock<boost::shared_mutex> lock(mLock);
-    for (TelephonyEventSinkSeq::iterator iter = mSinks.begin();
-            iter != mSinks.end(); ++iter)
+    for (TelephonyEventSinkSeq::iterator iter = mStateItem->sinks.begin();
+            iter != mStateItem->sinks.end(); ++iter)
     {
         try
         {
@@ -210,3 +209,20 @@ Ice::Byte RTPTelephonyEventSource::translateDTMF(pj_uint8_t event)
         return (Ice::Byte) ((event - 12) + 'A');
     }
 }
+
+void RTPTelephonyEventSource::replicateState()
+{
+    mSessionAdapter->replicateState(mStateItem);
+}
+
+void RTPTelephonyEventSource::updateState(const RTPTelephonyEventSourceStateItemPtr& item)
+{
+    mStateItem->onEnd = item->onEnd;
+    mStateItem->timestamp = item->timestamp;
+    mStateItem->sinks = item->sinks;
+}
+
+RTPTelephonyEventSourceStateItemPtr RTPTelephonyEventSource::getStateItem()
+{
+    return mStateItem;
+}
diff --git a/src/RTPTelephonyEventSource.h b/src/RTPTelephonyEventSource.h
index 2013ec3..3749160 100644
--- a/src/RTPTelephonyEventSource.h
+++ b/src/RTPTelephonyEventSource.h
@@ -19,13 +19,16 @@
 #include <boost/thread.hpp>
 
 #include <AsteriskSCF/SessionCommunications/TelephonyEventsIf.h>
+#include <AsteriskSCF/Replication/MediaRTPPJMedia/RtpStateReplicationIf.h>
 
 #include <pjmedia.h>
 
+#include "SessionAdapter.h"
+
 class RTPTelephonyEventSource : public AsteriskSCF::SessionCommunications::V1::TelephonyEventSource
 {
 public:
-    RTPTelephonyEventSource(pjmedia_rtp_session *session);
+    RTPTelephonyEventSource(const AsteriskSCF::PJMediaRTP::SessionAdapterPtr& sessionAdapter);
 
     void addSink_async(
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSource_addSinkPtr& cb,
@@ -36,10 +39,11 @@ public:
             const AsteriskSCF::SessionCommunications::V1::AMD_TelephonyEventSource_getSinksPtr& cb,
             const Ice::Current&);
 
-    AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx getProxy();
-
     void read(const pjmedia_rtp_hdr *hdr, const Ice::Byte* payload);
 
+    void updateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr&);
+
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr getStateItem();
 protected:
     ~RTPTelephonyEventSource();
 
@@ -51,25 +55,10 @@ private:
     void sendEndEvent(const pjmedia_rtp_dtmf_event *event, int duration);
     void distributeToSinks(const AsteriskSCF::SessionCommunications::V1::TelephonyEventPtr& event);
     Ice::Byte translateDTMF(pj_uint8_t event);
+    void replicateState();
 
-    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;
-    /**
-     * The timestamp of the RTP packet that begins an RFC 4733 event. We keep
-     * this handy for calculating the duration of long events.
-     */
-    pj_uint32_t mTimestamp;
-    /**
-     * Sinks to send events to
-     */
-    AsteriskSCF::SessionCommunications::V1::TelephonyEventSinkSeq mSinks;
+    AsteriskSCF::PJMediaRTP::SessionAdapterPtr mSessionAdapter;
+    AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr mStateItem;
     boost::shared_mutex mLock;
 };
 
diff --git a/src/ReplicationAdapter.h b/src/ReplicationAdapter.h
index af5e829..72b4b98 100644
--- a/src/ReplicationAdapter.h
+++ b/src/ReplicationAdapter.h
@@ -35,6 +35,8 @@ public:
     virtual void update(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpSessionStateItemPtr& item) = 0;
     virtual void update(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSinkStateItemPtr& item) = 0;
     virtual void update(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr& item) = 0;
+    virtual void update(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr& item) = 0;
+    virtual void update(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr& item) = 0;
     virtual void destroy() = 0;
 };
 
diff --git a/src/RtpStateReplicatorListener.cpp b/src/RtpStateReplicatorListener.cpp
index b393613..5c287ce 100644
--- a/src/RtpStateReplicatorListener.cpp
+++ b/src/RtpStateReplicatorListener.cpp
@@ -147,6 +147,27 @@ public:
                     i->second->getSession()->update(item);
 		}
 	    }
+
+            void visitRTPTelephonyEventSourceStateItem(const RTPTelephonyEventSourceStateItemPtr& item)
+            {
+                map<string, boost::shared_ptr<RtpStateReplicatorItem> >::iterator i =
+                    mImpl->mStateItems.find(item->sessionId);
+                if (i != mImpl->mStateItems.end())
+                {
+                    i->second->getSession()->update(item);
+                }
+            }
+
+            void visitRTPTelephonyEventSinkStateItem(const RTPTelephonyEventSinkStateItemPtr& item)
+            {
+                map<string, boost::shared_ptr<RtpStateReplicatorItem> >::iterator i =
+                    mImpl->mStateItems.find(item->sessionId);
+                if (i != mImpl->mStateItems.end())
+                {
+                    i->second->getSession()->update(item);
+                }
+            }
+
 	};
 
 	AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStateItemVisitorPtr v = new visitor(this);
diff --git a/src/SessionAdapter.h b/src/SessionAdapter.h
index de017b2..1d3ce4f 100644
--- a/src/SessionAdapter.h
+++ b/src/SessionAdapter.h
@@ -51,6 +51,8 @@ public:
 
     virtual void replicateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSinkStateItemPtr& sinkStateItem) = 0;
     virtual void replicateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RtpStreamSourceStateItemPtr& sourceStateItem) = 0; 
+    virtual void replicateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSourceStateItemPtr& item) = 0;
+    virtual void replicateState(const AsteriskSCF::Replication::MediaRTPPJMedia::V1::RTPTelephonyEventSinkStateItemPtr& item) = 0;
 
     virtual AsteriskSCF::Media::V1::FormatPtr getFormat(int payload) = 0;
     virtual int getPayload(const AsteriskSCF::Media::V1::FormatPtr& format) = 0;

commit 27b6f831e45fcac62c47bc0a8e6346bceb41312f
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 11:04:05 2011 -0500

    Fix timestamp adjustment for long-duration events in the telephony event sink.

diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index cfaae6e..d6f6404 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -43,7 +43,7 @@ RTPTelephonyEventSink::RTPTelephonyEventSink(
         pjmedia_rtp_session *session,
         const PJMediaTransportPtr& transport,
         const SessionAdapterPtr& sessionAdapter)
-    : mSession(session), mTransport(transport), mSessionAdapter(sessionAdapter) { }
+    : mSession(session), mTransport(transport), mSessionAdapter(sessionAdapter), mSegmentno(0) { }
 
 void RTPTelephonyEventSink::write_async(
         const AMD_TelephonyEventSink_writePtr& cb,
@@ -57,24 +57,44 @@ void RTPTelephonyEventSink::write_async(
     
     pjmedia_rtp_dtmf_event payload;
     bool setMarker = false;
+    bool tsRollover = false;
     if ((beginDTMF = BeginDTMFEventPtr::dynamicCast(event)))
     {
         payload.event = translateDTMF(beginDTMF->signal);
         payload.e_vol = DTMFVolume;
         payload.duration = Duration;
         setMarker = true;
+        mSegmentno = 0;
     }
     else if (endDTMF = EndDTMFEventPtr::dynamicCast(event))
     {
+        int durationSamples = (endDTMF->duration * 8000 / 1000);
+        pj_uint16_t payloadDuration = (pj_uint16_t) (durationSamples % 0x10000);
+        tsRollover = (durationSamples / 0x10000) > mSegmentno;
+
+        if (tsRollover)
+        {
+            ++mSegmentno;
+        }
+
         payload.event = translateDTMF(endDTMF->signal);
         payload.e_vol = DTMFVolume;
-        payload.duration = pj_htons((pj_uint16_t)(((endDTMF->duration * 8000) / 1000) % 0xFFFF));
+        payload.duration = pj_htons(payloadDuration);
     }
     else if (continueDTMF = ContinueDTMFEventPtr::dynamicCast(event))
     {
+        int durationSamples = (continueDTMF->duration * 8000 / 1000);
+        pj_uint16_t payloadDuration = (pj_uint16_t) (durationSamples % 0x10000);
+        tsRollover = (durationSamples / 0x10000) > mSegmentno;
+
+        if (tsRollover)
+        {
+            ++mSegmentno;
+        }
+
         payload.event = translateDTMF(continueDTMF->signal);
         payload.e_vol = DTMFVolume | 0x80;
-        payload.duration = pj_htons((pj_uint16_t)(((continueDTMF->duration * 8000) / 1000) % 0xFFFF));
+        payload.duration = pj_htons(payloadDuration);
     }
     else if (flash = FlashEventPtr::dynamicCast(event))
     {
@@ -82,6 +102,7 @@ void RTPTelephonyEventSink::write_async(
         payload.e_vol = DTMFVolume;
         payload.duration = Duration;
         setMarker = true;
+        mSegmentno = 0;
     }
 
     const void *header;
@@ -94,17 +115,17 @@ void RTPTelephonyEventSink::write_async(
             new AsteriskSCF::Media::Formats::Other::V1::RFC4733(
                 AsteriskSCF::Media::Formats::Other::V1::RFC4733Name, 0));
 
-    //The fifth parameter is set to 0 here since the RTP timestamp is the same
-    //for all packets sent during an event.
-    //
-    //XXX The fifth parameter will need to be set to 0xFFFF each time that
-    //the event "rolls over" on long duration events.
+    //The fifth parameter is the amount to increase the RTP timestamp by
+    //for this packet. In most cases this will be 0 since packets describing
+    //the same event carry the same timestamp. However, in the case of a long
+    //duration event, the timestamp will be incremented by 65535 for each
+    //"segment" of the event.
     pj_status_t status = pjmedia_rtp_encode_rtp(
             mSession,
             payloadType,
             sizeof(payload),
             setMarker ? 1 : 0,
-            0,
+            tsRollover  ? 0xFFFF : 0,
             &header,
             &header_len);
 
diff --git a/src/RTPTelephonyEventSink.h b/src/RTPTelephonyEventSink.h
index 95c0f70..551a72f 100644
--- a/src/RTPTelephonyEventSink.h
+++ b/src/RTPTelephonyEventSink.h
@@ -51,6 +51,14 @@ private:
     pjmedia_rtp_session *mSession;
     AsteriskSCF::PJMediaRTP::PJMediaTransportPtr mTransport;
     AsteriskSCF::PJMediaRTP::SessionAdapterPtr mSessionAdapter;
+    /**
+     * For long duration RFC 4733 events, the timestamp needs to be incremented every time
+     * 65535 timestamp units pass. We must therefore keep track of how long the event has
+     * lasted in order to determine when to increase the timestamp. This number indicates
+     * the number of 65535 timestamp unit "segments" we have processed. Each time it increases,
+     * we will update the RTP timestamp for the event we are sending.
+     */
+    int mSegmentno;
     AsteriskSCF::SessionCommunications::V1::TelephonyEventSourcePrx mSource;
 };
 

commit 0950e6d32f6bdb665ad54090a324a5f93ace1b3b
Author: Mark Michelson <mmichelson at digium.com>
Date:   Wed Aug 10 09:48:36 2011 -0500

    Make sure to include the name of the format when allocating.
    
    Otherwise it won't be found and we won't have the proper payload type
    for our outbound packet.

diff --git a/src/RTPTelephonyEventSink.cpp b/src/RTPTelephonyEventSink.cpp
index b3198e1..cfaae6e 100644
--- a/src/RTPTelephonyEventSink.cpp
+++ b/src/RTPTelephonyEventSink.cpp
@@ -28,7 +28,7 @@ const pj_uint8_t DTMFVolume = 15;
 
 //Duration is used either for events where
 //duration isn't really a factor (like for
-//flash) or where we cannot determined a satisfactory
+//flash) or where we cannot determine a satisfactory
 //duration.
 //
 //This is derived from an 8000 Hz clock rate at
@@ -90,7 +90,9 @@ void RTPTelephonyEventSink::write_async(
 
     //XXX We could probably just cache this pointer so we don't have to create
     //a new one on every write.
-    payloadType = mSessionAdapter->getPayload(new AsteriskSCF::Media::Formats::Other::V1::RFC4733());
+    payloadType = mSessionAdapter->getPayload(
+            new AsteriskSCF::Media::Formats::Other::V1::RFC4733(
+                AsteriskSCF::Media::Formats::Other::V1::RFC4733Name, 0));
 
     //The fifth parameter is set to 0 here since the RTP timestamp is the same
     //for all packets sent during an event.

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


-- 
asterisk-scf/integration/media_rtp_pjmedia.git



More information about the asterisk-scf-commits mailing list