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