diff --git a/core/AmDtmfDetector.cpp b/core/AmDtmfDetector.cpp index 44350173..52847aae 100644 --- a/core/AmDtmfDetector.cpp +++ b/core/AmDtmfDetector.cpp @@ -135,13 +135,14 @@ void AmSipDtmfEvent::parseLine(const string& line) // // AmRtpDtmfEvent methods // -AmRtpDtmfEvent::AmRtpDtmfEvent(const dtmf_payload_t *payload, int sample_rate) +AmRtpDtmfEvent::AmRtpDtmfEvent(const dtmf_payload_t *payload, int sample_rate, unsigned int ts) : AmDtmfEvent(Dtmf::SOURCE_RTP) { m_duration_msec = ntohs(payload->duration) * 1000 / sample_rate; m_e = payload->e; m_volume = payload->volume; m_event = payload->event; + m_ts = ts; // RFC 2833: // R: This field is reserved for future use. The sender MUST set it // to zero, the receiver MUST ignore it. @@ -180,7 +181,8 @@ AmDtmfDetector::AmDtmfDetector(AmSession *session) m_sipDetector(this), m_eventPending(false), m_sipEventReceived(false), m_inbandEventReceived(false), m_rtpEventReceived(false), - m_inband_type(Dtmf::SEMSInternal) + m_inband_type(Dtmf::SEMSInternal), + m_currentEvent(-1) { #ifndef USE_SPANDSP setInbandDetector(Dtmf::SEMSInternal); @@ -237,11 +239,12 @@ void AmDtmfDetector::process(AmEvent *evt) void AmDtmfDetector::registerKeyReleased(int event, Dtmf::EventSource source, const struct timeval& start, - const struct timeval& stop) + const struct timeval& stop, + bool flush) { // Old event has not been sent yet // push out it now - if (m_eventPending && m_currentEvent != event) + if (flush || (m_eventPending && m_currentEvent != event)) { reportEvent(); } @@ -333,7 +336,8 @@ void AmDtmfDetector::putDtmfAudio(const unsigned char *buf, int size, int user_t // AmRtpDtmfDetector methods AmRtpDtmfDetector::AmRtpDtmfDetector(AmKeyPressSink *keysink) - : m_keysink(keysink), m_eventPending(false), m_packetCount(0) + : m_keysink(keysink), m_eventPending(false), m_packetCount(0), + m_currentTS(0), m_currentTS_i(false), m_lastTS_i(false) { } @@ -345,44 +349,50 @@ void AmRtpDtmfDetector::process(AmRtpDtmfEvent *evt) // ITU-T Q.24A) { m_packetCount = 0; // reset idle packet counter + + if (m_lastTS_i && m_lastTS == evt->ts()) { + // ignore events from past key press which was already reported + return; + } + if (!m_eventPending) { gettimeofday(&m_startTime, NULL); m_eventPending = true; m_currentEvent = evt->event(); + m_currentTS = evt->ts(); + m_currentTS_i = true; } - - if (m_eventPending) + else { - if (evt->event() != m_currentEvent) + if ((evt->event() != m_currentEvent) || + (m_currentTS_i && (evt->ts() != m_currentTS))) { // Previous event does not end correctly so send out it now... - sendPending(); + sendPending(true); // ... and reinitialize to process current event gettimeofday(&m_startTime, NULL); m_eventPending = true; m_currentEvent = evt->event(); + m_currentTS = evt->ts(); + m_currentTS_i = true; } - if (evt->e()) - { - sendPending(); - } - } - if (m_eventPending) - { - m_keysink->registerKeyPressed(m_currentEvent, Dtmf::SOURCE_RTP); } + m_keysink->registerKeyPressed(m_currentEvent, Dtmf::SOURCE_RTP); } } -void AmRtpDtmfDetector::sendPending() +void AmRtpDtmfDetector::sendPending(bool flush) { if (m_eventPending) { struct timeval end_time; gettimeofday(&end_time, NULL); - m_keysink->registerKeyReleased(m_currentEvent, Dtmf::SOURCE_RTP, m_startTime, end_time); + m_keysink->registerKeyReleased(m_currentEvent, Dtmf::SOURCE_RTP, m_startTime, end_time, flush); m_eventPending = false; + m_currentTS_i = false; + m_lastTS = m_currentTS; + m_lastTS_i = true; } } diff --git a/core/AmDtmfDetector.h b/core/AmDtmfDetector.h index e03f78dd..5bef4862 100644 --- a/core/AmDtmfDetector.h +++ b/core/AmDtmfDetector.h @@ -129,9 +129,10 @@ class AmKeyPressSink { * @param source which detector posted this event * @param start time when key was pressed * @param stop time when key was released + * @param flush whether key should be registered as own keypress immediately */ virtual void registerKeyReleased(int event, Dtmf::EventSource source, - const struct timeval& start, const struct timeval& stop) = 0; + const struct timeval& start, const struct timeval& stop, bool flush=false) = 0; /** * Through this method the AmDtmfDetector receives events that was * detected by specific detectors. @@ -156,13 +157,18 @@ class AmRtpDtmfEvent : public AmDtmfEvent */ int m_volume; + /** + * RTP timestamp + */ + unsigned int m_ts; + public: /** * Constructor * @param payload data from rtp packet of payload type telephone-event * @param sample_rate sampling rate (from SDP payload description) */ - AmRtpDtmfEvent(const dtmf_payload_t *payload, int sample_rate); + AmRtpDtmfEvent(const dtmf_payload_t *payload, int sample_rate, unsigned int ts); /** * Volume value from RTP packet @@ -172,6 +178,8 @@ class AmRtpDtmfEvent : public AmDtmfEvent * E flag from RTP packet */ int e() { return m_e; } + + unsigned int ts() { return m_ts; } }; /** @@ -328,9 +336,16 @@ class AmRtpDtmfDetector */ bool m_eventPending; int m_currentEvent; + unsigned int m_currentTS; + bool m_currentTS_i; int m_packetCount; - static const int MAX_PACKET_WAIT = 3; + unsigned int m_lastTS; + bool m_lastTS_i; + + // after MAX_PACKET_WAIT packets with no RTP DTMF packets received, + // a RTP DTMF event is sent out to the aggregating detector + static const int MAX_PACKET_WAIT = 5; /** * Time when first packet for current event was received */ @@ -339,7 +354,7 @@ class AmRtpDtmfDetector /** * Send out pending event */ - void sendPending(); + void sendPending(bool flush=false); public: /** @@ -404,9 +419,11 @@ class AmDtmfDetector * @param source which detector posted this event * @param start time when key was pressed * @param stop time when key was released + * @param flush whether key should be registered as own keypress immediately */ void registerKeyReleased(int event, Dtmf::EventSource source, - const struct timeval& start, const struct timeval& stop); + const struct timeval& start, const struct timeval& stop, + bool flush=false); /** * Through this method the AmDtmfDetector receives events that was * detected by specific detectors. diff --git a/core/AmRtpStream.cpp b/core/AmRtpStream.cpp index c563926d..60e683d2 100644 --- a/core/AmRtpStream.cpp +++ b/core/AmRtpStream.cpp @@ -319,9 +319,9 @@ int AmRtpStream::receive( unsigned char* buffer, unsigned int size, { dtmf_payload_t* dpl = (dtmf_payload_t*)rp->getData(); - DBG("DTMF: event=%i; e=%i; r=%i; volume=%i; duration=%i\n", - dpl->event,dpl->e,dpl->r,dpl->volume,ntohs(dpl->duration)); - session->postDtmfEvent(new AmRtpDtmfEvent(dpl, getTelephoneEventRate())); + DBG("DTMF: event=%i; e=%i; r=%i; volume=%i; duration=%i; ts=%u\n", + dpl->event,dpl->e,dpl->r,dpl->volume,ntohs(dpl->duration),rp->timestamp); + session->postDtmfEvent(new AmRtpDtmfEvent(dpl, getTelephoneEventRate(), rp->timestamp)); mem.freePacket(rp); return RTP_DTMF; }