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
18namespace webrtc {
19
20const int16_t Dtmf_a_times2Tab8Khz[8]=
21{
22	27978, 26956, 25701, 24219,
23	19073, 16325, 13085, 9314
24};
25
26const int16_t Dtmf_a_times2Tab16Khz[8]=
27{
28	31548, 31281, 30951, 30556,
29	29144, 28361, 27409, 26258
30};
31
32const 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
39const int16_t Dtmf_ym2Tab8Khz[8]=
40{
41	8527, 9315, 10163, 11036,
42	13322, 14206, 15021, 15708
43};
44
45const int16_t Dtmf_ym2Tab16Khz[8]=
46{
47	4429, 4879, 5380, 5918,
48	7490, 8207, 8979, 9801
49};
50
51const int16_t Dtmf_ym2Tab32Khz[8]=
52{
53	2235, 2468, 2728, 3010, 3853, 4249, 4685, 5164
54};
55
56const 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
68DtmfInband::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
85DtmfInband::~DtmfInband()
86{
87	delete &_critSect;
88}
89
90int
91DtmfInband::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
105int
106DtmfInband::GetSampleRate(uint16_t& frequency)
107{
108    frequency = _outputFrequencyHz;
109    return 0;
110}
111
112void
113DtmfInband::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
128int
129DtmfInband::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
159int
160DtmfInband::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
173int
174DtmfInband::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
200int
201DtmfInband::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
216void
217DtmfInband::ReInit()
218{
219    _reinit = true;
220}
221
222bool
223DtmfInband::IsAddingTone()
224{
225    CriticalSectionScoped lock(&_critSect);
226    return (_remainingSamples > 0 || _playing);
227}
228
229int
230DtmfInband::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
248void
249DtmfInband::UpdateDelaySinceLastTone()
250{
251    _delaySinceLastToneMS += kDtmfFrameSizeMs;
252    // avoid wraparound
253    if (_delaySinceLastToneMS > (1<<30))
254    {
255        _delaySinceLastToneMS = 1000;
256    }
257}
258
259uint32_t
260DtmfInband::DelaySinceLastTone() const
261{
262    return _delaySinceLastToneMS;
263}
264
265int16_t
266DtmfInband::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
351int16_t
352DtmfInband::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