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