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
DtmfBuffer(int fs_hz)26 DtmfBuffer::DtmfBuffer(int fs_hz) {
27 SetSampleRate(fs_hz);
28 }
29
30 DtmfBuffer::~DtmfBuffer() = default;
31
Flush()32 void DtmfBuffer::Flush() {
33 buffer_.clear();
34 }
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 //
ParseEvent(uint32_t rtp_timestamp,const uint8_t * payload,size_t payload_length_bytes,DtmfEvent * event)69 int DtmfBuffer::ParseEvent(uint32_t rtp_timestamp,
70 const uint8_t* payload,
71 size_t payload_length_bytes,
72 DtmfEvent* event) {
73 RTC_CHECK(payload);
74 RTC_CHECK(event);
75 if (payload_length_bytes < 4) {
76 LOG(LS_WARNING) << "ParseEvent payload too short";
77 return kPayloadTooShort;
78 }
79
80 event->event_no = payload[0];
81 event->end_bit = ((payload[1] & 0x80) != 0);
82 event->volume = (payload[1] & 0x3F);
83 event->duration = payload[2] << 8 | payload[3];
84 event->timestamp = rtp_timestamp;
85 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.
InsertEvent(const DtmfEvent & event)100 int DtmfBuffer::InsertEvent(const DtmfEvent& event) {
101 if (event.event_no < 0 || event.event_no > 15 ||
102 event.volume < 0 || event.volume > 36 ||
103 event.duration <= 0 || event.duration > 65535) {
104 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
GetEvent(uint32_t current_timestamp,DtmfEvent * event)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 &&
157 current_timestamp + frame_len_samples_ >= event_end) {
158 // We are done playing this. Erase the event.
159 buffer_.erase(it);
160 }
161 #endif
162 return true;
163 } 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 if (!next_available) {
168 if (event) {
169 event->event_no = it->event_no;
170 event->end_bit = it->end_bit;
171 event->volume = it->volume;
172 event->duration = it->duration;
173 event->timestamp = it->timestamp;
174 }
175 it = buffer_.erase(it);
176 return true;
177 } else {
178 it = buffer_.erase(it);
179 }
180 #else
181 it = buffer_.erase(it);
182 #endif
183 } else {
184 ++it;
185 }
186 }
187 return false;
188 }
189
Length() const190 size_t DtmfBuffer::Length() const {
191 return buffer_.size();
192 }
193
Empty() const194 bool DtmfBuffer::Empty() const {
195 return buffer_.empty();
196 }
197
SetSampleRate(int fs_hz)198 int DtmfBuffer::SetSampleRate(int fs_hz) {
199 if (fs_hz != 8000 &&
200 fs_hz != 16000 &&
201 fs_hz != 32000 &&
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.
SameEvent(const DtmfEvent & a,const DtmfEvent & b)215 bool DtmfBuffer::SameEvent(const DtmfEvent& a, const DtmfEvent& b) {
216 return (a.event_no == b.event_no) && (a.timestamp == b.timestamp);
217 }
218
MergeEvents(DtmfList::iterator it,const DtmfEvent & event)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.
CompareEvents(const DtmfEvent & a,const DtmfEvent & b)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
249