LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_coding/neteq - dtmf_buffer.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 96 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/modules/audio_coding/neteq/dtmf_buffer.h"
      12             : 
      13             : #include <assert.h>
      14             : #include <algorithm>  // max
      15             : 
      16             : #include "webrtc/base/checks.h"
      17             : #include "webrtc/base/logging.h"
      18             : 
      19             : // Modify the code to obtain backwards bit-exactness. Once bit-exactness is no
      20             : // longer required, this #define should be removed (and the code that it
      21             : // enables).
      22             : #define LEGACY_BITEXACT
      23             : 
      24             : namespace webrtc {
      25             : 
      26           0 : DtmfBuffer::DtmfBuffer(int fs_hz) {
      27           0 :   SetSampleRate(fs_hz);
      28           0 : }
      29             : 
      30             : DtmfBuffer::~DtmfBuffer() = default;
      31             : 
      32           0 : void DtmfBuffer::Flush() {
      33           0 :   buffer_.clear();
      34           0 : }
      35             : 
      36             : // The ParseEvent method parses 4 bytes from |payload| according to this format
      37             : // from RFC 4733:
      38             : //
      39             : //  0                   1                   2                   3
      40             : //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      41             : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      42             : // |     event     |E|R| volume    |          duration             |
      43             : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      44             : //
      45             : // Legend (adapted from RFC 4733)
      46             : // - event:    The event field is a number between 0 and 255 identifying a
      47             : //             specific telephony event. The buffer will not accept any event
      48             : //             numbers larger than 15.
      49             : // - E:        If set to a value of one, the "end" bit indicates that this
      50             : //             packet contains the end of the event.  For long-lasting events
      51             : //             that have to be split into segments, only the final packet for
      52             : //             the final segment will have the E bit set.
      53             : // - R:        Reserved.
      54             : // - volume:   For DTMF digits and other events representable as tones, this
      55             : //             field describes the power level of the tone, expressed in dBm0
      56             : //             after dropping the sign.  Power levels range from 0 to -63 dBm0.
      57             : //             Thus, larger values denote lower volume. The buffer discards
      58             : //             values larger than 36 (i.e., lower than -36 dBm0).
      59             : // - duration: The duration field indicates the duration of the event or segment
      60             : //             being reported, in timestamp units, expressed as an unsigned
      61             : //             integer in network byte order.  For a non-zero value, the event
      62             : //             or segment began at the instant identified by the RTP timestamp
      63             : //             and has so far lasted as long as indicated by this parameter.
      64             : //             The event may or may not have ended.  If the event duration
      65             : //             exceeds the maximum representable by the duration field, the
      66             : //             event is split into several contiguous segments. The buffer will
      67             : //             discard zero-duration events.
      68             : //
      69           0 : int DtmfBuffer::ParseEvent(uint32_t rtp_timestamp,
      70             :                            const uint8_t* payload,
      71             :                            size_t payload_length_bytes,
      72             :                            DtmfEvent* event) {
      73           0 :   RTC_CHECK(payload);
      74           0 :   RTC_CHECK(event);
      75           0 :   if (payload_length_bytes < 4) {
      76           0 :     LOG(LS_WARNING) << "ParseEvent payload too short";
      77           0 :     return kPayloadTooShort;
      78             :   }
      79             : 
      80           0 :   event->event_no = payload[0];
      81           0 :   event->end_bit = ((payload[1] & 0x80) != 0);
      82           0 :   event->volume = (payload[1] & 0x3F);
      83           0 :   event->duration = payload[2] << 8 | payload[3];
      84           0 :   event->timestamp = rtp_timestamp;
      85           0 :   return kOK;
      86             : }
      87             : 
      88             : // Inserts a DTMF event into the buffer. The event should be parsed from the
      89             : // bit stream using the ParseEvent method above before inserting it in the
      90             : // buffer.
      91             : // DTMF events can be quite long, and in most cases the duration of the event
      92             : // is not known when the first packet describing it is sent. To deal with that,
      93             : // the RFC 4733 specifies that multiple packets are sent for one and the same
      94             : // event as it is being created (typically, as the user is pressing the key).
      95             : // These packets will all share the same start timestamp and event number,
      96             : // while the duration will be the cumulative duration from the start. When
      97             : // inserting a new event, the InsertEvent method tries to find a matching event
      98             : // already in the buffer. If so, the new event is simply merged with the
      99             : // existing one.
     100           0 : int DtmfBuffer::InsertEvent(const DtmfEvent& event) {
     101           0 :   if (event.event_no < 0 || event.event_no > 15 ||
     102           0 :       event.volume < 0 || event.volume > 63 ||
     103           0 :       event.duration <= 0 || event.duration > 65535) {
     104           0 :     LOG(LS_WARNING) << "InsertEvent invalid parameters";
     105           0 :     return kInvalidEventParameters;
     106             :   }
     107           0 :   DtmfList::iterator it = buffer_.begin();
     108           0 :   while (it != buffer_.end()) {
     109           0 :     if (MergeEvents(it, event)) {
     110             :       // A matching event was found and the new event was merged.
     111           0 :       return kOK;
     112             :     }
     113           0 :     ++it;
     114             :   }
     115           0 :   buffer_.push_back(event);
     116             :   // Sort the buffer using CompareEvents to rank the events.
     117           0 :   buffer_.sort(CompareEvents);
     118           0 :   return kOK;
     119             : }
     120             : 
     121           0 : bool DtmfBuffer::GetEvent(uint32_t current_timestamp, DtmfEvent* event) {
     122           0 :   DtmfList::iterator it = buffer_.begin();
     123           0 :   while (it != buffer_.end()) {
     124             :     // |event_end| is an estimate of where the current event ends. If the end
     125             :     // bit is set, we know that the event ends at |timestamp| + |duration|.
     126           0 :     uint32_t event_end = it->timestamp + it->duration;
     127             : #ifdef LEGACY_BITEXACT
     128           0 :     bool next_available = false;
     129             : #endif
     130           0 :     if (!it->end_bit) {
     131             :       // If the end bit is not set, we allow extrapolation of the event for
     132             :       // some time.
     133           0 :       event_end += max_extrapolation_samples_;
     134           0 :       DtmfList::iterator next = it;
     135           0 :       ++next;
     136           0 :       if (next != buffer_.end()) {
     137             :         // If there is a next event in the buffer, we will not extrapolate over
     138             :         // the start of that new event.
     139           0 :         event_end = std::min(event_end, next->timestamp);
     140             : #ifdef LEGACY_BITEXACT
     141           0 :         next_available = true;
     142             : #endif
     143             :       }
     144             :     }
     145           0 :     if (current_timestamp >= it->timestamp
     146           0 :         && current_timestamp <= event_end) {  // TODO(hlundin): Change to <.
     147             :       // Found a matching event.
     148           0 :       if (event) {
     149           0 :         event->event_no = it->event_no;
     150           0 :         event->end_bit = it->end_bit;
     151           0 :         event->volume = it->volume;
     152           0 :         event->duration = it->duration;
     153           0 :         event->timestamp = it->timestamp;
     154             :       }
     155             : #ifdef LEGACY_BITEXACT
     156           0 :       if (it->end_bit &&
     157           0 :           current_timestamp + frame_len_samples_ >= event_end) {
     158             :         // We are done playing this. Erase the event.
     159           0 :         buffer_.erase(it);
     160             :       }
     161             : #endif
     162           0 :       return true;
     163           0 :     } else if (current_timestamp > event_end) {  // TODO(hlundin): Change to >=.
     164             :       // Erase old event. Operation returns a valid pointer to the next element
     165             :       // in the list.
     166             : #ifdef LEGACY_BITEXACT
     167           0 :       if (!next_available) {
     168           0 :         if (event) {
     169           0 :           event->event_no = it->event_no;
     170           0 :           event->end_bit = it->end_bit;
     171           0 :           event->volume = it->volume;
     172           0 :           event->duration = it->duration;
     173           0 :           event->timestamp = it->timestamp;
     174             :         }
     175           0 :         it = buffer_.erase(it);
     176           0 :         return true;
     177             :       } else {
     178           0 :         it = buffer_.erase(it);
     179             :       }
     180             : #else
     181             :       it = buffer_.erase(it);
     182             : #endif
     183             :     } else {
     184           0 :       ++it;
     185             :     }
     186             :   }
     187           0 :   return false;
     188             : }
     189             : 
     190           0 : size_t DtmfBuffer::Length() const {
     191           0 :   return buffer_.size();
     192             : }
     193             : 
     194           0 : bool DtmfBuffer::Empty() const {
     195           0 :   return buffer_.empty();
     196             : }
     197             : 
     198           0 : int DtmfBuffer::SetSampleRate(int fs_hz) {
     199           0 :   if (fs_hz != 8000 &&
     200           0 :       fs_hz != 16000 &&
     201           0 :       fs_hz != 32000 &&
     202           0 :       fs_hz != 44100 &&
     203             :       fs_hz != 48000) {
     204           0 :     return kInvalidSampleRate;
     205             :   }
     206           0 :   max_extrapolation_samples_ = 7 * fs_hz / 100;
     207           0 :   frame_len_samples_ = fs_hz / 100;
     208           0 :   return kOK;
     209             : }
     210             : 
     211             : // The method returns true if the two events are considered to be the same.
     212             : // The are defined as equal if they share the same timestamp and event number.
     213             : // The special case with long-lasting events that have to be split into segments
     214             : // is not handled in this method. These will be treated as separate events in
     215             : // the buffer.
     216           0 : bool DtmfBuffer::SameEvent(const DtmfEvent& a, const DtmfEvent& b) {
     217           0 :   return (a.event_no == b.event_no) && (a.timestamp == b.timestamp);
     218             : }
     219             : 
     220           0 : bool DtmfBuffer::MergeEvents(DtmfList::iterator it, const DtmfEvent& event) {
     221           0 :   if (SameEvent(*it, event)) {
     222           0 :     if (!it->end_bit) {
     223             :       // Do not extend the duration of an event for which the end bit was
     224             :       // already received.
     225           0 :       it->duration = std::max(event.duration, it->duration);
     226             :     }
     227           0 :     if (event.end_bit) {
     228           0 :       it->end_bit = true;
     229             :     }
     230           0 :     return true;
     231             :   } else {
     232           0 :     return false;
     233             :   }
     234             : }
     235             : 
     236             : // Returns true if |a| goes before |b| in the sorting order ("|a| < |b|").
     237             : // The events are ranked using their start timestamp (taking wrap-around into
     238             : // account). In the unlikely situation that two events share the same start
     239             : // timestamp, the event number is used to rank the two. Note that packets
     240             : // that belong to the same events, and therefore sharing the same start
     241             : // timestamp, have already been merged before the sort method is called.
     242           0 : bool DtmfBuffer::CompareEvents(const DtmfEvent& a, const DtmfEvent& b) {
     243           0 :   if (a.timestamp == b.timestamp) {
     244           0 :     return a.event_no < b.event_no;
     245             :   }
     246             :   // Take wrap-around into account.
     247           0 :   return (static_cast<uint32_t>(b.timestamp - a.timestamp) < 0xFFFFFFFF / 2);
     248             : }
     249             : }  // namespace webrtc

Generated by: LCOV version 1.13