Home | History | Annotate | Download | only in voice_engine
      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 
     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 
     85 DtmfInband::~DtmfInband()
     86 {
     87 	delete &_critSect;
     88 }
     89 
     90 int
     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
    106 DtmfInband::GetSampleRate(uint16_t& frequency)
    107 {
    108     frequency = _outputFrequencyHz;
    109     return 0;
    110 }
    111 
    112 void
    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
    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
    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
    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
    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
    217 DtmfInband::ReInit()
    218 {
    219     _reinit = true;
    220 }
    221 
    222 bool
    223 DtmfInband::IsAddingTone()
    224 {
    225     CriticalSectionScoped lock(&_critSect);
    226     return (_remainingSamples > 0 || _playing);
    227 }
    228 
    229 int
    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
    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
    260 DtmfInband::DelaySinceLastTone() const
    261 {
    262     return _delaySinceLastToneMS;
    263 }
    264 
    265 int16_t
    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
    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