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