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
This commit is contained in:
bjornv@webrtc.org 2013-02-15 18:40:34 +00:00
parent 21a2fc902d
commit b4cd342eb9
4 changed files with 114 additions and 104 deletions

View File

@ -122,7 +122,7 @@ static void ComfortNoise(aec_t *aec, float efw[2][PART_LEN1],
const float *noisePow, const float *lambda); const float *noisePow, const float *lambda);
static void WebRtcAec_InitLevel(power_level_t *level); 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 UpdateLevel(power_level_t* level, float in[2][PART_LEN1]);
static void UpdateMetrics(aec_t *aec); static void UpdateMetrics(aec_t *aec);
// Convert from time domain to frequency domain. Note that |time_data| are // 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; 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) { static void ProcessBlock(aec_t* aec) {
int i; int i;
float d[PART_LEN], y[PART_LEN], e[PART_LEN], dH[PART_LEN]; 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; level->sfrcounter = 0;
} }
static void WebRtcAec_InitStats(stats_t *stats) static void WebRtcAec_InitStats(stats* stats)
{ {
stats->instant = offsetLevel; stats->instant = offsetLevel;
stats->average = offsetLevel; stats->average = offsetLevel;

View File

@ -65,7 +65,7 @@ typedef struct {
float himean; float himean;
int counter; int counter;
int hicounter; int hicounter;
} stats_t; } stats;
typedef struct { typedef struct {
int farBufWritePos, farBufReadPos; int farBufWritePos, farBufReadPos;
@ -131,10 +131,10 @@ typedef struct {
int metricsMode; int metricsMode;
int stateCounter; int stateCounter;
stats_t erl; stats erl;
stats_t erle; stats erle;
stats_t aNlp; stats aNlp;
stats_t rerl; stats rerl;
// Quantities to control H band scaling for SWB input // Quantities to control H band scaling for SWB input
int freq_avg_ic; // initial bin for averaging nlp gain 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); int WebRtcAec_GetDelayMetricsCore(aec_t* self, int* median, int* std);
// Returns the echo state (1: echo, 0: no echo). // Returns the echo state (1: echo, 0: no echo).
int WebRtcAec_echo_state(aec_t* self); 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_ #endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_

View File

@ -629,100 +629,97 @@ int WebRtcAec_get_echo_status(void* handle, int* status) {
return 0; return 0;
} }
WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics) int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
{ const float kUpWeight = 0.7f;
const float upweight = 0.7f;
float dtmp; float dtmp;
short stmp; int stmp;
aecpc_t *aecpc = aecInst; aecpc_t* self = (aecpc_t*)handle;
stats erl;
stats erle;
stats a_nlp;
if (aecpc == NULL) { if (handle == NULL ) {
return -1; return -1;
} }
if (metrics == NULL ) { if (metrics == NULL ) {
aecpc->lastError = AEC_NULL_POINTER_ERROR; self->lastError = AEC_NULL_POINTER_ERROR;
return -1;
}
if (self->initFlag != initCheck) {
self->lastError = AEC_UNINITIALIZED_ERROR;
return -1; return -1;
} }
if (aecpc->initFlag != initCheck) { WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp);
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
return -1;
}
// ERL // ERL
metrics->erl.instant = (short) aecpc->aec->erl.instant; metrics->erl.instant = (int) erl.instant;
if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) { if ((erl.himean > offsetLevel) && (erl.average > offsetLevel)) {
// Use a mix between regular average and upper part average // Use a mix between regular average and upper part average.
dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average; dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average;
metrics->erl.average = (short) dtmp; metrics->erl.average = (int) dtmp;
} } else {
else {
metrics->erl.average = offsetLevel; metrics->erl.average = offsetLevel;
} }
metrics->erl.max = (short) aecpc->aec->erl.max; metrics->erl.max = (int) erl.max;
if (aecpc->aec->erl.min < (offsetLevel * (-1))) { if (erl.min < (offsetLevel * (-1))) {
metrics->erl.min = (short) aecpc->aec->erl.min; metrics->erl.min = (int) erl.min;
} } else {
else {
metrics->erl.min = offsetLevel; metrics->erl.min = offsetLevel;
} }
// ERLE // ERLE
metrics->erle.instant = (short) aecpc->aec->erle.instant; metrics->erle.instant = (int) erle.instant;
if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) { if ((erle.himean > offsetLevel) && (erle.average > offsetLevel)) {
// Use a mix between regular average and upper part average // Use a mix between regular average and upper part average.
dtmp = upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average; dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average;
metrics->erle.average = (short) dtmp; metrics->erle.average = (int) dtmp;
} } else {
else {
metrics->erle.average = offsetLevel; metrics->erle.average = offsetLevel;
} }
metrics->erle.max = (short) aecpc->aec->erle.max; metrics->erle.max = (int) erle.max;
if (aecpc->aec->erle.min < (offsetLevel * (-1))) { if (erle.min < (offsetLevel * (-1))) {
metrics->erle.min = (short) aecpc->aec->erle.min; metrics->erle.min = (int) erle.min;
} else { } else {
metrics->erle.min = offsetLevel; metrics->erle.min = offsetLevel;
} }
// RERL // RERL
if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) { if ((metrics->erl.average > offsetLevel)
&& (metrics->erle.average > offsetLevel)) {
stmp = metrics->erl.average + metrics->erle.average; stmp = metrics->erl.average + metrics->erle.average;
} } else {
else {
stmp = offsetLevel; stmp = offsetLevel;
} }
metrics->rerl.average = stmp; metrics->rerl.average = stmp;
// No other statistics needed, but returned for completeness // No other statistics needed, but returned for completeness.
metrics->rerl.instant = stmp; metrics->rerl.instant = stmp;
metrics->rerl.max = stmp; metrics->rerl.max = stmp;
metrics->rerl.min = stmp; metrics->rerl.min = stmp;
// A_NLP // A_NLP
metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant; metrics->aNlp.instant = (int) a_nlp.instant;
if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) { if ((a_nlp.himean > offsetLevel) && (a_nlp.average > offsetLevel)) {
// Use a mix between regular average and upper part average // Use a mix between regular average and upper part average.
dtmp = upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average; dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average;
metrics->aNlp.average = (short) dtmp; metrics->aNlp.average = (int) dtmp;
} } else {
else {
metrics->aNlp.average = offsetLevel; metrics->aNlp.average = offsetLevel;
} }
metrics->aNlp.max = (short) aecpc->aec->aNlp.max; metrics->aNlp.max = (int) a_nlp.max;
if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) { if (a_nlp.min < (offsetLevel * (-1))) {
metrics->aNlp.min = (short) aecpc->aec->aNlp.min; metrics->aNlp.min = (int) a_nlp.min;
} } else {
else {
metrics->aNlp.min = offsetLevel; metrics->aNlp.min = offsetLevel;
} }

View File

@ -43,10 +43,10 @@ typedef struct {
} AecConfig; } AecConfig;
typedef struct { typedef struct {
WebRtc_Word16 instant; int instant;
WebRtc_Word16 average; int average;
WebRtc_Word16 max; int max;
WebRtc_Word16 min; int min;
} AecLevel; } AecLevel;
typedef struct { typedef struct {
@ -215,16 +215,16 @@ int WebRtcAec_get_echo_status(void* handle, int* status);
* *
* Inputs Description * Inputs Description
* ------------------------------------------------------------------- * -------------------------------------------------------------------
* void *aecInst Pointer to the AEC instance * void *handle Pointer to the AEC instance
* *
* Outputs Description * Outputs Description
* ------------------------------------------------------------------- * -------------------------------------------------------------------
* AecMetrics *metrics Struct which will be filled out with the * AecMetrics *metrics Struct which will be filled out with the
* current echo metrics. * current echo metrics.
* WebRtc_Word32 return 0: OK * int return 0: OK
* -1: error * -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. * Gets the current delay metrics for the session.