Changed the digital AGC1 gain to properly support multichannel
Beyond making the digital AGC1 code properly support multichannel, this CL also -Removes deprecated debug logging code. -Converts the gain application to be fully in floating point which --Is less computationally complex. --Does not quantize the samples to 16 bit before applying the gains. Bug: webrtc:10859 Change-Id: I6020ba8ae7e311dfc93a72783a2bb68d935f90c5 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159861 Commit-Queue: Per Åhgren <peah@webrtc.org> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29886}
This commit is contained in:
parent
3af0cd8de2
commit
77dc19905d
@ -20,9 +20,6 @@
|
||||
#include "modules/audio_processing/agc/legacy/analog_agc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
@ -510,12 +507,6 @@ void WebRtcAgc_ZeroCtrl(LegacyAgc* stt, int32_t* inMicLevel, int32_t* env) {
|
||||
stt->micVol = *inMicLevel;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold,"
|
||||
" micVol: %d\n",
|
||||
stt->fcount, stt->micVol);
|
||||
#endif
|
||||
|
||||
stt->activeSpeech = 0;
|
||||
stt->Rxx16_LPw32Max = 0;
|
||||
@ -605,16 +596,8 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
inMicLevelTmp = inMicLevel << stt->scale;
|
||||
|
||||
if (inMicLevelTmp > stt->maxAnalog) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n",
|
||||
stt->fcount);
|
||||
#endif
|
||||
return -1;
|
||||
} else if (inMicLevelTmp < stt->minLevel) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n",
|
||||
stt->fcount);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -644,12 +627,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
stt->micVol = inMicLevelTmp;
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
// stt->numBlocksMicLvlSat = 0;
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual"
|
||||
" decrease, raise vol\n",
|
||||
stt->fcount);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -699,11 +676,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
}
|
||||
inMicLevelTmp = stt->micVol;
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n",
|
||||
stt->fcount, stt->micVol);
|
||||
#endif
|
||||
|
||||
if (stt->micVol < stt->minOutput) {
|
||||
*saturationWarning = 1;
|
||||
@ -826,12 +798,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
stt->Rxx16_LPw32Max = 0;
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
// stt->numBlocksMicLvlSat = 0;
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: measure >"
|
||||
" 2ndUpperLim, micVol = %d, maxLevel = %d\n",
|
||||
stt->fcount, stt->micVol, stt->maxLevel);
|
||||
#endif
|
||||
}
|
||||
} else if (stt->Rxx160_LPw32 > stt->upperLimit) {
|
||||
@ -865,12 +831,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
// stt->numBlocksMicLvlSat = 0;
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: measure >"
|
||||
" UpperLim, micVol = %d, maxLevel = %d\n",
|
||||
stt->fcount, stt->micVol, stt->maxLevel);
|
||||
#endif
|
||||
}
|
||||
} else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) {
|
||||
@ -920,12 +880,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
stt->numBlocksMicLvlSat++;
|
||||
fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
|
||||
}
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: measure <"
|
||||
" 2ndLowerLim, micVol = %d\n",
|
||||
stt->fcount, stt->micVol);
|
||||
#endif
|
||||
}
|
||||
} else if (stt->Rxx160_LPw32 < stt->lowerLimit) {
|
||||
@ -975,12 +929,6 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
stt->numBlocksMicLvlSat++;
|
||||
fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat);
|
||||
}
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt,
|
||||
"\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol "
|
||||
"= %d\n",
|
||||
stt->fcount, stt->micVol);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
@ -1041,24 +989,20 @@ int32_t WebRtcAgc_ProcessAnalog(void* state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAgc_Process(void* agcInst,
|
||||
int WebRtcAgc_Analyze(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) {
|
||||
LegacyAgc* stt;
|
||||
uint8_t* saturationWarning,
|
||||
int32_t gains[11]) {
|
||||
LegacyAgc* stt = (LegacyAgc*)agcInst;
|
||||
|
||||
stt = (LegacyAgc*)agcInst;
|
||||
|
||||
//
|
||||
if (stt == NULL) {
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
|
||||
if (stt->fs == 8000) {
|
||||
if (samples != 80) {
|
||||
@ -1076,18 +1020,14 @@ int WebRtcAgc_Process(void* agcInst,
|
||||
// TODO(minyue): PUT IN RANGE CHECKING FOR INPUT LEVELS
|
||||
*outMicLevel = inMicLevel;
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->fcount++;
|
||||
#endif
|
||||
|
||||
if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, in_near, num_bands, out,
|
||||
stt->fs, stt->lowLevelSignal) == -1) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n",
|
||||
stt->fcount);
|
||||
#endif
|
||||
int32_t error =
|
||||
WebRtcAgc_ComputeDigitalGains(&stt->digitalAgc, in_near, num_bands,
|
||||
stt->fs, stt->lowLevelSignal, gains);
|
||||
if (error == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stt->agcMode < kAgcModeFixedDigital &&
|
||||
(stt->lowLevelSignal == 0 || stt->agcMode != kAgcModeAdaptiveDigital)) {
|
||||
if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevel, outMicLevel,
|
||||
@ -1096,10 +1036,6 @@ int WebRtcAgc_Process(void* agcInst,
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\t%d\n", stt->fcount, inMicLevel,
|
||||
*outMicLevel, stt->maxLevel, stt->micVol);
|
||||
#endif
|
||||
|
||||
/* update queue */
|
||||
if (stt->inQueue > 1) {
|
||||
@ -1114,6 +1050,15 @@ int WebRtcAgc_Process(void* agcInst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAgc_Process(const void* agcInst,
|
||||
const int32_t gains[11],
|
||||
const int16_t* const* in_near,
|
||||
size_t num_bands,
|
||||
int16_t* const* out) {
|
||||
const LegacyAgc* stt = (const LegacyAgc*)agcInst;
|
||||
return WebRtcAgc_ApplyDigitalGains(gains, num_bands, stt->fs, in_near, out);
|
||||
}
|
||||
|
||||
int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
|
||||
LegacyAgc* stt;
|
||||
stt = (LegacyAgc*)agcInst;
|
||||
@ -1152,10 +1097,6 @@ int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
|
||||
if (WebRtcAgc_CalculateGainTable(
|
||||
&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB,
|
||||
stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n",
|
||||
stt->fcount);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
/* Store the config in a WebRtcAgcConfig */
|
||||
@ -1194,12 +1135,6 @@ int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config) {
|
||||
void* WebRtcAgc_Create() {
|
||||
LegacyAgc* stt = malloc(sizeof(LegacyAgc));
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->fpt = fopen("./agc_test_log.txt", "wt");
|
||||
stt->agcLog = fopen("./agc_debug_log.txt", "wt");
|
||||
stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt");
|
||||
#endif
|
||||
|
||||
stt->initFlag = 0;
|
||||
stt->lastError = 0;
|
||||
|
||||
@ -1210,11 +1145,6 @@ void WebRtcAgc_Free(void* state) {
|
||||
LegacyAgc* stt;
|
||||
|
||||
stt = (LegacyAgc*)state;
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fclose(stt->fpt);
|
||||
fclose(stt->agcLog);
|
||||
fclose(stt->digitalAgc.logFile);
|
||||
#endif
|
||||
free(stt);
|
||||
}
|
||||
|
||||
@ -1249,14 +1179,7 @@ int WebRtcAgc_Init(void* agcInst,
|
||||
* dBOv)]
|
||||
* 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)]
|
||||
*/
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->fcount = 0;
|
||||
fprintf(stt->fpt, "AGC->Init\n");
|
||||
#endif
|
||||
if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
stt->agcMode = agcMode;
|
||||
@ -1310,10 +1233,6 @@ int WebRtcAgc_Init(void* agcInst,
|
||||
stt->numBlocksMicLvlSat = 0;
|
||||
stt->micLvlSat = 0;
|
||||
#endif
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n",
|
||||
stt->minLevel, stt->maxAnalog, stt->maxLevel);
|
||||
#endif
|
||||
|
||||
/* Minimum output volume is 4% higher than the available lowest volume level
|
||||
*/
|
||||
@ -1377,14 +1296,8 @@ int WebRtcAgc_Init(void* agcInst,
|
||||
|
||||
/* Only positive values are allowed that are not too large */
|
||||
if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n");
|
||||
#endif
|
||||
return -1;
|
||||
} else {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
fprintf(stt->fpt, "\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,9 +12,6 @@
|
||||
#define MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
|
||||
|
||||
//#define MIC_LEVEL_FEEDBACK
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "modules/audio_processing/agc/legacy/digital_agc.h"
|
||||
#include "modules/audio_processing/agc/legacy/gain_control.h"
|
||||
@ -119,12 +116,6 @@ typedef struct {
|
||||
AgcVad vadMic;
|
||||
DigitalAgc digitalAgc;
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
FILE* fpt;
|
||||
FILE* agcLog;
|
||||
int32_t fcount;
|
||||
#endif
|
||||
|
||||
int16_t lowLevelSignal;
|
||||
} LegacyAgc;
|
||||
|
||||
|
||||
@ -15,9 +15,6 @@
|
||||
#include "modules/audio_processing/agc/legacy/digital_agc.h"
|
||||
|
||||
#include <string.h>
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "modules/audio_processing/agc/legacy/gain_control.h"
|
||||
@ -254,9 +251,6 @@ int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
|
||||
stt->gain = 65536;
|
||||
stt->gatePrevious = 0;
|
||||
stt->agcMode = agcMode;
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->frameCounter = 0;
|
||||
#endif
|
||||
|
||||
// initialize VADs
|
||||
WebRtcAgc_InitVad(&stt->vadNearend);
|
||||
@ -275,27 +269,25 @@ int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
// Gains is an 11 element long array (one value per ms, incl start & end).
|
||||
int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* stt,
|
||||
const int16_t* const* in_near,
|
||||
size_t num_bands,
|
||||
int16_t* const* out,
|
||||
uint32_t FS,
|
||||
int16_t lowlevelSignal) {
|
||||
// array for gains (one value per ms, incl start & end)
|
||||
int32_t gains[11];
|
||||
|
||||
int32_t out_tmp, tmp32;
|
||||
int16_t lowlevelSignal,
|
||||
int32_t gains[11]) {
|
||||
int32_t tmp32;
|
||||
int32_t env[10];
|
||||
int32_t max_nrg;
|
||||
int32_t cur_level;
|
||||
int32_t gain32, delta;
|
||||
int32_t gain32;
|
||||
int16_t logratio;
|
||||
int16_t lower_thr, upper_thr;
|
||||
int16_t zeros = 0, zeros_fast, frac = 0;
|
||||
int16_t decay;
|
||||
int16_t gate, gain_adj;
|
||||
int16_t k;
|
||||
size_t n, i, L;
|
||||
size_t n, L;
|
||||
int16_t L2; // samples/subframe
|
||||
|
||||
// determine number of samples per ms
|
||||
@ -309,14 +301,8 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_bands; ++i) {
|
||||
if (in_near[i] != out[i]) {
|
||||
// Only needed if they don't already point to the same place.
|
||||
memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
|
||||
}
|
||||
}
|
||||
// VAD for near end
|
||||
logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10);
|
||||
logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, in_near[0], L * 10);
|
||||
|
||||
// Account for far end VAD
|
||||
if (stt->vadFarend.counter > 10) {
|
||||
@ -358,18 +344,13 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
decay = 0;
|
||||
}
|
||||
}
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->frameCounter++;
|
||||
fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100,
|
||||
logratio, decay, stt->vadNearend.stdLongTerm);
|
||||
#endif
|
||||
// Find max amplitude per sub frame
|
||||
// iterate over sub frames
|
||||
for (k = 0; k < 10; k++) {
|
||||
// iterate over samples
|
||||
max_nrg = 0;
|
||||
for (n = 0; n < L; n++) {
|
||||
int32_t nrg = out[0][k * L + n] * out[0][k * L + n];
|
||||
int32_t nrg = in_near[0][k * L + n] * in_near[0][k * L + n];
|
||||
if (nrg > max_nrg) {
|
||||
max_nrg = nrg;
|
||||
}
|
||||
@ -416,12 +397,6 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
tmp32 = ((stt->gainTable[zeros - 1] - stt->gainTable[zeros]) *
|
||||
(int64_t)frac) >> 12;
|
||||
gains[k + 1] = stt->gainTable[zeros] + tmp32;
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
if (k == 0) {
|
||||
fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level,
|
||||
stt->capacitorFast, stt->capacitorSlow, zeros);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Gate processing (lower gain during absence of speech)
|
||||
@ -498,20 +473,47 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
// save start gain for next frame
|
||||
stt->gain = gains[10];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11], size_t num_bands,
|
||||
uint32_t FS, const int16_t* const* in_near,
|
||||
int16_t* const* out) {
|
||||
// Apply gain
|
||||
// handle first sub frame separately
|
||||
delta = (gains[1] - gains[0]) * (1 << (4 - L2));
|
||||
gain32 = gains[0] * (1 << 4);
|
||||
size_t L;
|
||||
int16_t L2; // samples/subframe
|
||||
|
||||
// determine number of samples per ms
|
||||
if (FS == 8000) {
|
||||
L = 8;
|
||||
L2 = 3;
|
||||
} else if (FS == 16000 || FS == 32000 || FS == 48000) {
|
||||
L = 16;
|
||||
L2 = 4;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_bands; ++i) {
|
||||
if (in_near[i] != out[i]) {
|
||||
// Only needed if they don't already point to the same place.
|
||||
memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
|
||||
}
|
||||
}
|
||||
|
||||
// iterate over samples
|
||||
for (n = 0; n < L; n++) {
|
||||
for (i = 0; i < num_bands; ++i) {
|
||||
out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
|
||||
int32_t delta = (gains[1] - gains[0]) * (1 << (4 - L2));
|
||||
int32_t gain32 = gains[0] * (1 << 4);
|
||||
for (size_t n = 0; n < L; n++) {
|
||||
for (size_t i = 0; i < num_bands; ++i) {
|
||||
int32_t out_tmp = (int64_t)out[i][n] * ((gain32 + 127) >> 7) >> 16;
|
||||
if (out_tmp > 4095) {
|
||||
out[i][n] = (int16_t)32767;
|
||||
} else if (out_tmp < -4096) {
|
||||
out[i][n] = (int16_t)-32768;
|
||||
} else {
|
||||
tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
|
||||
int32_t tmp32 = ((int64_t)out[i][n] * (gain32 >> 4)) >> 16;
|
||||
out[i][n] = (int16_t)tmp32;
|
||||
}
|
||||
}
|
||||
@ -519,12 +521,12 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
gain32 += delta;
|
||||
}
|
||||
// iterate over subframes
|
||||
for (k = 1; k < 10; k++) {
|
||||
for (int k = 1; k < 10; k++) {
|
||||
delta = (gains[k + 1] - gains[k]) * (1 << (4 - L2));
|
||||
gain32 = gains[k] * (1 << 4);
|
||||
// iterate over samples
|
||||
for (n = 0; n < L; n++) {
|
||||
for (i = 0; i < num_bands; ++i) {
|
||||
for (size_t n = 0; n < L; n++) {
|
||||
for (size_t i = 0; i < num_bands; ++i) {
|
||||
int64_t tmp64 = ((int64_t)(out[i][k * L + n])) * (gain32 >> 4);
|
||||
tmp64 = tmp64 >> 16;
|
||||
if (tmp64 > 32767) {
|
||||
@ -540,7 +542,6 @@ int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
gain32 += delta;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -11,9 +11,6 @@
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
// the 32 most significant bits of A(19) * B(26) >> 13
|
||||
@ -44,20 +41,22 @@ typedef struct {
|
||||
int16_t agcMode;
|
||||
AgcVad vadNearend;
|
||||
AgcVad vadFarend;
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
FILE* logFile;
|
||||
int frameCounter;
|
||||
#endif
|
||||
} DigitalAgc;
|
||||
|
||||
int32_t WebRtcAgc_InitDigital(DigitalAgc* digitalAgcInst, int16_t agcMode);
|
||||
|
||||
int32_t WebRtcAgc_ProcessDigital(DigitalAgc* digitalAgcInst,
|
||||
int32_t WebRtcAgc_ComputeDigitalGains(DigitalAgc* digitalAgcInst,
|
||||
const int16_t* const* inNear,
|
||||
size_t num_bands,
|
||||
int16_t* const* out,
|
||||
uint32_t FS,
|
||||
int16_t lowLevelSignal);
|
||||
int16_t lowLevelSignal,
|
||||
int32_t gains[11]);
|
||||
|
||||
int32_t WebRtcAgc_ApplyDigitalGains(const int32_t gains[11],
|
||||
size_t num_bands,
|
||||
uint32_t FS,
|
||||
const int16_t* const* in_near,
|
||||
int16_t* const* out);
|
||||
|
||||
int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* digitalAgcInst,
|
||||
const int16_t* inFar,
|
||||
|
||||
@ -127,12 +127,12 @@ int WebRtcAgc_VirtualMic(void* agcInst,
|
||||
int32_t* micLevelOut);
|
||||
|
||||
/*
|
||||
* This function processes a 10 ms frame and adjusts (normalizes) the gain both
|
||||
* analog and digitally. The gain adjustments are done only during active
|
||||
* periods of speech. The length of the speech vectors must be given in samples
|
||||
* (80 when FS=8000, and 160 when FS=16000, FS=32000 or FS=48000). The echo
|
||||
* parameter can be used to ensure the AGC will not adjust upward in the
|
||||
* presence of echo.
|
||||
* This function analyses a 10 ms frame and produces the analog and digital
|
||||
* gains required to normalize the signal. The gain adjustments are done only
|
||||
* during active periods of speech. The length of the speech vectors must be
|
||||
* given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or
|
||||
* FS=48000). The echo parameter can be used to ensure the AGC will not adjust
|
||||
* upward in the presence of echo.
|
||||
*
|
||||
* This function should be called after processing the near-end microphone
|
||||
* signal, in any case after any echo cancellation.
|
||||
@ -150,25 +150,47 @@ int WebRtcAgc_VirtualMic(void* agcInst,
|
||||
*
|
||||
* Output:
|
||||
* - outMicLevel : Adjusted microphone volume level
|
||||
* - out : Gain-adjusted near-end speech vector
|
||||
* : May be the same vector as the input.
|
||||
* - saturationWarning : A returned value of 1 indicates a saturation event
|
||||
* has occurred and the volume cannot be further
|
||||
* reduced. Otherwise will be set to 0.
|
||||
* - gains : Vector of gains to apply for digital normalization
|
||||
*
|
||||
* Return value:
|
||||
* : 0 - Normal operation.
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Process(void* agcInst,
|
||||
int WebRtcAgc_Analyze(void* agcInst,
|
||||
const int16_t* const* inNear,
|
||||
size_t num_bands,
|
||||
size_t samples,
|
||||
int16_t* const* out,
|
||||
int32_t inMicLevel,
|
||||
int32_t* outMicLevel,
|
||||
int16_t echo,
|
||||
uint8_t* saturationWarning);
|
||||
uint8_t* saturationWarning,
|
||||
int32_t gains[11]);
|
||||
|
||||
/*
|
||||
* This function processes a 10 ms frame by applying precomputed digital gains.
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance
|
||||
* - gains : Vector of gains to apply for digital normalization
|
||||
* - in_near : Near-end input speech vector for each band
|
||||
* - num_bands : Number of bands in input/output vector
|
||||
*
|
||||
* Output:
|
||||
* - out : Gain-adjusted near-end speech vector
|
||||
* : May be the same vector as the input.
|
||||
*
|
||||
* Return value:
|
||||
* : 0 - Normal operation.
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Process(const void* agcInst,
|
||||
const int32_t gains[11],
|
||||
const int16_t* const* in_near,
|
||||
size_t num_bands,
|
||||
int16_t* const* out);
|
||||
|
||||
/*
|
||||
* This function sets the config parameters (targetLevelDbfs,
|
||||
|
||||
@ -18,8 +18,8 @@
|
||||
#include "modules/audio_processing/include/audio_processing.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -39,59 +39,65 @@ int16_t MapSetting(GainControl::Mode mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Checks whether the legacy digital gain application should be used.
|
||||
bool UseLegacyDigitalGainApplier() {
|
||||
return field_trial::IsEnabled("WebRTC-UseLegacyDigitalGainApplier");
|
||||
}
|
||||
|
||||
// Floating point variant of WebRtcAgc_Process.
|
||||
void ApplyDigitalGain(const int32_t gains[11],
|
||||
size_t num_bands,
|
||||
float* const* out) {
|
||||
constexpr float kScaling = 1.f / 65536.f;
|
||||
constexpr int kNumSubSections = 16;
|
||||
constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
|
||||
|
||||
float gains_scaled[11];
|
||||
for (int k = 0; k < 11; ++k) {
|
||||
gains_scaled[k] = gains[k] * kScaling;
|
||||
}
|
||||
|
||||
for (size_t b = 0; b < num_bands; ++b) {
|
||||
float* out_band = out[b];
|
||||
for (int k = 0, sample = 0; k < 10; ++k) {
|
||||
const float delta =
|
||||
(gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
|
||||
float gain = gains_scaled[k];
|
||||
for (int n = 0; n < kNumSubSections; ++n, ++sample) {
|
||||
RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
|
||||
out_band[sample] *= gain;
|
||||
out_band[sample] =
|
||||
std::min(32767.f, std::max(-32768.f, out_band[sample]));
|
||||
gain += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class GainControlImpl::GainController {
|
||||
public:
|
||||
explicit GainController() {
|
||||
state_ = WebRtcAgc_Create();
|
||||
RTC_CHECK(state_);
|
||||
struct GainControlImpl::MonoAgcState {
|
||||
MonoAgcState() {
|
||||
state = WebRtcAgc_Create();
|
||||
RTC_CHECK(state);
|
||||
}
|
||||
|
||||
~GainController() {
|
||||
RTC_DCHECK(state_);
|
||||
WebRtcAgc_Free(state_);
|
||||
~MonoAgcState() {
|
||||
RTC_DCHECK(state);
|
||||
WebRtcAgc_Free(state);
|
||||
}
|
||||
|
||||
Handle* state() {
|
||||
RTC_DCHECK(state_);
|
||||
return state_;
|
||||
}
|
||||
|
||||
void Initialize(int minimum_capture_level,
|
||||
int maximum_capture_level,
|
||||
Mode mode,
|
||||
int sample_rate_hz,
|
||||
int capture_level) {
|
||||
RTC_DCHECK(state_);
|
||||
int error =
|
||||
WebRtcAgc_Init(state_, minimum_capture_level, maximum_capture_level,
|
||||
MapSetting(mode), sample_rate_hz);
|
||||
RTC_DCHECK_EQ(0, error);
|
||||
|
||||
set_capture_level(capture_level);
|
||||
}
|
||||
|
||||
void set_capture_level(int capture_level) { capture_level_ = capture_level; }
|
||||
|
||||
int get_capture_level() {
|
||||
RTC_DCHECK(capture_level_);
|
||||
return *capture_level_;
|
||||
}
|
||||
|
||||
private:
|
||||
Handle* state_;
|
||||
// TODO(peah): Remove the optional once the initialization is moved into the
|
||||
// ctor.
|
||||
absl::optional<int> capture_level_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(GainController);
|
||||
MonoAgcState(const MonoAgcState&) = delete;
|
||||
MonoAgcState& operator=(const MonoAgcState&) = delete;
|
||||
int32_t gains[11];
|
||||
Handle* state;
|
||||
};
|
||||
|
||||
int GainControlImpl::instance_counter_ = 0;
|
||||
|
||||
GainControlImpl::GainControlImpl()
|
||||
: data_dumper_(new ApmDataDumper(instance_counter_)),
|
||||
use_legacy_gain_applier_(UseLegacyDigitalGainApplier()),
|
||||
mode_(kAdaptiveAnalog),
|
||||
minimum_capture_level_(0),
|
||||
maximum_capture_level_(255),
|
||||
@ -102,7 +108,7 @@ GainControlImpl::GainControlImpl()
|
||||
was_analog_level_set_(false),
|
||||
stream_is_saturated_(false) {}
|
||||
|
||||
GainControlImpl::~GainControlImpl() {}
|
||||
GainControlImpl::~GainControlImpl() = default;
|
||||
|
||||
void GainControlImpl::ProcessRenderAudio(
|
||||
rtc::ArrayView<const int16_t> packed_render_audio) {
|
||||
@ -110,8 +116,8 @@ void GainControlImpl::ProcessRenderAudio(
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
WebRtcAgc_AddFarend(gain_controller->state(), packed_render_audio.data(),
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
|
||||
packed_render_audio.size());
|
||||
}
|
||||
}
|
||||
@ -120,27 +126,28 @@ void GainControlImpl::PackRenderAudioBuffer(
|
||||
const AudioBuffer& audio,
|
||||
std::vector<int16_t>* packed_buffer) {
|
||||
RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
|
||||
std::array<int16_t, AudioBuffer::kMaxSplitFrameLength> mixed_low_pass_data;
|
||||
rtc::ArrayView<const int16_t> mixed_low_pass(mixed_low_pass_data.data(),
|
||||
audio.num_frames_per_band());
|
||||
std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
|
||||
mixed_16_kHz_render_data;
|
||||
rtc::ArrayView<const int16_t> mixed_16_kHz_render(
|
||||
mixed_16_kHz_render_data.data(), audio.num_frames_per_band());
|
||||
if (audio.num_channels() == 1) {
|
||||
FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
|
||||
audio.num_frames_per_band(), mixed_low_pass_data.data());
|
||||
audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
|
||||
} else {
|
||||
const int num_channels = static_cast<int>(audio.num_channels());
|
||||
for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
|
||||
int32_t value =
|
||||
FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[0][i]);
|
||||
for (int j = 1; j < num_channels; ++j) {
|
||||
value += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[j][i]);
|
||||
int32_t sum = 0;
|
||||
for (int ch = 0; ch < num_channels; ++ch) {
|
||||
sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
|
||||
}
|
||||
mixed_low_pass_data[i] = value / num_channels;
|
||||
mixed_16_kHz_render_data[i] = sum / num_channels;
|
||||
}
|
||||
}
|
||||
|
||||
packed_buffer->clear();
|
||||
packed_buffer->insert(packed_buffer->end(), mixed_low_pass.data(),
|
||||
(mixed_low_pass.data() + audio.num_frames_per_band()));
|
||||
packed_buffer->insert(
|
||||
packed_buffer->end(), mixed_16_kHz_render.data(),
|
||||
(mixed_16_kHz_render.data() + audio.num_frames_per_band()));
|
||||
}
|
||||
|
||||
int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
|
||||
@ -151,7 +158,7 @@ int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
|
||||
RTC_DCHECK(num_proc_channels_);
|
||||
RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
|
||||
RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
|
||||
RTC_DCHECK_LE(*num_proc_channels_, gain_controllers_.size());
|
||||
RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
|
||||
|
||||
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
||||
[AudioBuffer::kMaxSplitFrameLength];
|
||||
@ -159,39 +166,35 @@ int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
|
||||
split_band_data[0], split_band_data[1], split_band_data[2]};
|
||||
|
||||
if (mode_ == kAdaptiveAnalog) {
|
||||
int capture_channel = 0;
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
gain_controller->set_capture_level(analog_capture_level_);
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
capture_levels_[ch] = analog_capture_level_;
|
||||
|
||||
audio.ExportSplitChannelData(capture_channel, split_bands);
|
||||
audio.ExportSplitChannelData(ch, split_bands);
|
||||
|
||||
int err =
|
||||
WebRtcAgc_AddMic(gain_controller->state(), split_bands,
|
||||
WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
|
||||
audio.num_bands(), audio.num_frames_per_band());
|
||||
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
}
|
||||
++capture_channel;
|
||||
}
|
||||
} else if (mode_ == kAdaptiveDigital) {
|
||||
int capture_channel = 0;
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
int32_t capture_level_out = 0;
|
||||
|
||||
audio.ExportSplitChannelData(capture_channel, split_bands);
|
||||
audio.ExportSplitChannelData(ch, split_bands);
|
||||
|
||||
int err =
|
||||
WebRtcAgc_VirtualMic(gain_controller->state(), split_bands,
|
||||
WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
|
||||
audio.num_bands(), audio.num_frames_per_band(),
|
||||
analog_capture_level_, &capture_level_out);
|
||||
|
||||
gain_controller->set_capture_level(capture_level_out);
|
||||
capture_levels_[ch] = capture_level_out;
|
||||
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
}
|
||||
++capture_channel;
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,57 +217,78 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
|
||||
RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
|
||||
|
||||
stream_is_saturated_ = false;
|
||||
int capture_channel = 0;
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
int32_t capture_level_out = 0;
|
||||
uint8_t saturation_warning = 0;
|
||||
|
||||
bool error_reported = false;
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
||||
[AudioBuffer::kMaxSplitFrameLength];
|
||||
int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
|
||||
split_band_data[0], split_band_data[1], split_band_data[2]};
|
||||
audio->ExportSplitChannelData(capture_channel, split_bands);
|
||||
audio->ExportSplitChannelData(ch, split_bands);
|
||||
|
||||
// The call to stream_has_echo() is ok from a deadlock perspective
|
||||
// as the capture lock is allready held.
|
||||
int err = WebRtcAgc_Process(
|
||||
gain_controller->state(), split_bands, audio->num_bands(),
|
||||
audio->num_frames_per_band(), split_bands,
|
||||
gain_controller->get_capture_level(), &capture_level_out,
|
||||
stream_has_echo, &saturation_warning);
|
||||
int32_t new_capture_level = 0;
|
||||
uint8_t saturation_warning = 0;
|
||||
int err_analyze = WebRtcAgc_Analyze(
|
||||
mono_agcs_[ch]->state, split_bands, audio->num_bands(),
|
||||
audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
|
||||
stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
|
||||
capture_levels_[ch] = new_capture_level;
|
||||
|
||||
audio->ImportSplitChannelData(capture_channel, split_bands);
|
||||
error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
|
||||
|
||||
if (err != AudioProcessing::kNoError) {
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
|
||||
}
|
||||
|
||||
gain_controller->set_capture_level(capture_level_out);
|
||||
if (saturation_warning == 1) {
|
||||
stream_is_saturated_ = true;
|
||||
// Choose the minimun gain for application
|
||||
size_t index_to_apply = 0;
|
||||
for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
|
||||
if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
|
||||
index_to_apply = ch;
|
||||
}
|
||||
}
|
||||
|
||||
++capture_channel;
|
||||
if (use_legacy_gain_applier_) {
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
int16_t split_band_data[AudioBuffer::kMaxNumBands]
|
||||
[AudioBuffer::kMaxSplitFrameLength];
|
||||
int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
|
||||
split_band_data[0], split_band_data[1], split_band_data[2]};
|
||||
audio->ExportSplitChannelData(ch, split_bands);
|
||||
|
||||
int err_process = WebRtcAgc_Process(
|
||||
mono_agcs_[ch]->state, mono_agcs_[index_to_apply]->gains, split_bands,
|
||||
audio->num_bands(), split_bands);
|
||||
RTC_DCHECK_EQ(err_process, 0);
|
||||
|
||||
audio->ImportSplitChannelData(ch, split_bands);
|
||||
}
|
||||
} else {
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
|
||||
audio->split_bands(ch));
|
||||
}
|
||||
}
|
||||
|
||||
RTC_DCHECK_LT(0ul, *num_proc_channels_);
|
||||
if (mode_ == kAdaptiveAnalog) {
|
||||
// Take the analog level to be the average across the handles.
|
||||
analog_capture_level_ = 0;
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
analog_capture_level_ += gain_controller->get_capture_level();
|
||||
// Take the analog level to be the minimum accross all channels.
|
||||
analog_capture_level_ = capture_levels_[0];
|
||||
for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
|
||||
analog_capture_level_ =
|
||||
std::min(analog_capture_level_, capture_levels_[ch]);
|
||||
}
|
||||
}
|
||||
|
||||
analog_capture_level_ /= (*num_proc_channels_);
|
||||
if (error_reported) {
|
||||
return AudioProcessing::kUnspecifiedError;
|
||||
}
|
||||
|
||||
was_analog_level_set_ = false;
|
||||
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::compression_gain_db() const {
|
||||
return compression_gain_db_;
|
||||
}
|
||||
|
||||
// TODO(ajm): ensure this is called under kAdaptiveAnalog.
|
||||
int GainControlImpl::set_stream_analog_level(int level) {
|
||||
@ -282,9 +306,6 @@ int GainControlImpl::set_stream_analog_level(int level) {
|
||||
int GainControlImpl::stream_analog_level() const {
|
||||
data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
|
||||
&analog_capture_level_);
|
||||
// TODO(ajm): enable this assertion?
|
||||
// RTC_DCHECK_EQ(kAdaptiveAnalog, mode_);
|
||||
|
||||
return analog_capture_level_;
|
||||
}
|
||||
|
||||
@ -301,10 +322,6 @@ int GainControlImpl::Enable(bool enable) {
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
bool GainControlImpl::is_enabled() const {
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_mode(Mode mode) {
|
||||
if (MapSetting(mode) == -1) {
|
||||
return AudioProcessing::kBadParameterError;
|
||||
@ -317,49 +334,21 @@ int GainControlImpl::set_mode(Mode mode) {
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
GainControl::Mode GainControlImpl::mode() const {
|
||||
return mode_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
|
||||
if (minimum < 0) {
|
||||
if (minimum < 0 || maximum > 65535 || maximum < minimum) {
|
||||
return AudioProcessing::kBadParameterError;
|
||||
}
|
||||
|
||||
if (maximum > 65535) {
|
||||
return AudioProcessing::kBadParameterError;
|
||||
}
|
||||
|
||||
if (maximum < minimum) {
|
||||
return AudioProcessing::kBadParameterError;
|
||||
}
|
||||
|
||||
size_t num_proc_channels_local = 0u;
|
||||
int sample_rate_hz_local = 0;
|
||||
{
|
||||
minimum_capture_level_ = minimum;
|
||||
maximum_capture_level_ = maximum;
|
||||
|
||||
RTC_DCHECK(num_proc_channels_);
|
||||
RTC_DCHECK(sample_rate_hz_);
|
||||
num_proc_channels_local = *num_proc_channels_;
|
||||
sample_rate_hz_local = *sample_rate_hz_;
|
||||
}
|
||||
Initialize(num_proc_channels_local, sample_rate_hz_local);
|
||||
Initialize(*num_proc_channels_, *sample_rate_hz_);
|
||||
return AudioProcessing::kNoError;
|
||||
}
|
||||
|
||||
int GainControlImpl::analog_level_minimum() const {
|
||||
return minimum_capture_level_;
|
||||
}
|
||||
|
||||
int GainControlImpl::analog_level_maximum() const {
|
||||
return maximum_capture_level_;
|
||||
}
|
||||
|
||||
bool GainControlImpl::stream_is_saturated() const {
|
||||
return stream_is_saturated_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_target_level_dbfs(int level) {
|
||||
if (level > 31 || level < 0) {
|
||||
@ -369,10 +358,6 @@ int GainControlImpl::set_target_level_dbfs(int level) {
|
||||
return Configure();
|
||||
}
|
||||
|
||||
int GainControlImpl::target_level_dbfs() const {
|
||||
return target_level_dbfs_;
|
||||
}
|
||||
|
||||
int GainControlImpl::set_compression_gain_db(int gain) {
|
||||
if (gain < 0 || gain > 90) {
|
||||
RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
|
||||
@ -387,10 +372,6 @@ int GainControlImpl::enable_limiter(bool enable) {
|
||||
return Configure();
|
||||
}
|
||||
|
||||
bool GainControlImpl::is_limiter_enabled() const {
|
||||
return limiter_enabled_;
|
||||
}
|
||||
|
||||
void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
|
||||
data_dumper_->InitiateNewSetOfRecordings();
|
||||
|
||||
@ -401,13 +382,18 @@ void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
|
||||
return;
|
||||
}
|
||||
|
||||
gain_controllers_.resize(*num_proc_channels_);
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
if (!gain_controller) {
|
||||
gain_controller.reset(new GainController());
|
||||
mono_agcs_.resize(*num_proc_channels_);
|
||||
capture_levels_.resize(*num_proc_channels_);
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
if (!mono_agcs_[ch]) {
|
||||
mono_agcs_[ch].reset(new MonoAgcState());
|
||||
}
|
||||
gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_,
|
||||
mode_, *sample_rate_hz_, analog_capture_level_);
|
||||
|
||||
int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
|
||||
maximum_capture_level_, MapSetting(mode_),
|
||||
*sample_rate_hz_);
|
||||
RTC_DCHECK_EQ(error, 0);
|
||||
capture_levels_[ch] = analog_capture_level_;
|
||||
}
|
||||
|
||||
Configure();
|
||||
@ -424,11 +410,10 @@ int GainControlImpl::Configure() {
|
||||
config.limiterEnable = limiter_enabled_;
|
||||
|
||||
int error = AudioProcessing::kNoError;
|
||||
for (auto& gain_controller : gain_controllers_) {
|
||||
const int handle_error =
|
||||
WebRtcAgc_set_config(gain_controller->state(), config);
|
||||
if (handle_error != AudioProcessing::kNoError) {
|
||||
error = handle_error;
|
||||
for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
|
||||
int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
|
||||
if (error_ch != AudioProcessing::kNoError) {
|
||||
error = error_ch;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
|
||||
@ -20,7 +20,6 @@
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_processing/agc/gain_control.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -45,13 +44,13 @@ class GainControlImpl : public GainControl {
|
||||
std::vector<int16_t>* packed_buffer);
|
||||
|
||||
// GainControl implementation.
|
||||
bool is_enabled() const override;
|
||||
bool is_enabled() const override { return enabled_; }
|
||||
int stream_analog_level() const override;
|
||||
bool is_limiter_enabled() const override;
|
||||
Mode mode() const override;
|
||||
bool is_limiter_enabled() const override { return limiter_enabled_; }
|
||||
Mode mode() const override { return mode_; }
|
||||
int Enable(bool enable) override;
|
||||
int set_mode(Mode mode) override;
|
||||
int compression_gain_db() const override;
|
||||
int compression_gain_db() const override { return compression_gain_db_; }
|
||||
int set_analog_level_limits(int minimum, int maximum) override;
|
||||
int set_compression_gain_db(int gain) override;
|
||||
int set_target_level_dbfs(int level) override;
|
||||
@ -59,13 +58,13 @@ class GainControlImpl : public GainControl {
|
||||
int set_stream_analog_level(int level) override;
|
||||
|
||||
private:
|
||||
class GainController;
|
||||
struct MonoAgcState;
|
||||
|
||||
// GainControl implementation.
|
||||
int target_level_dbfs() const override;
|
||||
int analog_level_minimum() const override;
|
||||
int analog_level_maximum() const override;
|
||||
bool stream_is_saturated() const override;
|
||||
int target_level_dbfs() const override { return target_level_dbfs_; }
|
||||
int analog_level_minimum() const override { return minimum_capture_level_; }
|
||||
int analog_level_maximum() const override { return maximum_capture_level_; }
|
||||
bool stream_is_saturated() const override { return stream_is_saturated_; }
|
||||
|
||||
int Configure();
|
||||
|
||||
@ -73,6 +72,7 @@ class GainControlImpl : public GainControl {
|
||||
|
||||
bool enabled_ = false;
|
||||
|
||||
const bool use_legacy_gain_applier_;
|
||||
Mode mode_;
|
||||
int minimum_capture_level_;
|
||||
int maximum_capture_level_;
|
||||
@ -83,7 +83,8 @@ class GainControlImpl : public GainControl {
|
||||
bool was_analog_level_set_;
|
||||
bool stream_is_saturated_;
|
||||
|
||||
std::vector<std::unique_ptr<GainController>> gain_controllers_;
|
||||
std::vector<std::unique_ptr<MonoAgcState>> mono_agcs_;
|
||||
std::vector<int> capture_levels_;
|
||||
|
||||
absl::optional<size_t> num_proc_channels_;
|
||||
absl::optional<int> sample_rate_hz_;
|
||||
|
||||
@ -133,21 +133,6 @@ void RunBitExactnessTest(int sample_rate_hz,
|
||||
// Chromium ARM and ARM64 boths have been identified. This is tracked in the
|
||||
// issue https://bugs.chromium.org/p/webrtc/issues/detail?id=5711.
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
Mono8kHz_AdaptiveAnalog_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#else
|
||||
TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono8kHz_AdaptiveAnalog_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.006622f, -0.002747f, 0.001587f};
|
||||
RunBitExactnessTest(8000, 1, GainControl::Mode::kAdaptiveAnalog, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
}
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
@ -209,21 +194,6 @@ TEST(GainControlBitExactnessTest,
|
||||
kOutputReference);
|
||||
}
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
Mono8kHz_AdaptiveDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#else
|
||||
TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono8kHz_AdaptiveDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.004028f, -0.001678f, 0.000946f};
|
||||
RunBitExactnessTest(8000, 1, GainControl::Mode::kAdaptiveDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
}
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
@ -264,7 +234,7 @@ TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono32kHz_AdaptiveDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.006104f, -0.005524f, -0.004974f};
|
||||
const float kOutputReference[] = {-0.006134f, -0.005524f, -0.005005f};
|
||||
RunBitExactnessTest(32000, 1, GainControl::Mode::kAdaptiveDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
@ -279,27 +249,12 @@ TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono48kHz_AdaptiveDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.006104f, -0.005524f, -0.004974f};
|
||||
const float kOutputReference[] = {-0.006134f, -0.005524f, -0.005005};
|
||||
RunBitExactnessTest(32000, 1, GainControl::Mode::kAdaptiveDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
}
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
Mono8kHz_FixedDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#else
|
||||
TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono8kHz_FixedDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.011871f, -0.004944f, 0.002838f};
|
||||
RunBitExactnessTest(8000, 1, GainControl::Mode::kFixedDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
}
|
||||
|
||||
#if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
|
||||
defined(WEBRTC_ANDROID))
|
||||
TEST(GainControlBitExactnessTest,
|
||||
@ -324,8 +279,8 @@ TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Stereo16kHz_FixedDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.048950f, -0.028503f, -0.050354f,
|
||||
-0.048950f, -0.028503f, -0.050354f};
|
||||
const float kOutputReference[] = {-0.048896f, -0.028479f, -0.050345f,
|
||||
-0.048896f, -0.028479f, -0.050345f};
|
||||
RunBitExactnessTest(16000, 2, GainControl::Mode::kFixedDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
@ -340,7 +295,7 @@ TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono32kHz_FixedDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.018188f, -0.016418f, -0.014862f};
|
||||
const float kOutputReference[] = {-0.018158f, -0.016357f, -0.014832f};
|
||||
RunBitExactnessTest(32000, 1, GainControl::Mode::kFixedDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
@ -355,7 +310,7 @@ TEST(GainControlBitExactnessTest,
|
||||
DISABLED_Mono48kHz_FixedDigital_Tl10_SL50_CG5_Lim_AL0_100) {
|
||||
#endif
|
||||
const int kStreamAnalogLevelReference = 50;
|
||||
const float kOutputReference[] = {-0.018188f, -0.016418f, -0.014862f};
|
||||
const float kOutputReference[] = {-0.018158f, -0.016357f, -0.014832f};
|
||||
RunBitExactnessTest(32000, 1, GainControl::Mode::kFixedDigital, 10, 50, 5,
|
||||
true, 0, 100, kStreamAnalogLevelReference,
|
||||
kOutputReference);
|
||||
|
||||
@ -1 +1 @@
|
||||
f85386d49e89027aa14f2aad36537a8a4e887a61
|
||||
4010b1fe15eda1b42968cdb3f9fed399e1aa7197
|
||||
@ -1 +1 @@
|
||||
734cc6174a5dac2fd87de267fe8d12519fe18321
|
||||
8d368435bbc80edab08205c6f21db1416e119119
|
||||
Loading…
x
Reference in New Issue
Block a user