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