tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dtmf_buffer.cc (9258B)


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