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
|