diff --git a/src/voice_engine/main/interface/voe_audio_processing.h b/src/voice_engine/main/interface/voe_audio_processing.h index 0b72952f30..541807bc82 100644 --- a/src/voice_engine/main/interface/voe_audio_processing.h +++ b/src/voice_engine/main/interface/voe_audio_processing.h @@ -149,17 +149,22 @@ public: // and 0 if silence. The output is always 1 if VAD is disabled. virtual int VoiceActivityIndicator(int channel) = 0; - // Enables or disables the possibility to retrieve instantaneous - // echo metrics during an active call. - virtual int SetEchoMetricsStatus(bool enable) = 0; + // Enables or disables the possibility to retrieve echo metrics and delay + // logging values during an active call. The metrics are only supported in + // AEC. + virtual int SetEcMetricsStatus(bool enable) = 0; - // Gets the current echo metric status. - virtual int GetEchoMetricsStatus(bool& enabled) = 0; + // Gets the current EC metric status. + virtual int GetEcMetricsStatus(bool& enabled) = 0; - // Gets the instantaneous echo level metrics for the near-end and - // far-end signals. + // Gets the instantaneous echo level metrics. virtual int GetEchoMetrics(int& ERL, int& ERLE, int& RERL, int& A_NLP) = 0; + // Gets the EC internal |delay_median| and |delay_std| in ms between + // near-end and far-end. The values are calculated over the time period + // since the last GetEcDelayMetrics() call. + virtual int GetEcDelayMetrics(int& delay_median, int& delay_std) = 0; + // Enables recording of Audio Processing (AP) debugging information. // The file can later be used for off-line analysis of the AP performance. virtual int StartDebugRecording(const char* fileNameUTF8) = 0; diff --git a/src/voice_engine/main/source/voe_audio_processing_impl.cc b/src/voice_engine/main/source/voe_audio_processing_impl.cc index c47946e88c..c053aea796 100644 --- a/src/voice_engine/main/source/voe_audio_processing_impl.cc +++ b/src/voice_engine/main/source/voe_audio_processing_impl.cc @@ -946,9 +946,9 @@ int VoEAudioProcessingImpl::VoiceActivityIndicator(int channel) return activity; } -int VoEAudioProcessingImpl::SetEchoMetricsStatus(bool enable) { +int VoEAudioProcessingImpl::SetEcMetricsStatus(bool enable) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), - "SetEchoMetricsStatus(enable=%d)", enable); + "SetEcMetricsStatus(enable=%d)", enable); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); @@ -958,11 +958,13 @@ int VoEAudioProcessingImpl::SetEchoMetricsStatus(bool enable) { return -1; } - if (_audioProcessingModulePtr->echo_cancellation()->enable_metrics(enable) != - 0) { + if ((_audioProcessingModulePtr->echo_cancellation()->enable_metrics(enable) + != 0) || + (_audioProcessingModulePtr->echo_cancellation()->enable_delay_logging( + enable) != 0)) { _engineStatistics.SetLastError( VE_APM_ERROR, kTraceError, - "SetEchoMetricsStatus() unable to set echo metrics mode"); + "SetEcMetricsStatus() unable to set EC metrics mode"); return -1; } return 0; @@ -973,9 +975,9 @@ int VoEAudioProcessingImpl::SetEchoMetricsStatus(bool enable) { #endif } -int VoEAudioProcessingImpl::GetEchoMetricsStatus(bool& enabled) { +int VoEAudioProcessingImpl::GetEcMetricsStatus(bool& enabled) { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), - "GetEchoMetricsStatus(enabled=?)"); + "GetEcMetricsStatus(enabled=?)"); ANDROID_NOT_SUPPORTED(); IPHONE_NOT_SUPPORTED(); @@ -985,11 +987,22 @@ int VoEAudioProcessingImpl::GetEchoMetricsStatus(bool& enabled) { return -1; } - enabled = - _audioProcessingModulePtr->echo_cancellation()->are_metrics_enabled(); + bool echo_mode = + _audioProcessingModulePtr->echo_cancellation()->are_metrics_enabled(); + bool delay_mode = + _audioProcessingModulePtr->echo_cancellation()->is_delay_logging_enabled(); + + if (echo_mode != delay_mode) { + _engineStatistics.SetLastError( + VE_APM_ERROR, kTraceError, + "GetEcMetricsStatus() delay logging and echo mode are not the same"); + return -1; + } + + enabled = echo_mode; WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, -1), - "GetEchoMetricsStatus() => enabled=%d", enabled); + "GetEcMetricsStatus() => enabled=%d", enabled); return 0; #else _engineStatistics.SetLastError( @@ -1001,55 +1014,92 @@ int VoEAudioProcessingImpl::GetEchoMetricsStatus(bool& enabled) { int VoEAudioProcessingImpl::GetEchoMetrics(int& ERL, int& ERLE, int& RERL, - int& A_NLP) -{ - WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), - "GetEchoMetrics(ERL=?, ERLE=?, RERL=?, A_NLP=?)"); - ANDROID_NOT_SUPPORTED(); - IPHONE_NOT_SUPPORTED(); + int& A_NLP) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), + "GetEchoMetrics(ERL=?, ERLE=?, RERL=?, A_NLP=?)"); + ANDROID_NOT_SUPPORTED(); + IPHONE_NOT_SUPPORTED(); #ifdef WEBRTC_VOICE_ENGINE_ECHO - if (!_engineStatistics.Initialized()) - { - _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); - return -1; - } + if (!_engineStatistics.Initialized()) { + _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); + return -1; + } + if (!_audioProcessingModulePtr->echo_cancellation()->is_enabled()) { + _engineStatistics.SetLastError( + VE_APM_ERROR, kTraceWarning, + "GetEchoMetrics() AudioProcessingModule AEC is not enabled"); + return -1; + } - bool echoMode = - _audioProcessingModulePtr->echo_cancellation()->is_enabled(); - EchoCancellation::Metrics echoMetrics; + // Get Echo Metrics from Audio Processing Module. + EchoCancellation::Metrics echoMetrics; + if (_audioProcessingModulePtr->echo_cancellation()->GetMetrics(&echoMetrics)) + { + WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), + "GetEchoMetrics(), AudioProcessingModule metrics error"); + return -1; + } - if (echoMode == false) - { - _engineStatistics.SetLastError( - VE_APM_ERROR, kTraceWarning, - "GetEchoMetrics() AudioProcessingModule echo metrics is not" - "enabled"); - return -1; - } - if (_audioProcessingModulePtr->echo_cancellation()->GetMetrics( - &echoMetrics)) - { - WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), - "GetEchoMetrics(), AudioProcessingModule echo metrics" - "error"); - return -1; - } + // Echo quality metrics. + ERL = echoMetrics.echo_return_loss.instant; + ERLE = echoMetrics.echo_return_loss_enhancement.instant; + RERL = echoMetrics.residual_echo_return_loss.instant; + A_NLP = echoMetrics.a_nlp.instant; - ERL = echoMetrics.echo_return_loss.instant; - ERLE = echoMetrics.echo_return_loss_enhancement.instant; - RERL = echoMetrics.residual_echo_return_loss.instant; - A_NLP = echoMetrics.a_nlp.instant; - - WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1), + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1), "GetEchoMetrics() => ERL=%d, ERLE=%d, RERL=%d, A_NLP=%d", ERL, ERLE, RERL, A_NLP); - return 0; + return 0; #else - _engineStatistics.SetLastError( - VE_FUNC_NOT_SUPPORTED, kTraceError, - "SetEcStatus() EC is not supported"); + _engineStatistics.SetLastError( + VE_FUNC_NOT_SUPPORTED, kTraceError, "SetEcStatus() EC is not supported"); + return -1; +#endif +} + +int VoEAudioProcessingImpl::GetEcDelayMetrics(int& delay_median, + int& delay_std) { + WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId, -1), + "GetEcDelayMetrics(median=?, std=?)"); + ANDROID_NOT_SUPPORTED(); + IPHONE_NOT_SUPPORTED(); + +#ifdef WEBRTC_VOICE_ENGINE_ECHO + if (!_engineStatistics.Initialized()) { + _engineStatistics.SetLastError(VE_NOT_INITED, kTraceError); return -1; + } + if (!_audioProcessingModulePtr->echo_cancellation()->is_enabled()) { + _engineStatistics.SetLastError( + VE_APM_ERROR, kTraceWarning, + "GetEcDelayMetrics() AudioProcessingModule AEC is not enabled"); + return -1; + } + + int median = 0; + int std = 0; + // Get delay-logging values from Audio Processing Module. + if (_audioProcessingModulePtr->echo_cancellation()->GetDelayMetrics( + &median, &std)) { + WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), + "GetEcDelayMetrics(), AudioProcessingModule delay-logging " + "error"); + return -1; + } + + // EC delay-logging metrics + delay_median = median; + delay_std = std; + + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1), + "GetEcDelayMetrics() => delay_median=%d, delay_std=%d", + delay_median, delay_std); + return 0; +#else + _engineStatistics.SetLastError( + VE_FUNC_NOT_SUPPORTED, kTraceError, "SetEcStatus() EC is not supported"); + return -1; #endif } diff --git a/src/voice_engine/main/source/voe_audio_processing_impl.h b/src/voice_engine/main/source/voe_audio_processing_impl.h index fb129811f4..277731e324 100644 --- a/src/voice_engine/main/source/voe_audio_processing_impl.h +++ b/src/voice_engine/main/source/voe_audio_processing_impl.h @@ -70,12 +70,14 @@ public: virtual int VoiceActivityIndicator(int channel); - virtual int SetEchoMetricsStatus(bool enable); + virtual int SetEcMetricsStatus(bool enable); - virtual int GetEchoMetricsStatus(bool& enabled); + virtual int GetEcMetricsStatus(bool& enabled); virtual int GetEchoMetrics(int& ERL, int& ERLE, int& RERL, int& A_NLP); + virtual int GetEcDelayMetrics(int& delay_median, int& delay_std); + virtual int StartDebugRecording(const char* fileNameUTF8); virtual int StopDebugRecording(); diff --git a/src/voice_engine/main/source/voe_call_report_impl.cc b/src/voice_engine/main/source/voe_call_report_impl.cc index 8a8d643af7..36a5ff21d7 100644 --- a/src/voice_engine/main/source/voe_call_report_impl.cc +++ b/src/voice_engine/main/source/voe_call_report_impl.cc @@ -89,7 +89,7 @@ int VoECallReportImpl::ResetCallReportStatistics(int channel) _audioProcessingModulePtr->echo_cancellation()->are_metrics_enabled(); WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), - " current AudioProcessingModule echo metric currentState %d", + " current AudioProcessingModule echo metric state %d)", echoMode); // Reset the APM statistics if (_audioProcessingModulePtr->echo_cancellation()->enable_metrics(true) diff --git a/src/voice_engine/main/test/auto_test/voe_extended_test.cc b/src/voice_engine/main/test/auto_test/voe_extended_test.cc index d17ac9fb86..d98e44ef0c 100644 --- a/src/voice_engine/main/test/auto_test/voe_extended_test.cc +++ b/src/voice_engine/main/test/auto_test/voe_extended_test.cc @@ -1699,13 +1699,14 @@ int VoEExtendedTest::TestCallReport() EchoStatistics echo; TEST(GetEchoMetricSummary); ANL(); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); TEST_MUSTPASS(enabled != false); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(true)); + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); TEST_MUSTPASS(report->GetEchoMetricSummary(echo)); // all outputs will be // -100 in loopback (skip further tests) AOK(); ANL(); + // TODO(xians): investigate the cause of test failure before enabling. /* StatVal delays; @@ -8117,26 +8118,26 @@ digitalCompressionGaindBDefault); SLEEP(NSSleep); ////////////////////////////////// - // Echo Metrics + // Ec Metrics #if (!defined(MAC_IPHONE) && !defined(WEBRTC_ANDROID)) - TEST(GetEchoMetricsStatus); + TEST(GetEcMetricsStatus); ANL(); - TEST(SetEchoMetricsStatus); + TEST(SetEcMetricsStatus); ANL(); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); MARK(); TEST_MUSTPASS(enabled != false); MARK(); // should be OFF by default - TEST_MUSTPASS(apm->SetEchoMetricsStatus(true)); + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); MARK(); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); MARK(); TEST_MUSTPASS(enabled != true); MARK(); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(false)); + TEST_MUSTPASS(apm->SetEcMetricsStatus(false)); MARK(); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); MARK(); TEST_MUSTPASS(enabled != false); MARK(); @@ -8148,21 +8149,43 @@ digitalCompressionGaindBDefault); int ERL, ERLE, RERL, A_NLP; TEST_MUSTPASS(-1 != apm->GetEchoMetrics(ERL, ERLE, RERL, A_NLP)); - MARK(); // should fail since not activated + MARK(); // Should fail since not activated. err = base->LastError(); TEST_MUSTPASS(err != VE_APM_ERROR); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(true)); + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); TEST_MUSTPASS(-1 != apm->GetEchoMetrics(ERL, ERLE, RERL, A_NLP)); - MARK(); // should fail since AEC is off + MARK(); // Should fail since AEC is off. err = base->LastError(); TEST_MUSTPASS(err != VE_APM_ERROR); TEST_MUSTPASS(apm->SetEcStatus(true)); TEST_MUSTPASS(apm->GetEchoMetrics(ERL, ERLE, RERL, A_NLP)); - MARK(); // should work now - TEST_LOG( - "\nEcho: ERL=%d, ERLE=%d, RERL=%d, A_NLP=%d [dB]\n", - ERL, ERLE, RERL, A_NLP); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(false)); + MARK(); // Should work now. + TEST_LOG("\nEcho: ERL=%d, ERLE=%d, RERL=%d, A_NLP=%d [dB]\n", + ERL, ERLE, RERL, A_NLP); + TEST_MUSTPASS(apm->SetEcMetricsStatus(false)); + TEST_MUSTPASS(apm->SetEcStatus(false)); + AOK(); + ANL(); + + TEST(GetEcDelayMetrics); + ANL(); + + int delay_median = 0; + int delay_std = 0; + TEST_MUSTPASS(-1 != apm->GetEcDelayMetrics(delay_median, delay_std)); + MARK(); // Should fail since not activated. + err = base->LastError(); + TEST_MUSTPASS(err != VE_APM_ERROR); + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); + TEST_MUSTPASS(-1 != apm->GetEcDelayMetrics(delay_median, delay_std)); + MARK(); // Should fail since AEC is off. + err = base->LastError(); + TEST_MUSTPASS(err != VE_APM_ERROR); + TEST_MUSTPASS(apm->SetEcStatus(true)); + TEST_MUSTPASS(apm->GetEcDelayMetrics(delay_median, delay_std)); + MARK(); // Should work now. + TEST_LOG("\nEC Delay: median=%d, std=%d [ms]\n", delay_median, delay_std); + TEST_MUSTPASS(apm->SetEcMetricsStatus(false)); TEST_MUSTPASS(apm->SetEcStatus(false)); AOK(); ANL(); diff --git a/src/voice_engine/main/test/auto_test/voe_standard_test.cc b/src/voice_engine/main/test/auto_test/voe_standard_test.cc index cbea33c2a6..e0cf2b6d47 100644 --- a/src/voice_engine/main/test/auto_test/voe_standard_test.cc +++ b/src/voice_engine/main/test/auto_test/voe_standard_test.cc @@ -2792,27 +2792,30 @@ int VoETestManager::DoStandardTest() #if (!defined(MAC_IPHONE) && !defined(WEBRTC_ANDROID) && defined(WEBRTC_VOICE_ENGINE_NR)) #ifdef WEBRTC_VOICE_ENGINE_ECHO bool enabled = false; - TEST_LOG("Echo Metric calls\n"); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); // check default + TEST_LOG("EC Metrics calls\n"); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); // check default TEST_MUSTPASS(enabled != false); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(true)); // enable echo metrics + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); // enable EC metrics // must enable AEC to get valid echo metrics TEST_MUSTPASS(apm->SetEcStatus(true, kEcAec)); - TEST_MUSTPASS(apm->GetEchoMetricsStatus(enabled)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(enabled)); TEST_MUSTPASS(enabled != true); TEST_LOG("Speak into microphone and check metrics for 10 seconds...\n"); - int ERLE, ERL, RERL, A_NLP; - for (int t = 0; t < 5; t++) - { - SLEEP(2000); - TEST_MUSTPASS(apm->GetEchoMetrics(ERL, ERLE, RERL, A_NLP)); - TEST_LOG(" Echo : ERL=%5d, ERLE=%5d, RERL=%5d, A_NLP=%5d [dB]\n", - ERL, ERLE, RERL, A_NLP); + int ERL, ERLE, RERL, A_NLP; + int delay_median = 0; + int delay_std = 0; + for (int t = 0; t < 5; t++) { + SLEEP(2000); + TEST_MUSTPASS(apm->GetEchoMetrics(ERL, ERLE, RERL, A_NLP)); + TEST_MUSTPASS(apm->GetEcDelayMetrics(delay_median, delay_std)); + TEST_LOG(" Echo : ERL=%5d, ERLE=%5d, RERL=%5d, A_NLP=%5d [dB], " + " delay median=%3d, delay std=%3d [ms]\n", + ERL, ERLE, RERL, A_NLP, delay_median, delay_std); } - TEST_MUSTPASS(apm->SetEchoMetricsStatus(false)); // disable echo metrics + TEST_MUSTPASS(apm->SetEcMetricsStatus(false)); // disable echo metrics #else - TEST_LOG("Skipping echo metrics tests -" + TEST_LOG("Skipping Echo Control metrics tests -" " WEBRTC_VOICE_ENGINE_ECHO not defined \n"); #endif // #ifdef WEBRTC_VOICE_ENGINE_ECHO #else @@ -3255,9 +3258,9 @@ int VoETestManager::DoStandardTest() TEST_MUSTPASS(report->ResetCallReportStatistics(-1)); bool onOff; - TEST_MUSTPASS(apm->GetEchoMetricsStatus(onOff)); + TEST_MUSTPASS(apm->GetEcMetricsStatus(onOff)); TEST_MUSTPASS(onOff != false); - TEST_MUSTPASS(apm->SetEchoMetricsStatus(true)); + TEST_MUSTPASS(apm->SetEcMetricsStatus(true)); SLEEP(3000); EchoStatistics echo; TEST(GetEchoMetricSummary);ANL();