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 /* analog_agc.c
12 *
13 * Using a feedback system, determines an appropriate analog volume level
14 * given an input signal and current volume level. Targets a conservative
15 * signal level and is intended for use with a digital AGC to apply
16 * additional gain.
17 *
18 */
19
20 #include "webrtc/modules/audio_processing/agc/legacy/analog_agc.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #ifdef WEBRTC_AGC_DEBUG_DUMP
25 #include <stdio.h>
26 #endif
27
28 /* The slope of in Q13*/
29 static const int16_t kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78};
30
31 /* The offset in Q14 */
32 static const int16_t kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951,
33 17367};
34
35 /* The slope of in Q13*/
36 static const int16_t kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337};
37
38 /* The offset in Q14 */
39 static const int16_t kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670,
40 17286};
41
42 static const int16_t kMuteGuardTimeMs = 8000;
43 static const int16_t kInitCheck = 42;
44 static const size_t kNumSubframes = 10;
45
46 /* Default settings if config is not used */
47 #define AGC_DEFAULT_TARGET_LEVEL 3
48 #define AGC_DEFAULT_COMP_GAIN 9
49 /* This is the target level for the analog part in ENV scale. To convert to RMS scale you
50 * have to add OFFSET_ENV_TO_RMS.
51 */
52 #define ANALOG_TARGET_LEVEL 11
53 #define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2
54 /* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually
55 * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with
56 * a table.
57 */
58 #define OFFSET_ENV_TO_RMS 9
59 /* The reference input level at which the digital part gives an output of targetLevelDbfs
60 * (desired level) if we have no compression gain. This level should be set high enough not
61 * to compress the peaks due to the dynamics.
62 */
63 #define DIGITAL_REF_AT_0_COMP_GAIN 4
64 /* Speed of reference level decrease.
65 */
66 #define DIFF_REF_TO_ANALOG 5
67
68 #ifdef MIC_LEVEL_FEEDBACK
69 #define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7
70 #endif
71 /* Size of analog gain table */
72 #define GAIN_TBL_LEN 32
73 /* Matlab code:
74 * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12));
75 */
76 /* Q12 */
77 static const uint16_t kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752,
78 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992,
79 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953};
80
81 /* Gain/Suppression tables for virtual Mic (in Q10) */
82 static const uint16_t kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204,
83 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757,
84 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563,
85 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739,
86 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456,
87 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960,
88 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305,
89 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628,
90 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603,
91 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864,
92 30681, 31520, 32382};
93 static const uint16_t kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952,
94 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700,
95 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514,
96 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378,
97 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278,
98 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204,
99 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150,
100 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110,
101 108, 106, 104, 102};
102
103 /* Table for target energy levels. Values in Q(-7)
104 * Matlab code
105 * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */
106
107 static const int32_t kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106,
108 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642,
109 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095,
110 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210,
111 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468,
112 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268,
113 213, 169, 134, 107, 85, 67};
114
WebRtcAgc_AddMic(void * state,int16_t * const * in_mic,size_t num_bands,size_t samples)115 int WebRtcAgc_AddMic(void *state, int16_t* const* in_mic, size_t num_bands,
116 size_t samples)
117 {
118 int32_t nrg, max_nrg, sample, tmp32;
119 int32_t *ptr;
120 uint16_t targetGainIdx, gain;
121 size_t i;
122 int16_t n, L, tmp16, tmp_speech[16];
123 LegacyAgc* stt;
124 stt = (LegacyAgc*)state;
125
126 if (stt->fs == 8000) {
127 L = 8;
128 if (samples != 80) {
129 return -1;
130 }
131 } else {
132 L = 16;
133 if (samples != 160) {
134 return -1;
135 }
136 }
137
138 /* apply slowly varying digital gain */
139 if (stt->micVol > stt->maxAnalog)
140 {
141 /* |maxLevel| is strictly >= |micVol|, so this condition should be
142 * satisfied here, ensuring there is no divide-by-zero. */
143 assert(stt->maxLevel > stt->maxAnalog);
144
145 /* Q1 */
146 tmp16 = (int16_t)(stt->micVol - stt->maxAnalog);
147 tmp32 = (GAIN_TBL_LEN - 1) * tmp16;
148 tmp16 = (int16_t)(stt->maxLevel - stt->maxAnalog);
149 targetGainIdx = tmp32 / tmp16;
150 assert(targetGainIdx < GAIN_TBL_LEN);
151
152 /* Increment through the table towards the target gain.
153 * If micVol drops below maxAnalog, we allow the gain
154 * to be dropped immediately. */
155 if (stt->gainTableIdx < targetGainIdx)
156 {
157 stt->gainTableIdx++;
158 } else if (stt->gainTableIdx > targetGainIdx)
159 {
160 stt->gainTableIdx--;
161 }
162
163 /* Q12 */
164 gain = kGainTableAnalog[stt->gainTableIdx];
165
166 for (i = 0; i < samples; i++)
167 {
168 size_t j;
169 for (j = 0; j < num_bands; ++j)
170 {
171 sample = (in_mic[j][i] * gain) >> 12;
172 if (sample > 32767)
173 {
174 in_mic[j][i] = 32767;
175 } else if (sample < -32768)
176 {
177 in_mic[j][i] = -32768;
178 } else
179 {
180 in_mic[j][i] = (int16_t)sample;
181 }
182 }
183 }
184 } else
185 {
186 stt->gainTableIdx = 0;
187 }
188
189 /* compute envelope */
190 if (stt->inQueue > 0)
191 {
192 ptr = stt->env[1];
193 } else
194 {
195 ptr = stt->env[0];
196 }
197
198 for (i = 0; i < kNumSubframes; i++)
199 {
200 /* iterate over samples */
201 max_nrg = 0;
202 for (n = 0; n < L; n++)
203 {
204 nrg = in_mic[0][i * L + n] * in_mic[0][i * L + n];
205 if (nrg > max_nrg)
206 {
207 max_nrg = nrg;
208 }
209 }
210 ptr[i] = max_nrg;
211 }
212
213 /* compute energy */
214 if (stt->inQueue > 0)
215 {
216 ptr = stt->Rxx16w32_array[1];
217 } else
218 {
219 ptr = stt->Rxx16w32_array[0];
220 }
221
222 for (i = 0; i < kNumSubframes / 2; i++)
223 {
224 if (stt->fs == 16000)
225 {
226 WebRtcSpl_DownsampleBy2(&in_mic[0][i * 32],
227 32,
228 tmp_speech,
229 stt->filterState);
230 } else
231 {
232 memcpy(tmp_speech, &in_mic[0][i * 16], 16 * sizeof(short));
233 }
234 /* Compute energy in blocks of 16 samples */
235 ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4);
236 }
237
238 /* update queue information */
239 if (stt->inQueue == 0)
240 {
241 stt->inQueue = 1;
242 } else
243 {
244 stt->inQueue = 2;
245 }
246
247 /* call VAD (use low band only) */
248 WebRtcAgc_ProcessVad(&stt->vadMic, in_mic[0], samples);
249
250 return 0;
251 }
252
WebRtcAgc_AddFarend(void * state,const int16_t * in_far,size_t samples)253 int WebRtcAgc_AddFarend(void *state, const int16_t *in_far, size_t samples) {
254 LegacyAgc* stt = (LegacyAgc*)state;
255
256 int err = WebRtcAgc_GetAddFarendError(state, samples);
257
258 if (err != 0)
259 return err;
260
261 return WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, in_far, samples);
262 }
263
WebRtcAgc_GetAddFarendError(void * state,size_t samples)264 int WebRtcAgc_GetAddFarendError(void *state, size_t samples) {
265 LegacyAgc* stt;
266 stt = (LegacyAgc*)state;
267
268 if (stt == NULL)
269 return -1;
270
271 if (stt->fs == 8000) {
272 if (samples != 80)
273 return -1;
274 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000) {
275 if (samples != 160)
276 return -1;
277 } else {
278 return -1;
279 }
280
281 return 0;
282 }
283
WebRtcAgc_VirtualMic(void * agcInst,int16_t * const * in_near,size_t num_bands,size_t samples,int32_t micLevelIn,int32_t * micLevelOut)284 int WebRtcAgc_VirtualMic(void *agcInst, int16_t* const* in_near,
285 size_t num_bands, size_t samples, int32_t micLevelIn,
286 int32_t *micLevelOut)
287 {
288 int32_t tmpFlt, micLevelTmp, gainIdx;
289 uint16_t gain;
290 size_t ii, j;
291 LegacyAgc* stt;
292
293 uint32_t nrg;
294 size_t sampleCntr;
295 uint32_t frameNrg = 0;
296 uint32_t frameNrgLimit = 5500;
297 int16_t numZeroCrossing = 0;
298 const int16_t kZeroCrossingLowLim = 15;
299 const int16_t kZeroCrossingHighLim = 20;
300
301 stt = (LegacyAgc*)agcInst;
302
303 /*
304 * Before applying gain decide if this is a low-level signal.
305 * The idea is that digital AGC will not adapt to low-level
306 * signals.
307 */
308 if (stt->fs != 8000)
309 {
310 frameNrgLimit = frameNrgLimit << 1;
311 }
312
313 frameNrg = (uint32_t)(in_near[0][0] * in_near[0][0]);
314 for (sampleCntr = 1; sampleCntr < samples; sampleCntr++)
315 {
316
317 // increment frame energy if it is less than the limit
318 // the correct value of the energy is not important
319 if (frameNrg < frameNrgLimit)
320 {
321 nrg = (uint32_t)(in_near[0][sampleCntr] * in_near[0][sampleCntr]);
322 frameNrg += nrg;
323 }
324
325 // Count the zero crossings
326 numZeroCrossing +=
327 ((in_near[0][sampleCntr] ^ in_near[0][sampleCntr - 1]) < 0);
328 }
329
330 if ((frameNrg < 500) || (numZeroCrossing <= 5))
331 {
332 stt->lowLevelSignal = 1;
333 } else if (numZeroCrossing <= kZeroCrossingLowLim)
334 {
335 stt->lowLevelSignal = 0;
336 } else if (frameNrg <= frameNrgLimit)
337 {
338 stt->lowLevelSignal = 1;
339 } else if (numZeroCrossing >= kZeroCrossingHighLim)
340 {
341 stt->lowLevelSignal = 1;
342 } else
343 {
344 stt->lowLevelSignal = 0;
345 }
346
347 micLevelTmp = micLevelIn << stt->scale;
348 /* Set desired level */
349 gainIdx = stt->micVol;
350 if (stt->micVol > stt->maxAnalog)
351 {
352 gainIdx = stt->maxAnalog;
353 }
354 if (micLevelTmp != stt->micRef)
355 {
356 /* Something has happened with the physical level, restart. */
357 stt->micRef = micLevelTmp;
358 stt->micVol = 127;
359 *micLevelOut = 127;
360 stt->micGainIdx = 127;
361 gainIdx = 127;
362 }
363 /* Pre-process the signal to emulate the microphone level. */
364 /* Take one step at a time in the gain table. */
365 if (gainIdx > 127)
366 {
367 gain = kGainTableVirtualMic[gainIdx - 128];
368 } else
369 {
370 gain = kSuppressionTableVirtualMic[127 - gainIdx];
371 }
372 for (ii = 0; ii < samples; ii++)
373 {
374 tmpFlt = (in_near[0][ii] * gain) >> 10;
375 if (tmpFlt > 32767)
376 {
377 tmpFlt = 32767;
378 gainIdx--;
379 if (gainIdx >= 127)
380 {
381 gain = kGainTableVirtualMic[gainIdx - 127];
382 } else
383 {
384 gain = kSuppressionTableVirtualMic[127 - gainIdx];
385 }
386 }
387 if (tmpFlt < -32768)
388 {
389 tmpFlt = -32768;
390 gainIdx--;
391 if (gainIdx >= 127)
392 {
393 gain = kGainTableVirtualMic[gainIdx - 127];
394 } else
395 {
396 gain = kSuppressionTableVirtualMic[127 - gainIdx];
397 }
398 }
399 in_near[0][ii] = (int16_t)tmpFlt;
400 for (j = 1; j < num_bands; ++j)
401 {
402 tmpFlt = (in_near[j][ii] * gain) >> 10;
403 if (tmpFlt > 32767)
404 {
405 tmpFlt = 32767;
406 }
407 if (tmpFlt < -32768)
408 {
409 tmpFlt = -32768;
410 }
411 in_near[j][ii] = (int16_t)tmpFlt;
412 }
413 }
414 /* Set the level we (finally) used */
415 stt->micGainIdx = gainIdx;
416 // *micLevelOut = stt->micGainIdx;
417 *micLevelOut = stt->micGainIdx >> stt->scale;
418 /* Add to Mic as if it was the output from a true microphone */
419 if (WebRtcAgc_AddMic(agcInst, in_near, num_bands, samples) != 0)
420 {
421 return -1;
422 }
423 return 0;
424 }
425
WebRtcAgc_UpdateAgcThresholds(LegacyAgc * stt)426 void WebRtcAgc_UpdateAgcThresholds(LegacyAgc* stt) {
427 int16_t tmp16;
428 #ifdef MIC_LEVEL_FEEDBACK
429 int zeros;
430
431 if (stt->micLvlSat)
432 {
433 /* Lower the analog target level since we have reached its maximum */
434 zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32);
435 stt->targetIdxOffset = (3 * zeros - stt->targetIdx - 2) / 4;
436 }
437 #endif
438
439 /* Set analog target level in envelope dBOv scale */
440 tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2;
441 tmp16 = WebRtcSpl_DivW32W16ResW16((int32_t)tmp16, ANALOG_TARGET_LEVEL);
442 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16;
443 if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN)
444 {
445 stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN;
446 }
447 if (stt->agcMode == kAgcModeFixedDigital)
448 {
449 /* Adjust for different parameter interpretation in FixedDigital mode */
450 stt->analogTarget = stt->compressionGaindB;
451 }
452 #ifdef MIC_LEVEL_FEEDBACK
453 stt->analogTarget += stt->targetIdxOffset;
454 #endif
455 /* Since the offset between RMS and ENV is not constant, we should make this into a
456 * table, but for now, we'll stick with a constant, tuned for the chosen analog
457 * target level.
458 */
459 stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS;
460 #ifdef MIC_LEVEL_FEEDBACK
461 stt->targetIdx += stt->targetIdxOffset;
462 #endif
463 /* Analog adaptation limits */
464 /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */
465 stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */
466 stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */
467 stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */
468 stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */
469 stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */
470 stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */
471 stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */
472 stt->upperLimit = stt->startUpperLimit;
473 stt->lowerLimit = stt->startLowerLimit;
474 }
475
WebRtcAgc_SaturationCtrl(LegacyAgc * stt,uint8_t * saturated,int32_t * env)476 void WebRtcAgc_SaturationCtrl(LegacyAgc* stt,
477 uint8_t* saturated,
478 int32_t* env) {
479 int16_t i, tmpW16;
480
481 /* Check if the signal is saturated */
482 for (i = 0; i < 10; i++)
483 {
484 tmpW16 = (int16_t)(env[i] >> 20);
485 if (tmpW16 > 875)
486 {
487 stt->envSum += tmpW16;
488 }
489 }
490
491 if (stt->envSum > 25000)
492 {
493 *saturated = 1;
494 stt->envSum = 0;
495 }
496
497 /* stt->envSum *= 0.99; */
498 stt->envSum = (int16_t)((stt->envSum * 32440) >> 15);
499 }
500
WebRtcAgc_ZeroCtrl(LegacyAgc * stt,int32_t * inMicLevel,int32_t * env)501 void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
502 int16_t i;
503 int32_t tmp32 = 0;
504 int32_t midVal;
505
506 /* Is the input signal zero? */
507 for (i = 0; i < 10; i++)
508 {
509 tmp32 += env[i];
510 }
511
512 /* Each block is allowed to have a few non-zero
513 * samples.
514 */
515 if (tmp32 < 500)
516 {
517 stt->msZero += 10;
518 } else
519 {
520 stt->msZero = 0;
521 }
522
523 if (stt->muteGuardMs > 0)
524 {
525 stt->muteGuardMs -= 10;
526 }
527
528 if (stt->msZero > 500)
529 {
530 stt->msZero = 0;
531
532 /* Increase microphone level only if it's less than 50% */
533 midVal = (stt->maxAnalog + stt->minLevel + 1) / 2;
534 if (*inMicLevel < midVal)
535 {
536 /* *inMicLevel *= 1.1; */
537 *inMicLevel = (1126 * *inMicLevel) >> 10;
538 /* Reduces risk of a muted mic repeatedly triggering excessive levels due
539 * to zero signal detection. */
540 *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax);
541 stt->micVol = *inMicLevel;
542 }
543
544 #ifdef WEBRTC_AGC_DEBUG_DUMP
545 fprintf(stt->fpt,
546 "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
547 " micVol: %d\n",
548 stt->fcount,
549 stt->micVol);
550 #endif
551
552 stt->activeSpeech = 0;
553 stt->Rxx16_LPw32Max = 0;
554
555 /* The AGC has a tendency (due to problems with the VAD parameters), to
556 * vastly increase the volume after a muting event. This timer prevents
557 * upwards adaptation for a short period. */
558 stt->muteGuardMs = kMuteGuardTimeMs;
559 }
560 }
561
WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc * stt)562 void WebRtcAgc_SpeakerInactiveCtrl(LegacyAgc* stt) {
563 /* Check if the near end speaker is inactive.
564 * If that is the case the VAD threshold is
565 * increased since the VAD speech model gets
566 * more sensitive to any sound after a long
567 * silence.
568 */
569
570 int32_t tmp32;
571 int16_t vadThresh;
572
573 if (stt->vadMic.stdLongTerm < 2500)
574 {
575 stt->vadThreshold = 1500;
576 } else
577 {
578 vadThresh = kNormalVadThreshold;
579 if (stt->vadMic.stdLongTerm < 4500)
580 {
581 /* Scale between min and max threshold */
582 vadThresh += (4500 - stt->vadMic.stdLongTerm) / 2;
583 }
584
585 /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */
586 tmp32 = vadThresh + 31 * stt->vadThreshold;
587 stt->vadThreshold = (int16_t)(tmp32 >> 5);
588 }
589 }
590
WebRtcAgc_ExpCurve(int16_t volume,int16_t * index)591 void WebRtcAgc_ExpCurve(int16_t volume, int16_t *index)
592 {
593 // volume in Q14
594 // index in [0-7]
595 /* 8 different curves */
596 if (volume > 5243)
597 {
598 if (volume > 7864)
599 {
600 if (volume > 12124)
601 {
602 *index = 7;
603 } else
604 {
605 *index = 6;
606 }
607 } else
608 {
609 if (volume > 6554)
610 {
611 *index = 5;
612 } else
613 {
614 *index = 4;
615 }
616 }
617 } else
618 {
619 if (volume > 2621)
620 {
621 if (volume > 3932)
622 {
623 *index = 3;
624 } else
625 {
626 *index = 2;
627 }
628 } else
629 {
630 if (volume > 1311)
631 {
632 *index = 1;
633 } else
634 {
635 *index = 0;
636 }
637 }
638 }
639 }
640
WebRtcAgc_ProcessAnalog(void * state,int32_t inMicLevel,int32_t * outMicLevel,int16_t vadLogRatio,int16_t echo,uint8_t * saturationWarning)641 int32_t WebRtcAgc_ProcessAnalog(void *state, int32_t inMicLevel,
642 int32_t *outMicLevel,
643 int16_t vadLogRatio,
644 int16_t echo, uint8_t *saturationWarning)
645 {
646 uint32_t tmpU32;
647 int32_t Rxx16w32, tmp32;
648 int32_t inMicLevelTmp, lastMicVol;
649 int16_t i;
650 uint8_t saturated = 0;
651 LegacyAgc* stt;
652
653 stt = (LegacyAgc*)state;
654 inMicLevelTmp = inMicLevel << stt->scale;
655
656 if (inMicLevelTmp > stt->maxAnalog)
657 {
658 #ifdef WEBRTC_AGC_DEBUG_DUMP
659 fprintf(stt->fpt,
660 "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
661 stt->fcount);
662 #endif
663 return -1;
664 } else if (inMicLevelTmp < stt->minLevel)
665 {
666 #ifdef WEBRTC_AGC_DEBUG_DUMP
667 fprintf(stt->fpt,
668 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
669 stt->fcount);
670 #endif
671 return -1;
672 }
673
674 if (stt->firstCall == 0)
675 {
676 int32_t tmpVol;
677 stt->firstCall = 1;
678 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
679 tmpVol = (stt->minLevel + tmp32);
680
681 /* If the mic level is very low at start, increase it! */
682 if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog))
683 {
684 inMicLevelTmp = tmpVol;
685 }
686 stt->micVol = inMicLevelTmp;
687 }
688
689 /* Set the mic level to the previous output value if there is digital input gain */
690 if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog))
691 {
692 inMicLevelTmp = stt->micVol;
693 }
694
695 /* If the mic level was manually changed to a very low value raise it! */
696 if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput))
697 {
698 tmp32 = ((stt->maxLevel - stt->minLevel) * 51) >> 9;
699 inMicLevelTmp = (stt->minLevel + tmp32);
700 stt->micVol = inMicLevelTmp;
701 #ifdef MIC_LEVEL_FEEDBACK
702 //stt->numBlocksMicLvlSat = 0;
703 #endif
704 #ifdef WEBRTC_AGC_DEBUG_DUMP
705 fprintf(stt->fpt,
706 "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
707 " decrease, raise vol\n",
708 stt->fcount);
709 #endif
710 }
711
712 if (inMicLevelTmp != stt->micVol)
713 {
714 if (inMicLevel == stt->lastInMicLevel) {
715 // We requested a volume adjustment, but it didn't occur. This is
716 // probably due to a coarse quantization of the volume slider.
717 // Restore the requested value to prevent getting stuck.
718 inMicLevelTmp = stt->micVol;
719 }
720 else {
721 // As long as the value changed, update to match.
722 stt->micVol = inMicLevelTmp;
723 }
724 }
725
726 if (inMicLevelTmp > stt->maxLevel)
727 {
728 // Always allow the user to raise the volume above the maxLevel.
729 stt->maxLevel = inMicLevelTmp;
730 }
731
732 // Store last value here, after we've taken care of manual updates etc.
733 stt->lastInMicLevel = inMicLevel;
734 lastMicVol = stt->micVol;
735
736 /* Checks if the signal is saturated. Also a check if individual samples
737 * are larger than 12000 is done. If they are the counter for increasing
738 * the volume level is set to -100ms
739 */
740 WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]);
741
742 /* The AGC is always allowed to lower the level if the signal is saturated */
743 if (saturated == 1)
744 {
745 /* Lower the recording level
746 * Rxx160_LP is adjusted down because it is so slow it could
747 * cause the AGC to make wrong decisions. */
748 /* stt->Rxx160_LPw32 *= 0.875; */
749 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 8) * 7;
750
751 stt->zeroCtrlMax = stt->micVol;
752
753 /* stt->micVol *= 0.903; */
754 tmp32 = inMicLevelTmp - stt->minLevel;
755 tmpU32 = WEBRTC_SPL_UMUL(29591, (uint32_t)(tmp32));
756 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
757 if (stt->micVol > lastMicVol - 2)
758 {
759 stt->micVol = lastMicVol - 2;
760 }
761 inMicLevelTmp = stt->micVol;
762
763 #ifdef WEBRTC_AGC_DEBUG_DUMP
764 fprintf(stt->fpt,
765 "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
766 stt->fcount,
767 stt->micVol);
768 #endif
769
770 if (stt->micVol < stt->minOutput)
771 {
772 *saturationWarning = 1;
773 }
774
775 /* Reset counter for decrease of volume level to avoid
776 * decreasing too much. The saturation control can still
777 * lower the level if needed. */
778 stt->msTooHigh = -100;
779
780 /* Enable the control mechanism to ensure that our measure,
781 * Rxx160_LP, is in the correct range. This must be done since
782 * the measure is very slow. */
783 stt->activeSpeech = 0;
784 stt->Rxx16_LPw32Max = 0;
785
786 /* Reset to initial values */
787 stt->msecSpeechInnerChange = kMsecSpeechInner;
788 stt->msecSpeechOuterChange = kMsecSpeechOuter;
789 stt->changeToSlowMode = 0;
790
791 stt->muteGuardMs = 0;
792
793 stt->upperLimit = stt->startUpperLimit;
794 stt->lowerLimit = stt->startLowerLimit;
795 #ifdef MIC_LEVEL_FEEDBACK
796 //stt->numBlocksMicLvlSat = 0;
797 #endif
798 }
799
800 /* Check if the input speech is zero. If so the mic volume
801 * is increased. On some computers the input is zero up as high
802 * level as 17% */
803 WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]);
804
805 /* Check if the near end speaker is inactive.
806 * If that is the case the VAD threshold is
807 * increased since the VAD speech model gets
808 * more sensitive to any sound after a long
809 * silence.
810 */
811 WebRtcAgc_SpeakerInactiveCtrl(stt);
812
813 for (i = 0; i < 5; i++)
814 {
815 /* Computed on blocks of 16 samples */
816
817 Rxx16w32 = stt->Rxx16w32_array[0][i];
818
819 /* Rxx160w32 in Q(-7) */
820 tmp32 = (Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos]) >> 3;
821 stt->Rxx160w32 = stt->Rxx160w32 + tmp32;
822 stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32;
823
824 /* Circular buffer */
825 stt->Rxx16pos++;
826 if (stt->Rxx16pos == RXX_BUFFER_LEN)
827 {
828 stt->Rxx16pos = 0;
829 }
830
831 /* Rxx16_LPw32 in Q(-4) */
832 tmp32 = (Rxx16w32 - stt->Rxx16_LPw32) >> kAlphaShortTerm;
833 stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32;
834
835 if (vadLogRatio > stt->vadThreshold)
836 {
837 /* Speech detected! */
838
839 /* Check if Rxx160_LP is in the correct range. If
840 * it is too high/low then we set it to the maximum of
841 * Rxx16_LPw32 during the first 200ms of speech.
842 */
843 if (stt->activeSpeech < 250)
844 {
845 stt->activeSpeech += 2;
846
847 if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max)
848 {
849 stt->Rxx16_LPw32Max = stt->Rxx16_LPw32;
850 }
851 } else if (stt->activeSpeech == 250)
852 {
853 stt->activeSpeech += 2;
854 tmp32 = stt->Rxx16_LPw32Max >> 3;
855 stt->Rxx160_LPw32 = tmp32 * RXX_BUFFER_LEN;
856 }
857
858 tmp32 = (stt->Rxx160w32 - stt->Rxx160_LPw32) >> kAlphaLongTerm;
859 stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32;
860
861 if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit)
862 {
863 stt->msTooHigh += 2;
864 stt->msTooLow = 0;
865 stt->changeToSlowMode = 0;
866
867 if (stt->msTooHigh > stt->msecSpeechOuterChange)
868 {
869 stt->msTooHigh = 0;
870
871 /* Lower the recording level */
872 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
873 tmp32 = stt->Rxx160_LPw32 >> 6;
874 stt->Rxx160_LPw32 = tmp32 * 53;
875
876 /* Reduce the max gain to avoid excessive oscillation
877 * (but never drop below the maximum analog level).
878 */
879 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
880 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
881
882 stt->zeroCtrlMax = stt->micVol;
883
884 /* 0.95 in Q15 */
885 tmp32 = inMicLevelTmp - stt->minLevel;
886 tmpU32 = WEBRTC_SPL_UMUL(31130, (uint32_t)(tmp32));
887 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
888 if (stt->micVol > lastMicVol - 1)
889 {
890 stt->micVol = lastMicVol - 1;
891 }
892 inMicLevelTmp = stt->micVol;
893
894 /* Enable the control mechanism to ensure that our measure,
895 * Rxx160_LP, is in the correct range.
896 */
897 stt->activeSpeech = 0;
898 stt->Rxx16_LPw32Max = 0;
899 #ifdef MIC_LEVEL_FEEDBACK
900 //stt->numBlocksMicLvlSat = 0;
901 #endif
902 #ifdef WEBRTC_AGC_DEBUG_DUMP
903 fprintf(stt->fpt,
904 "\tAGC->ProcessAnalog, frame %d: measure >"
905 " 2ndUpperLim, micVol = %d, maxLevel = %d\n",
906 stt->fcount,
907 stt->micVol,
908 stt->maxLevel);
909 #endif
910 }
911 } else if (stt->Rxx160_LPw32 > stt->upperLimit)
912 {
913 stt->msTooHigh += 2;
914 stt->msTooLow = 0;
915 stt->changeToSlowMode = 0;
916
917 if (stt->msTooHigh > stt->msecSpeechInnerChange)
918 {
919 /* Lower the recording level */
920 stt->msTooHigh = 0;
921 /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */
922 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 53;
923
924 /* Reduce the max gain to avoid excessive oscillation
925 * (but never drop below the maximum analog level).
926 */
927 stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16;
928 stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog);
929
930 stt->zeroCtrlMax = stt->micVol;
931
932 /* 0.965 in Q15 */
933 tmp32 = inMicLevelTmp - stt->minLevel;
934 tmpU32 = WEBRTC_SPL_UMUL(31621, (uint32_t)(inMicLevelTmp - stt->minLevel));
935 stt->micVol = (tmpU32 >> 15) + stt->minLevel;
936 if (stt->micVol > lastMicVol - 1)
937 {
938 stt->micVol = lastMicVol - 1;
939 }
940 inMicLevelTmp = stt->micVol;
941
942 #ifdef MIC_LEVEL_FEEDBACK
943 //stt->numBlocksMicLvlSat = 0;
944 #endif
945 #ifdef WEBRTC_AGC_DEBUG_DUMP
946 fprintf(stt->fpt,
947 "\tAGC->ProcessAnalog, frame %d: measure >"
948 " UpperLim, micVol = %d, maxLevel = %d\n",
949 stt->fcount,
950 stt->micVol,
951 stt->maxLevel);
952 #endif
953 }
954 } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit)
955 {
956 stt->msTooHigh = 0;
957 stt->changeToSlowMode = 0;
958 stt->msTooLow += 2;
959
960 if (stt->msTooLow > stt->msecSpeechOuterChange)
961 {
962 /* Raise the recording level */
963 int16_t index, weightFIX;
964 int16_t volNormFIX = 16384; // =1 in Q14.
965
966 stt->msTooLow = 0;
967
968 /* Normalize the volume level */
969 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
970 if (stt->maxInit != stt->minLevel)
971 {
972 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
973 }
974
975 /* Find correct curve */
976 WebRtcAgc_ExpCurve(volNormFIX, &index);
977
978 /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */
979 weightFIX = kOffset1[index] -
980 (int16_t)((kSlope1[index] * volNormFIX) >> 13);
981
982 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
983 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
984
985 tmp32 = inMicLevelTmp - stt->minLevel;
986 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
987 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
988 if (stt->micVol < lastMicVol + 2)
989 {
990 stt->micVol = lastMicVol + 2;
991 }
992
993 inMicLevelTmp = stt->micVol;
994
995 #ifdef MIC_LEVEL_FEEDBACK
996 /* Count ms in level saturation */
997 //if (stt->micVol > stt->maxAnalog) {
998 if (stt->micVol > 150)
999 {
1000 /* mic level is saturated */
1001 stt->numBlocksMicLvlSat++;
1002 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1003 }
1004 #endif
1005 #ifdef WEBRTC_AGC_DEBUG_DUMP
1006 fprintf(stt->fpt,
1007 "\tAGC->ProcessAnalog, frame %d: measure <"
1008 " 2ndLowerLim, micVol = %d\n",
1009 stt->fcount,
1010 stt->micVol);
1011 #endif
1012 }
1013 } else if (stt->Rxx160_LPw32 < stt->lowerLimit)
1014 {
1015 stt->msTooHigh = 0;
1016 stt->changeToSlowMode = 0;
1017 stt->msTooLow += 2;
1018
1019 if (stt->msTooLow > stt->msecSpeechInnerChange)
1020 {
1021 /* Raise the recording level */
1022 int16_t index, weightFIX;
1023 int16_t volNormFIX = 16384; // =1 in Q14.
1024
1025 stt->msTooLow = 0;
1026
1027 /* Normalize the volume level */
1028 tmp32 = (inMicLevelTmp - stt->minLevel) << 14;
1029 if (stt->maxInit != stt->minLevel)
1030 {
1031 volNormFIX = tmp32 / (stt->maxInit - stt->minLevel);
1032 }
1033
1034 /* Find correct curve */
1035 WebRtcAgc_ExpCurve(volNormFIX, &index);
1036
1037 /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */
1038 weightFIX = kOffset2[index] -
1039 (int16_t)((kSlope2[index] * volNormFIX) >> 13);
1040
1041 /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */
1042 stt->Rxx160_LPw32 = (stt->Rxx160_LPw32 / 64) * 67;
1043
1044 tmp32 = inMicLevelTmp - stt->minLevel;
1045 tmpU32 = ((uint32_t)weightFIX * (uint32_t)(inMicLevelTmp - stt->minLevel));
1046 stt->micVol = (tmpU32 >> 14) + stt->minLevel;
1047 if (stt->micVol < lastMicVol + 1)
1048 {
1049 stt->micVol = lastMicVol + 1;
1050 }
1051
1052 inMicLevelTmp = stt->micVol;
1053
1054 #ifdef MIC_LEVEL_FEEDBACK
1055 /* Count ms in level saturation */
1056 //if (stt->micVol > stt->maxAnalog) {
1057 if (stt->micVol > 150)
1058 {
1059 /* mic level is saturated */
1060 stt->numBlocksMicLvlSat++;
1061 fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
1062 }
1063 #endif
1064 #ifdef WEBRTC_AGC_DEBUG_DUMP
1065 fprintf(stt->fpt,
1066 "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n",
1067 stt->fcount,
1068 stt->micVol);
1069 #endif
1070
1071 }
1072 } else
1073 {
1074 /* The signal is inside the desired range which is:
1075 * lowerLimit < Rxx160_LP/640 < upperLimit
1076 */
1077 if (stt->changeToSlowMode > 4000)
1078 {
1079 stt->msecSpeechInnerChange = 1000;
1080 stt->msecSpeechOuterChange = 500;
1081 stt->upperLimit = stt->upperPrimaryLimit;
1082 stt->lowerLimit = stt->lowerPrimaryLimit;
1083 } else
1084 {
1085 stt->changeToSlowMode += 2; // in milliseconds
1086 }
1087 stt->msTooLow = 0;
1088 stt->msTooHigh = 0;
1089
1090 stt->micVol = inMicLevelTmp;
1091
1092 }
1093 #ifdef MIC_LEVEL_FEEDBACK
1094 if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET)
1095 {
1096 stt->micLvlSat = 1;
1097 fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1098 WebRtcAgc_UpdateAgcThresholds(stt);
1099 WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]),
1100 stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable,
1101 stt->analogTarget);
1102 stt->numBlocksMicLvlSat = 0;
1103 stt->micLvlSat = 0;
1104 fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset);
1105 fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx);
1106 }
1107 #endif
1108 }
1109 }
1110
1111 /* Ensure gain is not increased in presence of echo or after a mute event
1112 * (but allow the zeroCtrl() increase on the frame of a mute detection).
1113 */
1114 if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs))
1115 {
1116 if (stt->micVol > lastMicVol)
1117 {
1118 stt->micVol = lastMicVol;
1119 }
1120 }
1121
1122 /* limit the gain */
1123 if (stt->micVol > stt->maxLevel)
1124 {
1125 stt->micVol = stt->maxLevel;
1126 } else if (stt->micVol < stt->minOutput)
1127 {
1128 stt->micVol = stt->minOutput;
1129 }
1130
1131 *outMicLevel = WEBRTC_SPL_MIN(stt->micVol, stt->maxAnalog) >> stt->scale;
1132
1133 return 0;
1134 }
1135
WebRtcAgc_Process(void * agcInst,const int16_t * const * in_near,size_t num_bands,size_t samples,int16_t * const * out,int32_t inMicLevel,int32_t * outMicLevel,int16_t echo,uint8_t * saturationWarning)1136 int WebRtcAgc_Process(void *agcInst, const int16_t* const* in_near,
1137 size_t num_bands, size_t samples,
1138 int16_t* const* out, int32_t inMicLevel,
1139 int32_t *outMicLevel, int16_t echo,
1140 uint8_t *saturationWarning)
1141 {
1142 LegacyAgc* stt;
1143
1144 stt = (LegacyAgc*)agcInst;
1145
1146 //
1147 if (stt == NULL)
1148 {
1149 return -1;
1150 }
1151 //
1152
1153
1154 if (stt->fs == 8000)
1155 {
1156 if (samples != 80)
1157 {
1158 return -1;
1159 }
1160 } else if (stt->fs == 16000 || stt->fs == 32000 || stt->fs == 48000)
1161 {
1162 if (samples != 160)
1163 {
1164 return -1;
1165 }
1166 } else
1167 {
1168 return -1;
1169 }
1170
1171 *saturationWarning = 0;
1172 //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS
1173 *outMicLevel = inMicLevel;
1174
1175 #ifdef WEBRTC_AGC_DEBUG_DUMP
1176 stt->fcount++;
1177 #endif
1178
1179 if (WebRtcAgc_ProcessDigital(&stt->digitalAgc,
1180 in_near,
1181 num_bands,
1182 out,
1183 stt->fs,
1184 stt->lowLevelSignal) == -1)
1185 {
1186 #ifdef WEBRTC_AGC_DEBUG_DUMP
1187 fprintf(stt->fpt,
1188 "AGC->Process, frame %d: Error from DigAGC\n\n",
1189 stt->fcount);
1190 #endif
1191 return -1;
1192 }
1193 if (stt->agcMode < kAgcModeFixedDigital &&
1194 (stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital))
1195 {
1196 if (WebRtcAgc_ProcessAnalog(agcInst,
1197 inMicLevel,
1198 outMicLevel,
1199 stt->vadMic.logRatio,
1200 echo,
1201 saturationWarning) == -1)
1202 {
1203 return -1;
1204 }
1205 }
1206 #ifdef WEBRTC_AGC_DEBUG_DUMP
1207 fprintf(stt->agcLog,
1208 "%5d\t%d\t%d\t%d\t%d\n",
1209 stt->fcount,
1210 inMicLevel,
1211 *outMicLevel,
1212 stt->maxLevel,
1213 stt->micVol);
1214 #endif
1215
1216 /* update queue */
1217 if (stt->inQueue > 1)
1218 {
1219 memcpy(stt->env[0], stt->env[1], 10 * sizeof(int32_t));
1220 memcpy(stt->Rxx16w32_array[0],
1221 stt->Rxx16w32_array[1],
1222 5 * sizeof(int32_t));
1223 }
1224
1225 if (stt->inQueue > 0)
1226 {
1227 stt->inQueue--;
1228 }
1229
1230 return 0;
1231 }
1232
WebRtcAgc_set_config(void * agcInst,WebRtcAgcConfig agcConfig)1233 int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
1234 LegacyAgc* stt;
1235 stt = (LegacyAgc*)agcInst;
1236
1237 if (stt == NULL)
1238 {
1239 return -1;
1240 }
1241
1242 if (stt->initFlag != kInitCheck)
1243 {
1244 stt->lastError = AGC_UNINITIALIZED_ERROR;
1245 return -1;
1246 }
1247
1248 if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue)
1249 {
1250 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1251 return -1;
1252 }
1253 stt->limiterEnable = agcConfig.limiterEnable;
1254 stt->compressionGaindB = agcConfig.compressionGaindB;
1255 if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31))
1256 {
1257 stt->lastError = AGC_BAD_PARAMETER_ERROR;
1258 return -1;
1259 }
1260 stt->targetLevelDbfs = agcConfig.targetLevelDbfs;
1261
1262 if (stt->agcMode == kAgcModeFixedDigital)
1263 {
1264 /* Adjust for different parameter interpretation in FixedDigital mode */
1265 stt->compressionGaindB += agcConfig.targetLevelDbfs;
1266 }
1267
1268 /* Update threshold levels for analog adaptation */
1269 WebRtcAgc_UpdateAgcThresholds(stt);
1270
1271 /* Recalculate gain table */
1272 if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
1273 stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1)
1274 {
1275 #ifdef WEBRTC_AGC_DEBUG_DUMP
1276 fprintf(stt->fpt,
1277 "AGC->set_config, frame %d: Error from calcGainTable\n\n",
1278 stt->fcount);
1279 #endif
1280 return -1;
1281 }
1282 /* Store the config in a WebRtcAgcConfig */
1283 stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
1284 stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
1285 stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;
1286
1287 return 0;
1288 }
1289
WebRtcAgc_get_config(void * agcInst,WebRtcAgcConfig * config)1290 int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
1291 LegacyAgc* stt;
1292 stt = (LegacyAgc*)agcInst;
1293
1294 if (stt == NULL)
1295 {
1296 return -1;
1297 }
1298
1299 if (config == NULL)
1300 {
1301 stt->lastError = AGC_NULL_POINTER_ERROR;
1302 return -1;
1303 }
1304
1305 if (stt->initFlag != kInitCheck)
1306 {
1307 stt->lastError = AGC_UNINITIALIZED_ERROR;
1308 return -1;
1309 }
1310
1311 config->limiterEnable = stt->usedConfig.limiterEnable;
1312 config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs;
1313 config->compressionGaindB = stt->usedConfig.compressionGaindB;
1314
1315 return 0;
1316 }
1317
WebRtcAgc_Create()1318 void* WebRtcAgc_Create() {
1319 LegacyAgc* stt = malloc(sizeof(LegacyAgc));
1320
1321 #ifdef WEBRTC_AGC_DEBUG_DUMP
1322 stt->fpt = fopen("./agc_test_log.txt", "wt");
1323 stt->agcLog = fopen("./agc_debug_log.txt", "wt");
1324 stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
1325 #endif
1326
1327 stt->initFlag = 0;
1328 stt->lastError = 0;
1329
1330 return stt;
1331 }
1332
WebRtcAgc_Free(void * state)1333 void WebRtcAgc_Free(void *state) {
1334 LegacyAgc* stt;
1335
1336 stt = (LegacyAgc*)state;
1337 #ifdef WEBRTC_AGC_DEBUG_DUMP
1338 fclose(stt->fpt);
1339 fclose(stt->agcLog);
1340 fclose(stt->digitalAgc.logFile);
1341 #endif
1342 free(stt);
1343 }
1344
1345 /* minLevel - Minimum volume level
1346 * maxLevel - Maximum volume level
1347 */
WebRtcAgc_Init(void * agcInst,int32_t minLevel,int32_t maxLevel,int16_t agcMode,uint32_t fs)1348 int WebRtcAgc_Init(void *agcInst, int32_t minLevel, int32_t maxLevel,
1349 int16_t agcMode, uint32_t fs)
1350 {
1351 int32_t max_add, tmp32;
1352 int16_t i;
1353 int tmpNorm;
1354 LegacyAgc* stt;
1355
1356 /* typecast state pointer */
1357 stt = (LegacyAgc*)agcInst;
1358
1359 if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0)
1360 {
1361 stt->lastError = AGC_UNINITIALIZED_ERROR;
1362 return -1;
1363 }
1364
1365 /* Analog AGC variables */
1366 stt->envSum = 0;
1367
1368 /* mode = 0 - Only saturation protection
1369 * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1370 * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)]
1371 * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
1372 */
1373 #ifdef WEBRTC_AGC_DEBUG_DUMP
1374 stt->fcount = 0;
1375 fprintf(stt->fpt, "AGC->Init\n");
1376 #endif
1377 if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital)
1378 {
1379 #ifdef WEBRTC_AGC_DEBUG_DUMP
1380 fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
1381 #endif
1382 return -1;
1383 }
1384 stt->agcMode = agcMode;
1385 stt->fs = fs;
1386
1387 /* initialize input VAD */
1388 WebRtcAgc_InitVad(&stt->vadMic);
1389
1390 /* If the volume range is smaller than 0-256 then
1391 * the levels are shifted up to Q8-domain */
1392 tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
1393 stt->scale = tmpNorm - 23;
1394 if (stt->scale < 0)
1395 {
1396 stt->scale = 0;
1397 }
1398 // TODO(bjornv): Investigate if we really need to scale up a small range now when we have
1399 // a guard against zero-increments. For now, we do not support scale up (scale = 0).
1400 stt->scale = 0;
1401 maxLevel <<= stt->scale;
1402 minLevel <<= stt->scale;
1403
1404 /* Make minLevel and maxLevel static in AdaptiveDigital */
1405 if (stt->agcMode == kAgcModeAdaptiveDigital)
1406 {
1407 minLevel = 0;
1408 maxLevel = 255;
1409 stt->scale = 0;
1410 }
1411 /* The maximum supplemental volume range is based on a vague idea
1412 * of how much lower the gain will be than the real analog gain. */
1413 max_add = (maxLevel - minLevel) / 4;
1414
1415 /* Minimum/maximum volume level that can be set */
1416 stt->minLevel = minLevel;
1417 stt->maxAnalog = maxLevel;
1418 stt->maxLevel = maxLevel + max_add;
1419 stt->maxInit = stt->maxLevel;
1420
1421 stt->zeroCtrlMax = stt->maxAnalog;
1422 stt->lastInMicLevel = 0;
1423
1424 /* Initialize micVol parameter */
1425 stt->micVol = stt->maxAnalog;
1426 if (stt->agcMode == kAgcModeAdaptiveDigital)
1427 {
1428 stt->micVol = 127; /* Mid-point of mic level */
1429 }
1430 stt->micRef = stt->micVol;
1431 stt->micGainIdx = 127;
1432 #ifdef MIC_LEVEL_FEEDBACK
1433 stt->numBlocksMicLvlSat = 0;
1434 stt->micLvlSat = 0;
1435 #endif
1436 #ifdef WEBRTC_AGC_DEBUG_DUMP
1437 fprintf(stt->fpt,
1438 "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
1439 stt->minLevel,
1440 stt->maxAnalog,
1441 stt->maxLevel);
1442 #endif
1443
1444 /* Minimum output volume is 4% higher than the available lowest volume level */
1445 tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
1446 stt->minOutput = (stt->minLevel + tmp32);
1447
1448 stt->msTooLow = 0;
1449 stt->msTooHigh = 0;
1450 stt->changeToSlowMode = 0;
1451 stt->firstCall = 0;
1452 stt->msZero = 0;
1453 stt->muteGuardMs = 0;
1454 stt->gainTableIdx = 0;
1455
1456 stt->msecSpeechInnerChange = kMsecSpeechInner;
1457 stt->msecSpeechOuterChange = kMsecSpeechOuter;
1458
1459 stt->activeSpeech = 0;
1460 stt->Rxx16_LPw32Max = 0;
1461
1462 stt->vadThreshold = kNormalVadThreshold;
1463 stt->inActive = 0;
1464
1465 for (i = 0; i < RXX_BUFFER_LEN; i++)
1466 {
1467 stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
1468 }
1469 stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */
1470
1471 stt->Rxx16pos = 0;
1472 stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */
1473
1474 for (i = 0; i < 5; i++)
1475 {
1476 stt->Rxx16w32_array[0][i] = 0;
1477 }
1478 for (i = 0; i < 10; i++)
1479 {
1480 stt->env[0][i] = 0;
1481 stt->env[1][i] = 0;
1482 }
1483 stt->inQueue = 0;
1484
1485 #ifdef MIC_LEVEL_FEEDBACK
1486 stt->targetIdxOffset = 0;
1487 #endif
1488
1489 WebRtcSpl_MemSetW32(stt->filterState, 0, 8);
1490
1491 stt->initFlag = kInitCheck;
1492 // Default config settings.
1493 stt->defaultConfig.limiterEnable = kAgcTrue;
1494 stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
1495 stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;
1496
1497 if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1)
1498 {
1499 stt->lastError = AGC_UNSPECIFIED_ERROR;
1500 return -1;
1501 }
1502 stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value
1503
1504 stt->lowLevelSignal = 0;
1505
1506 /* Only positive values are allowed that are not too large */
1507 if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000))
1508 {
1509 #ifdef WEBRTC_AGC_DEBUG_DUMP
1510 fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
1511 #endif
1512 return -1;
1513 } else
1514 {
1515 #ifdef WEBRTC_AGC_DEBUG_DUMP
1516 fprintf(stt->fpt, "\n");
1517 #endif
1518 return 0;
1519 }
1520 }
1521