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