webrtc 自动增益AGC源码分析(一)

webrtc的自动增益模块在agc_legacy_c工程下:

analog_agc.c analog_agc.h digital_agc.c digital_agc.h gain_control.h

主要函数包括:

WebRtcAgc_AddMic

WebRtcAgc_AddFarend

WebRtcAgc_GetAddFarendError

WebRtcAgc_VirtualMic

WebRtcAgc_UpdateAgcThresholds

WebRtcAgc_SaturationCtrl

WebRtcAgc_ZeroCtrl

WebRtcAgc_SpeakerInactiveCtrl

WebRtcAgc_ExpCurve

WebRtcAgc_ProcessAnalog

WebRtcAgc_Process

WebRtcAgc_set_config

WebRtcAgc_get_config

WebRtcAgc_Create

WebRtcAgc_Free

WebRtcAgc_Init

WebRtcAgc_CalculateGainTable

WebRtcAgc_InitDigital

WebRtcAgc_AddFarendToDigital

WebRtcAgc_ProcessDigital

WebRtcAgc_InitVad

WebRtcAgc_ProcessVad

 

核心函数介绍:WebRtcAgc_Init

/* minLevel     - Minimum volume level
 * maxLevel     - Maximum volume level
 */
int WebRtcAgc_Init(void* agcInst,
                   int32_t minLevel,
                   int32_t maxLevel,
                   int16_t agcMode,
                   uint32_t fs) {
  int32_t max_add, tmp32;
  int16_t i;
  int tmpNorm;
  LegacyAgc* stt;

  /* typecast state pointer */
  stt = (LegacyAgc*)agcInst;

  if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) {
    stt->lastError = AGC_UNINITIALIZED_ERROR;
    return -1;
  }

  /* Analog AGC variables */
  stt->envSum = 0;

/* mode     = 0 - Only saturation protection
 *            1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3
 * dBOv)]
 *            2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3
 * 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;
  stt->fs = fs;

  /* initialize input VAD */
  WebRtcAgc_InitVad(&stt->vadMic);

  /* If the volume range is smaller than 0-256 then
   * the levels are shifted up to Q8-domain */
  tmpNorm = WebRtcSpl_NormU32((uint32_t)maxLevel);
  stt->scale = tmpNorm - 23;
  if (stt->scale < 0) {
    stt->scale = 0;
  }
  // TODO(bjornv): Investigate if we really need to scale up a small range now
  // when we have
  // a guard against zero-increments. For now, we do not support scale up (scale
  // = 0).
  stt->scale = 0;
  maxLevel <<= stt->scale;
  minLevel <<= stt->scale;

  /* Make minLevel and maxLevel static in AdaptiveDigital */
  if (stt->agcMode == kAgcModeAdaptiveDigital) {
    minLevel = 0;
    maxLevel = 255;
    stt->scale = 0;
  }
  /* The maximum supplemental volume range is based on a vague idea
   * of how much lower the gain will be than the real analog gain. */
  max_add = (maxLevel - minLevel) / 4;

  /* Minimum/maximum volume level that can be set */
  stt->minLevel = minLevel;
  stt->maxAnalog = maxLevel;
  stt->maxLevel = maxLevel + max_add;
  stt->maxInit = stt->maxLevel;

  stt->zeroCtrlMax = stt->maxAnalog;
  stt->lastInMicLevel = 0;

  /* Initialize micVol parameter */
  stt->micVol = stt->maxAnalog;
  if (stt->agcMode == kAgcModeAdaptiveDigital) {
    stt->micVol = 127; /* Mid-point of mic level */
  }
  stt->micRef = stt->micVol;
  stt->micGainIdx = 127;
#ifdef MIC_LEVEL_FEEDBACK
  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
   */
  tmp32 = ((stt->maxLevel - stt->minLevel) * 10) >> 8;
  stt->minOutput = (stt->minLevel + tmp32);

  stt->msTooLow = 0;
  stt->msTooHigh = 0;
  stt->changeToSlowMode = 0;
  stt->firstCall = 0;
  stt->msZero = 0;
  stt->muteGuardMs = 0;
  stt->gainTableIdx = 0;

  stt->msecSpeechInnerChange = kMsecSpeechInner;
  stt->msecSpeechOuterChange = kMsecSpeechOuter;

  stt->activeSpeech = 0;
  stt->Rxx16_LPw32Max = 0;

  stt->vadThreshold = kNormalVadThreshold;
  stt->inActive = 0;

  for (i = 0; i < RXX_BUFFER_LEN; i++) {
    stt->Rxx16_vectorw32[i] = (int32_t)1000; /* -54dBm0 */
  }
  stt->Rxx160w32 =
      125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */

  stt->Rxx16pos = 0;
  stt->Rxx16_LPw32 = (int32_t)16284; /* Q(-4) */

  for (i = 0; i < 5; i++) {
    stt->Rxx16w32_array[0][i] = 0;
  }
  for (i = 0; i < 10; i++) {
    stt->env[0][i] = 0;
    stt->env[1][i] = 0;
  }
  stt->inQueue = 0;

