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