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