#ifdef MIC_LEVEL_FEEDBACK
  stt->targetIdxOffset = 0;
#endif

  WebRtcSpl_MemSetW32(stt->filterState, 0, 8);

  stt->initFlag = kInitCheck;
  // Default config settings.
  stt->defaultConfig.limiterEnable = kAgcTrue;
  stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL;
  stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN;

  if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) {
    stt->lastError = AGC_UNSPECIFIED_ERROR;
    return -1;
  }
  stt->Rxx160_LPw32 = stt->analogTargetLevel;  // Initialize rms value

  stt->lowLevelSignal = 0;

  /* 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;
  }
}

WebRtcAgc_InitDigital函数:

int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
  if (agcMode == kAgcModeFixedDigital) {
    // start at minimum to find correct gain faster
    stt->capacitorSlow = 0;
  } else {
    // start out with 0 dB gain
    stt->capacitorSlow = 134217728;  // (int32_t)(0.125f * 32768.0f * 32768.0f);
  }
  stt->capacitorFast = 0;
  stt->gain = 65536;
  stt->gatePrevious = 0;
  stt->agcMode = agcMode;
#ifdef WEBRTC_AGC_DEBUG_DUMP
  stt->frameCounter = 0;
#endif

  // initialize VADs
  WebRtcAgc_InitVad(&stt->vadNearend);
  WebRtcAgc_InitVad(&stt->vadFarend);

  return 0;
}

WebRtcAgc_InitVad函数:

void WebRtcAgc_InitVad(AgcVad* state) {
  int16_t k;

  state->HPstate = 0;   // state of high pass filter
  state->logRatio = 0;  // log( P(active) / P(inactive) )
  // average input level (Q10)
  state->meanLongTerm = 15 << 10;

  // variance of input level (Q8)
  state->varianceLongTerm = 500 << 8;

  state->stdLongTerm = 0;  // standard deviation of input level in dB
  // short-term average input level (Q10)
  state->meanShortTerm = 15 << 10;

  // short-term variance of input level (Q8)
  state->varianceShortTerm = 500 << 8;

  state->stdShortTerm =
      0;               // short-term standard deviation of input level in dB
  state->counter = 3;  // counts updates
  for (k = 0; k < 8; k++) {
    // downsampling filter
    state->downState[k] = 0;
  }
}

WebRtcAgc_set_config函数:

int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig agcConfig) {
  LegacyAgc* stt;
  stt = (LegacyAgc*)agcInst;

  if (stt == NULL) {
    return -1;
  }

  if (stt->initFlag != kInitCheck) {
    stt->lastError = AGC_UNINITIALIZED_ERROR;
    return -1;
  }

  if (agcConfig.limiterEnable != kAgcFalse &&
      agcConfig.limiterEnable != kAgcTrue) {
    stt->lastError = AGC_BAD_PARAMETER_ERROR;
    return -1;
  }
  stt->limiterEnable = agcConfig.limiterEnable;
  stt->compressionGaindB = agcConfig.compressionGaindB;
  if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) {
    stt->lastError = AGC_BAD_PARAMETER_ERROR;
    return -1;
  }
  stt->targetLevelDbfs = agcConfig.targetLevelDbfs;

  if (stt->agcMode == kAgcModeFixedDigital) {
    /* Adjust for different parameter interpretation in FixedDigital mode */
    stt->compressionGaindB += agcConfig.targetLevelDbfs;
  }

  /* Update threshold levels for analog adaptation */
  WebRtcAgc_UpdateAgcThresholds(stt);

  /* Recalculate gain table */
  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 */
  stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB;
  stt->usedConfig.limiterEnable = agcConfig.limiterEnable;
  stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs;

  return 0;
}

 

你可能感兴趣的:(WebRTC流媒体技术)