From b4cd342eb98408eafc62f819fb521277ef3d3caf Mon Sep 17 00:00:00 2001 From: "bjornv@webrtc.org" Date: Fri, 15 Feb 2013 18:40:34 +0000 Subject: [PATCH] This refactoring CL contains an API to get low level echo metrics stats. TEST=audioproc_unittest, trybots BUG=None Review URL: https://webrtc-codereview.appspot.com/1107007 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3523 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../modules/audio_processing/aec/aec_core.c | 15 +- .../modules/audio_processing/aec/aec_core.h | 30 ++-- .../audio_processing/aec/echo_cancellation.c | 159 +++++++++--------- .../aec/include/echo_cancellation.h | 14 +- 4 files changed, 114 insertions(+), 104 deletions(-) diff --git a/webrtc/modules/audio_processing/aec/aec_core.c b/webrtc/modules/audio_processing/aec/aec_core.c index 2dbd067c5..104b3dd85 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.c +++ b/webrtc/modules/audio_processing/aec/aec_core.c @@ -122,7 +122,7 @@ static void ComfortNoise(aec_t *aec, float efw[2][PART_LEN1], const float *noisePow, const float *lambda); static void WebRtcAec_InitLevel(power_level_t *level); -static void WebRtcAec_InitStats(stats_t *stats); +static void WebRtcAec_InitStats(stats* stats); static void UpdateLevel(power_level_t* level, float in[2][PART_LEN1]); static void UpdateMetrics(aec_t *aec); // Convert from time domain to frequency domain. Note that |time_data| are @@ -721,6 +721,17 @@ int WebRtcAec_echo_state(aec_t* self) { return self->echoState; } +void WebRtcAec_GetEchoStats(aec_t* self, stats* erl, stats* erle, + stats* a_nlp) { + assert(self != NULL); + assert(erl != NULL); + assert(erle != NULL); + assert(a_nlp != NULL); + *erl = self->erl; + *erle = self->erle; + *a_nlp = self->aNlp; +} + static void ProcessBlock(aec_t* aec) { int i; float d[PART_LEN], y[PART_LEN], e[PART_LEN], dH[PART_LEN]; @@ -1391,7 +1402,7 @@ static void WebRtcAec_InitLevel(power_level_t *level) level->sfrcounter = 0; } -static void WebRtcAec_InitStats(stats_t *stats) +static void WebRtcAec_InitStats(stats* stats) { stats->instant = offsetLevel; stats->average = offsetLevel; diff --git a/webrtc/modules/audio_processing/aec/aec_core.h b/webrtc/modules/audio_processing/aec/aec_core.h index 7474ec76c..a740b0dc4 100644 --- a/webrtc/modules/audio_processing/aec/aec_core.h +++ b/webrtc/modules/audio_processing/aec/aec_core.h @@ -56,16 +56,16 @@ typedef struct { } power_level_t; typedef struct { - float instant; - float average; - float min; - float max; - float sum; - float hisum; - float himean; - int counter; - int hicounter; -} stats_t; + float instant; + float average; + float min; + float max; + float sum; + float hisum; + float himean; + int counter; + int hicounter; +} stats; typedef struct { int farBufWritePos, farBufReadPos; @@ -131,10 +131,10 @@ typedef struct { int metricsMode; int stateCounter; - stats_t erl; - stats_t erle; - stats_t aNlp; - stats_t rerl; + stats erl; + stats erle; + stats aNlp; + stats rerl; // Quantities to control H band scaling for SWB input int freq_avg_ic; // initial bin for averaging nlp gain @@ -187,5 +187,7 @@ int WebRtcAec_MoveFarReadPtr(aec_t* aec, int elements); int WebRtcAec_GetDelayMetricsCore(aec_t* self, int* median, int* std); // Returns the echo state (1: echo, 0: no echo). int WebRtcAec_echo_state(aec_t* self); +// Gets statistics of the echo metrics ERL, ERLE, A_NLP. +void WebRtcAec_GetEchoStats(aec_t* self, stats* erl, stats* erle, stats* a_nlp); #endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ diff --git a/webrtc/modules/audio_processing/aec/echo_cancellation.c b/webrtc/modules/audio_processing/aec/echo_cancellation.c index c6aa45451..25f44e2d6 100644 --- a/webrtc/modules/audio_processing/aec/echo_cancellation.c +++ b/webrtc/modules/audio_processing/aec/echo_cancellation.c @@ -629,104 +629,101 @@ int WebRtcAec_get_echo_status(void* handle, int* status) { return 0; } -WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics) -{ - const float upweight = 0.7f; - float dtmp; - short stmp; - aecpc_t *aecpc = aecInst; +int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) { + const float kUpWeight = 0.7f; + float dtmp; + int stmp; + aecpc_t* self = (aecpc_t*)handle; + stats erl; + stats erle; + stats a_nlp; - if (aecpc == NULL) { - return -1; - } + if (handle == NULL ) { + return -1; + } + if (metrics == NULL ) { + self->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + if (self->initFlag != initCheck) { + self->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } - if (metrics == NULL) { - aecpc->lastError = AEC_NULL_POINTER_ERROR; - return -1; - } + WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp); - if (aecpc->initFlag != initCheck) { - aecpc->lastError = AEC_UNINITIALIZED_ERROR; - return -1; - } + // ERL + metrics->erl.instant = (int) erl.instant; - // ERL - metrics->erl.instant = (short) aecpc->aec->erl.instant; + if ((erl.himean > offsetLevel) && (erl.average > offsetLevel)) { + // Use a mix between regular average and upper part average. + dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average; + metrics->erl.average = (int) dtmp; + } else { + metrics->erl.average = offsetLevel; + } - if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) { - // Use a mix between regular average and upper part average - dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average; - metrics->erl.average = (short) dtmp; - } - else { - metrics->erl.average = offsetLevel; - } + metrics->erl.max = (int) erl.max; - metrics->erl.max = (short) aecpc->aec->erl.max; + if (erl.min < (offsetLevel * (-1))) { + metrics->erl.min = (int) erl.min; + } else { + metrics->erl.min = offsetLevel; + } - if (aecpc->aec->erl.min < (offsetLevel * (-1))) { - metrics->erl.min = (short) aecpc->aec->erl.min; - } - else { - metrics->erl.min = offsetLevel; - } + // ERLE + metrics->erle.instant = (int) erle.instant; - // ERLE - metrics->erle.instant = (short) aecpc->aec->erle.instant; + if ((erle.himean > offsetLevel) && (erle.average > offsetLevel)) { + // Use a mix between regular average and upper part average. + dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average; + metrics->erle.average = (int) dtmp; + } else { + metrics->erle.average = offsetLevel; + } - if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) { - // Use a mix between regular average and upper part average - dtmp = upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average; - metrics->erle.average = (short) dtmp; - } - else { - metrics->erle.average = offsetLevel; - } + metrics->erle.max = (int) erle.max; - metrics->erle.max = (short) aecpc->aec->erle.max; + if (erle.min < (offsetLevel * (-1))) { + metrics->erle.min = (int) erle.min; + } else { + metrics->erle.min = offsetLevel; + } - if (aecpc->aec->erle.min < (offsetLevel * (-1))) { - metrics->erle.min = (short) aecpc->aec->erle.min; - } else { - metrics->erle.min = offsetLevel; - } + // RERL + if ((metrics->erl.average > offsetLevel) + && (metrics->erle.average > offsetLevel)) { + stmp = metrics->erl.average + metrics->erle.average; + } else { + stmp = offsetLevel; + } + metrics->rerl.average = stmp; - // RERL - if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) { - stmp = metrics->erl.average + metrics->erle.average; - } - else { - stmp = offsetLevel; - } - metrics->rerl.average = stmp; + // No other statistics needed, but returned for completeness. + metrics->rerl.instant = stmp; + metrics->rerl.max = stmp; + metrics->rerl.min = stmp; - // No other statistics needed, but returned for completeness - metrics->rerl.instant = stmp; - metrics->rerl.max = stmp; - metrics->rerl.min = stmp; + // A_NLP + metrics->aNlp.instant = (int) a_nlp.instant; - // A_NLP - metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant; + if ((a_nlp.himean > offsetLevel) && (a_nlp.average > offsetLevel)) { + // Use a mix between regular average and upper part average. + dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average; + metrics->aNlp.average = (int) dtmp; + } else { + metrics->aNlp.average = offsetLevel; + } - if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) { - // Use a mix between regular average and upper part average - dtmp = upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average; - metrics->aNlp.average = (short) dtmp; - } - else { - metrics->aNlp.average = offsetLevel; - } + metrics->aNlp.max = (int) a_nlp.max; - metrics->aNlp.max = (short) aecpc->aec->aNlp.max; + if (a_nlp.min < (offsetLevel * (-1))) { + metrics->aNlp.min = (int) a_nlp.min; + } else { + metrics->aNlp.min = offsetLevel; + } - if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) { - metrics->aNlp.min = (short) aecpc->aec->aNlp.min; - } - else { - metrics->aNlp.min = offsetLevel; - } - - return 0; + return 0; } int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std) { diff --git a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h b/webrtc/modules/audio_processing/aec/include/echo_cancellation.h index 82dc0d3b1..367ed5614 100644 --- a/webrtc/modules/audio_processing/aec/include/echo_cancellation.h +++ b/webrtc/modules/audio_processing/aec/include/echo_cancellation.h @@ -43,10 +43,10 @@ typedef struct { } AecConfig; typedef struct { - WebRtc_Word16 instant; - WebRtc_Word16 average; - WebRtc_Word16 max; - WebRtc_Word16 min; + int instant; + int average; + int max; + int min; } AecLevel; typedef struct { @@ -215,16 +215,16 @@ int WebRtcAec_get_echo_status(void* handle, int* status); * * Inputs Description * ------------------------------------------------------------------- - * void *aecInst Pointer to the AEC instance + * void *handle Pointer to the AEC instance * * Outputs Description * ------------------------------------------------------------------- * AecMetrics *metrics Struct which will be filled out with the * current echo metrics. - * WebRtc_Word32 return 0: OK + * int return 0: OK * -1: error */ -WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics); +int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics); /* * Gets the current delay metrics for the session.