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