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