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/voice_engine/dtmf_inband.h"
12 
13 #include <assert.h>
14 
15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
16 #include "webrtc/system_wrappers/include/trace.h"
17 
18 namespace webrtc {
19 
20 const int16_t Dtmf_a_times2Tab8Khz[8]=
21 {
22 	27978, 26956, 25701, 24219,
23 	19073, 16325, 13085, 9314
24 };
25 
26 const int16_t Dtmf_a_times2Tab16Khz[8]=
27 {
28 	31548, 31281, 30951, 30556,
29 	29144, 28361, 27409, 26258
30 };
31 
32 const int16_t Dtmf_a_times2Tab32Khz[8]=
33 {
34 	32462,32394, 32311, 32210, 31849, 31647, 31400, 31098
35 };
36 
37 // Second table is sin(2*pi*f/fs) in Q14
38 
39 const int16_t Dtmf_ym2Tab8Khz[8]=
40 {
41 	8527, 9315, 10163, 11036,
42 	13322, 14206, 15021, 15708
43 };
44 
45 const int16_t Dtmf_ym2Tab16Khz[8]=
46 {
47 	4429, 4879, 5380, 5918,
48 	7490, 8207, 8979, 9801
49 };
50 
51 const int16_t Dtmf_ym2Tab32Khz[8]=
52 {
53 	2235, 2468, 2728, 3010, 3853, 4249, 4685, 5164
54 };
55 
56 const int16_t Dtmf_dBm0kHz[37]=
57 {
58        16141,      14386,      12821,      11427,      10184,       9077,
59         8090,       7210,       6426,       5727,       5104,       4549,
60         4054,       3614,       3221,       2870,       2558,       2280,
61         2032,       1811,       1614,       1439,       1282,       1143,
62         1018,        908,        809,        721,        643,        573,
63          510,        455,        405,        361,        322,        287,
64 		 256
65 };
66 
67 
DtmfInband(int32_t id)68 DtmfInband::DtmfInband(int32_t id) :
69     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
70     _id(id),
71     _outputFrequencyHz(8000),
72     _frameLengthSamples(0),
73     _remainingSamples(0),
74     _eventCode(0),
75     _attenuationDb(0),
76     _lengthMs(0),
77     _reinit(true),
78     _playing(false),
79     _delaySinceLastToneMS(1000)
80 {
81     memset(_oldOutputLow, 0, sizeof(_oldOutputLow));
82     memset(_oldOutputHigh, 0, sizeof(_oldOutputHigh));
83 }
84 
~DtmfInband()85 DtmfInband::~DtmfInband()
86 {
87 	delete &_critSect;
88 }
89 
90 int
SetSampleRate(uint16_t frequency)91 DtmfInband::SetSampleRate(uint16_t frequency)
92 {
93     if (frequency != 8000 &&
94             frequency != 16000 &&
95             frequency != 32000)
96     {
97         // invalid sample rate
98         assert(false);
99         return -1;
100     }
101     _outputFrequencyHz = frequency;
102     return 0;
103 }
104 
105 int
GetSampleRate(uint16_t & frequency)106 DtmfInband::GetSampleRate(uint16_t& frequency)
107 {
108     frequency = _outputFrequencyHz;
109     return 0;
110 }
111 
112 void
Init()113 DtmfInband::Init()
114 {
115     _remainingSamples = 0;
116     _frameLengthSamples = 0;
117     _eventCode = 0;
118     _attenuationDb = 0;
119     _lengthMs = 0;
120     _reinit = true;
121     _oldOutputLow[0] = 0;
122     _oldOutputLow[1] = 0;
123     _oldOutputHigh[0] = 0;
124     _oldOutputHigh[1] = 0;
125     _delaySinceLastToneMS = 1000;
126 }
127 
128 int
AddTone(uint8_t eventCode,int32_t lengthMs,int32_t attenuationDb)129 DtmfInband::AddTone(uint8_t eventCode,
130                     int32_t lengthMs,
131                     int32_t attenuationDb)
132 {
133     CriticalSectionScoped lock(&_critSect);
134 
135     if (attenuationDb > 36 || eventCode > 15)
136     {
137         assert(false);
138         return -1;
139     }
140 
141     if (IsAddingTone())
142     {
143         WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_id,-1),
144                    "DtmfInband::AddTone() new tone interrupts ongoing tone");
145     }
146 
147     ReInit();
148 
149     _frameLengthSamples = static_cast<int16_t> (_outputFrequencyHz / 100);
150     _eventCode = static_cast<int16_t> (eventCode);
151     _attenuationDb = static_cast<int16_t> (attenuationDb);
152     _remainingSamples = static_cast<int32_t>
153         (lengthMs * (_outputFrequencyHz / 1000));
154     _lengthMs = lengthMs;
155 
156     return 0;
157 }
158 
159 int
ResetTone()160 DtmfInband::ResetTone()
161 {
162     CriticalSectionScoped lock(&_critSect);
163 
164     ReInit();
165 
166     _frameLengthSamples = static_cast<int16_t> (_outputFrequencyHz / 100);
167     _remainingSamples = static_cast<int32_t>
168         (_lengthMs * (_outputFrequencyHz / 1000));
169 
170     return 0;
171 }
172 
173 int
StartTone(uint8_t eventCode,int32_t attenuationDb)174 DtmfInband::StartTone(uint8_t eventCode,
175                       int32_t attenuationDb)
176 {
177     CriticalSectionScoped lock(&_critSect);
178 
179     if (attenuationDb > 36 || eventCode > 15)
180     {
181         assert(false);
182         return -1;
183     }
184 
185     if (IsAddingTone())
186     {
187             return -1;
188     }
189 
190     ReInit();
191 
192     _frameLengthSamples = static_cast<int16_t> (_outputFrequencyHz / 100);
193     _eventCode = static_cast<int16_t> (eventCode);
194     _attenuationDb = static_cast<int16_t> (attenuationDb);
195     _playing = true;
196 
197     return 0;
198 }
199 
200 int
StopTone()201 DtmfInband::StopTone()
202 {
203     CriticalSectionScoped lock(&_critSect);
204 
205     if (!_playing)
206     {
207         return 0;
208     }
209 
210     _playing = false;
211 
212     return 0;
213 }
214 
215 // Shall be called between tones
216 void
ReInit()217 DtmfInband::ReInit()
218 {
219     _reinit = true;
220 }
221 
222 bool
IsAddingTone()223 DtmfInband::IsAddingTone()
224 {
225     CriticalSectionScoped lock(&_critSect);
226     return (_remainingSamples > 0 || _playing);
227 }
228 
229 int
Get10msTone(int16_t output[320],uint16_t & outputSizeInSamples)230 DtmfInband::Get10msTone(int16_t output[320],
231                         uint16_t& outputSizeInSamples)
232 {
233     CriticalSectionScoped lock(&_critSect);
234     if (DtmfFix_generate(output,
235                          _eventCode,
236                          _attenuationDb,
237                          _frameLengthSamples,
238                          _outputFrequencyHz) == -1)
239     {
240         return -1;
241     }
242     _remainingSamples -= _frameLengthSamples;
243     outputSizeInSamples = _frameLengthSamples;
244     _delaySinceLastToneMS = 0;
245     return 0;
246 }
247 
248 void
UpdateDelaySinceLastTone()249 DtmfInband::UpdateDelaySinceLastTone()
250 {
251     _delaySinceLastToneMS += kDtmfFrameSizeMs;
252     // avoid wraparound
253     if (_delaySinceLastToneMS > (1<<30))
254     {
255         _delaySinceLastToneMS = 1000;
256     }
257 }
258 
259 uint32_t
DelaySinceLastTone() const260 DtmfInband::DelaySinceLastTone() const
261 {
262     return _delaySinceLastToneMS;
263 }
264 
265 int16_t
DtmfFix_generate(int16_t * decoded,int16_t value,int16_t volume,int16_t frameLen,int16_t fs)266 DtmfInband::DtmfFix_generate(int16_t *decoded,
267                              int16_t value,
268                              int16_t volume,
269                              int16_t frameLen,
270                              int16_t fs)
271 {
272     const int16_t *a_times2Tbl;
273     const int16_t *y2_Table;
274     int16_t a1_times2 = 0, a2_times2 = 0;
275 
276     if (fs==8000) {
277         a_times2Tbl=Dtmf_a_times2Tab8Khz;
278         y2_Table=Dtmf_ym2Tab8Khz;
279     } else if (fs==16000) {
280         a_times2Tbl=Dtmf_a_times2Tab16Khz;
281         y2_Table=Dtmf_ym2Tab16Khz;
282     } else if (fs==32000) {
283         a_times2Tbl=Dtmf_a_times2Tab32Khz;
284         y2_Table=Dtmf_ym2Tab32Khz;
285     } else {
286         return(-1);
287     }
288 
289     if ((value==1)||(value==2)||(value==3)||(value==12)) {
290         a1_times2=a_times2Tbl[0];
291         if (_reinit) {
292             _oldOutputLow[0]=y2_Table[0];
293             _oldOutputLow[1]=0;
294         }
295     } else if ((value==4)||(value==5)||(value==6)||(value==13)) {
296         a1_times2=a_times2Tbl[1];
297         if (_reinit) {
298             _oldOutputLow[0]=y2_Table[1];
299             _oldOutputLow[1]=0;
300         }
301     } else if ((value==7)||(value==8)||(value==9)||(value==14)) {
302         a1_times2=a_times2Tbl[2];
303         if (_reinit) {
304             _oldOutputLow[0]=y2_Table[2];
305             _oldOutputLow[1]=0;
306         }
307     } else if ((value==10)||(value==0)||(value==11)||(value==15)) {
308         a1_times2=a_times2Tbl[3];
309         if (_reinit) {
310             _oldOutputLow[0]=y2_Table[3];
311             _oldOutputLow[1]=0;
312         }
313     }
314     if ((value==1)||(value==4)||(value==7)||(value==10)) {
315         a2_times2=a_times2Tbl[4];
316         if (_reinit) {
317             _oldOutputHigh[0]=y2_Table[4];
318             _oldOutputHigh[1]=0;
319             _reinit=false;
320         }
321     } else if ((value==2)||(value==5)||(value==8)||(value==0)) {
322         a2_times2=a_times2Tbl[5];
323         if (_reinit) {
324             _oldOutputHigh[0]=y2_Table[5];
325             _oldOutputHigh[1]=0;
326             _reinit=false;
327         }
328     } else if ((value==3)||(value==6)||(value==9)||(value==11)) {
329         a2_times2=a_times2Tbl[6];
330         if (_reinit) {
331             _oldOutputHigh[0]=y2_Table[6];
332             _oldOutputHigh[1]=0;
333             _reinit=false;
334         }
335     } else if ((value==12)||(value==13)||(value==14)||(value==15)) {
336         a2_times2=a_times2Tbl[7];
337         if (_reinit) {
338             _oldOutputHigh[0]=y2_Table[7];
339             _oldOutputHigh[1]=0;
340             _reinit=false;
341         }
342     }
343 
344     return (DtmfFix_generateSignal(a1_times2,
345                                    a2_times2,
346                                    volume,
347                                    decoded,
348                                    frameLen));
349 }
350 
351 int16_t
DtmfFix_generateSignal(int16_t a1_times2,int16_t a2_times2,int16_t volume,int16_t * signal,int16_t length)352 DtmfInband::DtmfFix_generateSignal(int16_t a1_times2,
353                                    int16_t a2_times2,
354                                    int16_t volume,
355                                    int16_t *signal,
356                                    int16_t length)
357 {
358     int i;
359 
360     /* Generate Signal */
361     for (i=0;i<length;i++) {
362         int32_t tempVal;
363         int16_t tempValLow, tempValHigh;
364 
365         /* Use recursion formula y[n] = a*2*y[n-1] - y[n-2] */
366         tempValLow  = (int16_t)(((( (int32_t)(a1_times2 *
367             _oldOutputLow[1])) + 8192) >> 14) - _oldOutputLow[0]);
368         tempValHigh = (int16_t)(((( (int32_t)(a2_times2 *
369             _oldOutputHigh[1])) + 8192) >> 14) - _oldOutputHigh[0]);
370 
371         /* Update memory */
372         _oldOutputLow[0]=_oldOutputLow[1];
373         _oldOutputLow[1]=tempValLow;
374         _oldOutputHigh[0]=_oldOutputHigh[1];
375         _oldOutputHigh[1]=tempValHigh;
376 
377         tempVal = (int32_t)(kDtmfAmpLow * tempValLow) +
378             (int32_t)(kDtmfAmpHigh * tempValHigh);
379 
380         /* Norm the signal to Q14 */
381         tempVal=(tempVal+16384)>>15;
382 
383         /* Scale the signal to correct dbM0 value */
384         signal[i]=(int16_t)((tempVal*Dtmf_dBm0kHz[volume]+8192)>>14);
385     }
386 
387     return(0);
388 }
389 
390 }  // namespace webrtc
391