| /* |
| * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "unit_test.h" |
| |
| #include "event_wrapper.h" |
| #include "module_common_types.h" |
| #include "thread_wrapper.h" |
| #include "trace.h" |
| #include "signal_processing_library.h" |
| |
| #include "audio_processing.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| struct ThreadData { |
| ThreadData(int thread_num_, AudioProcessing* ap_) |
| : thread_num(thread_num_), |
| error(false), |
| ap(ap_) {} |
| int thread_num; |
| bool error; |
| AudioProcessing* ap; |
| }; |
| |
| // Don't use GTest here; non-thread-safe on Windows (as of 1.5.0). |
| bool DeadlockProc(void* thread_object) { |
| ThreadData* thread_data = static_cast<ThreadData*>(thread_object); |
| AudioProcessing* ap = thread_data->ap; |
| int err = ap->kNoError; |
| |
| AudioFrame primary_frame; |
| AudioFrame reverse_frame; |
| primary_frame._payloadDataLengthInSamples = 320; |
| primary_frame._audioChannel = 2; |
| primary_frame._frequencyInHz = 32000; |
| reverse_frame._payloadDataLengthInSamples = 320; |
| reverse_frame._audioChannel = 2; |
| reverse_frame._frequencyInHz = 32000; |
| |
| ap->echo_cancellation()->Enable(true); |
| ap->gain_control()->Enable(true); |
| ap->high_pass_filter()->Enable(true); |
| ap->level_estimator()->Enable(true); |
| ap->noise_suppression()->Enable(true); |
| ap->voice_detection()->Enable(true); |
| |
| if (thread_data->thread_num % 2 == 0) { |
| err = ap->AnalyzeReverseStream(&reverse_frame); |
| if (err != ap->kNoError) { |
| printf("Error in AnalyzeReverseStream(): %d\n", err); |
| thread_data->error = true; |
| return false; |
| } |
| } |
| |
| if (thread_data->thread_num % 2 == 1) { |
| ap->set_stream_delay_ms(0); |
| ap->echo_cancellation()->set_stream_drift_samples(0); |
| ap->gain_control()->set_stream_analog_level(0); |
| err = ap->ProcessStream(&primary_frame); |
| if (err == ap->kStreamParameterNotSetError) { |
| printf("Expected kStreamParameterNotSetError in ProcessStream(): %d\n", |
| err); |
| } else if (err != ap->kNoError) { |
| printf("Error in ProcessStream(): %d\n", err); |
| thread_data->error = true; |
| return false; |
| } |
| ap->gain_control()->stream_analog_level(); |
| } |
| |
| EventWrapper* event = EventWrapper::Create(); |
| event->Wait(1); |
| delete event; |
| event = NULL; |
| |
| return true; |
| } |
| } // namespace |
| |
| class ApmEnvironment : public ::testing::Environment { |
| public: |
| virtual void SetUp() { |
| Trace::CreateTrace(); |
| ASSERT_EQ(0, Trace::SetTraceFile("ApmTrace.txt")); |
| } |
| |
| virtual void TearDown() { |
| Trace::ReturnTrace(); |
| } |
| }; |
| |
| ApmTest::ApmTest() |
| : apm_(NULL), |
| far_file_(NULL), |
| near_file_(NULL), |
| stat_file_(NULL), |
| read_stat_(true) { |
| } |
| |
| void ApmTest::SetUp() { |
| apm_ = AudioProcessing::Create(0); |
| ASSERT_TRUE(apm_ != NULL); |
| |
| far_file_ = fopen("aecFar.pcm", "rb"); |
| ASSERT_TRUE(far_file_ != NULL) << "Cannot read source file aecFar.pcm\n"; |
| near_file_ = fopen("aecNear.pcm", "rb"); |
| ASSERT_TRUE(near_file_ != NULL) << "Cannot read source file aecNear.pcm\n"; |
| |
| if (read_stat_) { |
| stat_file_ = fopen("statData.dat", "rb"); |
| ASSERT_TRUE(stat_file_ != NULL) << |
| "Cannot write to source file statData.dat\n"; |
| } |
| } |
| |
| void ApmTest::TearDown() { |
| if (far_file_ != NULL) { |
| ASSERT_EQ(0, fclose(far_file_)); |
| } |
| far_file_ = NULL; |
| if (near_file_ != NULL) { |
| ASSERT_EQ(0, fclose(near_file_)); |
| } |
| near_file_ = NULL; |
| if (stat_file_ != NULL) { |
| ASSERT_EQ(0, fclose(stat_file_)); |
| } |
| stat_file_ = NULL; |
| |
| if (apm_ != NULL) { |
| AudioProcessing::Destroy(apm_); |
| } |
| apm_ = NULL; |
| } |
| |
| TEST_F(ApmTest, Deadlock) { |
| const int num_threads = 16; |
| std::vector<ThreadWrapper*> threads(num_threads); |
| std::vector<ThreadData*> thread_data(num_threads); |
| |
| ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(32000)); |
| ASSERT_EQ(apm_->kNoError, apm_->set_num_channels(2, 2)); |
| ASSERT_EQ(apm_->kNoError, apm_->set_num_reverse_channels(2)); |
| |
| for (int i = 0; i < num_threads; i++) { |
| thread_data[i] = new ThreadData(i, apm_); |
| threads[i] = ThreadWrapper::CreateThread(DeadlockProc, |
| thread_data[i], |
| kNormalPriority, |
| 0); |
| ASSERT_TRUE(threads[i] != NULL); |
| unsigned int thread_id = 0; |
| threads[i]->Start(thread_id); |
| } |
| |
| EventWrapper* event = EventWrapper::Create(); |
| ASSERT_EQ(kEventTimeout, event->Wait(5000)); |
| delete event; |
| event = NULL; |
| |
| for (int i = 0; i < num_threads; i++) { |
| // This will return false if the thread has deadlocked. |
| ASSERT_TRUE(threads[i]->Stop()); |
| ASSERT_FALSE(thread_data[i]->error); |
| delete threads[i]; |
| threads[i] = NULL; |
| delete thread_data[i]; |
| thread_data[i] = NULL; |
| } |
| } |
| |
| TEST_F(ApmTest, Process) { |
| if (!read_stat_) { |
| stat_file_ = fopen("statData.dat", "wb"); |
| ASSERT_TRUE(stat_file_ != NULL) |
| << "Cannot write to source file statData.dat\n"; |
| } |
| // Testing number of invalid channels |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_channels(0, 1)); |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_channels(1, 0)); |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_channels(3, 1)); |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_channels(1, 3)); |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_reverse_channels(0)); |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_reverse_channels(3)); |
| // Testing number of valid channels |
| for (int ii = 1; ii < 3; ++ii) { |
| for (int jj = 1; jj < 3; ++jj) { |
| if (jj > ii ) { |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_num_channels(ii, jj)); |
| } else { |
| ASSERT_EQ(apm_->kNoError, apm_->set_num_channels(ii, jj)); |
| ASSERT_EQ(jj, apm_->num_output_channels()); |
| } |
| } |
| ASSERT_EQ(ii, apm_->num_input_channels()); |
| ASSERT_EQ(apm_->kNoError, apm_->set_num_reverse_channels(ii)); |
| ASSERT_EQ(ii, apm_->num_reverse_channels()); |
| } |
| |
| // Testing invalid sample rates |
| ASSERT_EQ(apm_->kBadParameterError, apm_->set_sample_rate_hz(10000)); |
| // Testing valid sample rates |
| int fs[] = {8000, 16000, 32000}; |
| for (int ii = 0; ii < sizeof(fs)/sizeof(*fs); ++ii) { |
| ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(fs[ii])); |
| ASSERT_EQ(fs[ii], apm_->sample_rate_hz()); |
| } |
| |
| AudioFrame render_audio; |
| AudioFrame capture_audio; |
| |
| render_audio._payloadDataLengthInSamples = 320; |
| render_audio._audioChannel = 2; |
| render_audio._frequencyInHz = 32000; |
| capture_audio._payloadDataLengthInSamples = 320; |
| capture_audio._audioChannel = 2; |
| capture_audio._frequencyInHz = 32000; |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_drift_compensation(true)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_metrics(true)); |
| EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_analog_level_limits(0, 255)); |
| EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->high_pass_filter()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kUnsupportedComponentError, |
| apm_->level_estimator()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->noise_suppression()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->Enable(true)); |
| |
| LevelEstimator::Metrics far_metrics; |
| LevelEstimator::Metrics near_metrics; |
| EchoCancellation::Metrics echo_metrics; |
| for (int i = 0; i < 100; i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->AnalyzeReverseStream(&render_audio)); |
| |
| EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_stream_drift_samples(0)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_stream_analog_level(127)); |
| |
| EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(&capture_audio)); |
| |
| apm_->echo_cancellation()->stream_has_echo(); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->GetMetrics(&echo_metrics)); |
| |
| apm_->gain_control()->stream_analog_level(); |
| apm_->gain_control()->stream_is_saturated(); |
| |
| EXPECT_EQ(apm_->kUnsupportedComponentError, |
| apm_->level_estimator()->GetMetrics(&near_metrics, |
| &far_metrics)); |
| |
| apm_->voice_detection()->stream_has_voice(); |
| } |
| // Wrong order tests |
| // No stream parameter |
| EXPECT_EQ(apm_->kNoError, |
| apm_->AnalyzeReverseStream(&render_audio)); |
| EXPECT_EQ(apm_->kStreamParameterNotSetError, |
| apm_->ProcessStream(&capture_audio)); |
| |
| // Missing agc level |
| EXPECT_EQ(apm_->kNoError, apm_->Initialize()); |
| EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_stream_drift_samples(0)); |
| EXPECT_EQ(apm_->kStreamParameterNotSetError, |
| apm_->ProcessStream(&capture_audio)); |
| |
| // Missing delay |
| EXPECT_EQ(apm_->kNoError, apm_->Initialize()); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_stream_drift_samples(0)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_stream_analog_level(127)); |
| EXPECT_EQ(apm_->kStreamParameterNotSetError, |
| apm_->ProcessStream(&capture_audio)); |
| |
| // Missing drift |
| EXPECT_EQ(apm_->kNoError, apm_->Initialize()); |
| EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_stream_analog_level(127)); |
| EXPECT_EQ(apm_->kStreamParameterNotSetError, |
| apm_->ProcessStream(&capture_audio)); |
| // All there |
| EXPECT_EQ(apm_->kNoError, apm_->Initialize()); |
| EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_stream_drift_samples(0)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_stream_analog_level(127)); |
| EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(&capture_audio)); |
| |
| // Test with real audio |
| // Loop through all possible combinations |
| // (# reverse channels, # channels, sample rates) |
| int revCh[] = {1, 2}; |
| int nRevCh = 2; |
| int ch[] = {1, 2}; |
| int nCh = 2; |
| int nFs = (int)(sizeof(fs)/sizeof(*fs)); |
| if (read_stat_) { |
| fread(&nRevCh, sizeof(int), 1, stat_file_); |
| fread(revCh, sizeof(int), nRevCh, stat_file_); |
| fread(&nCh, sizeof(int), 1, stat_file_); |
| fread(ch, sizeof(int), nCh, stat_file_); |
| fread(&nFs, sizeof(int), 1, stat_file_); |
| fread(fs, 1, sizeof(fs), stat_file_); |
| } else { |
| fwrite(&nRevCh, sizeof(int), 1, stat_file_); |
| fwrite(revCh, sizeof(int), nRevCh, stat_file_); |
| fwrite(&nCh, sizeof(int), 1, stat_file_); |
| fwrite(ch, sizeof(int), nCh, stat_file_); |
| fwrite(&nFs, sizeof(int), 1, stat_file_); |
| fwrite(fs, 1, sizeof(fs), stat_file_); |
| } |
| int testCnt = 0; |
| for (int iRevCh = 0; iRevCh < nRevCh; ++iRevCh) { |
| for (int iCh = 0; iCh < nCh; ++iCh) { |
| for (int iFs = 0; iFs < nFs; ++iFs) { |
| render_audio._payloadDataLengthInSamples = fs[iFs]/100; |
| render_audio._audioChannel = revCh[iRevCh]; |
| render_audio._frequencyInHz = fs[iFs]; |
| capture_audio._payloadDataLengthInSamples = fs[iFs]/100; |
| capture_audio._audioChannel = ch[iCh]; |
| capture_audio._frequencyInHz = fs[iFs]; |
| |
| EXPECT_EQ(apm_->kNoError, apm_->Initialize()); |
| ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(fs[iFs])); |
| ASSERT_EQ(apm_->kNoError, |
| apm_->set_num_channels(capture_audio._audioChannel, |
| capture_audio._audioChannel)); |
| ASSERT_EQ(apm_->kNoError, |
| apm_->set_num_reverse_channels(render_audio._audioChannel)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_drift_compensation(false)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_metrics(true)); |
| EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_analog_level_limits(0, 255)); |
| EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->high_pass_filter()->Enable(true)); |
| |
| //EXPECT_EQ(apm_->kNoError, |
| // apm_->level_estimator()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->noise_suppression()->Enable(true)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->Enable(true)); |
| bool runningFiles = true; |
| int i = 0; |
| int echo_count = 0; |
| int vad_count = 0; |
| int sat_count = 0; |
| int analog_level = 127; |
| int sat_gain = 2; |
| size_t read_count = 0; |
| WebRtc_Word16 tmpData[640]; |
| int tmp_int; |
| |
| int echo_count_ref_ = 0; |
| int vad_count_ref_ = 0; |
| int sat_count_ref_ = 0; |
| //LevelEstimator::Metrics far_metrics_ref_; |
| //LevelEstimator::Metrics near_metrics_ref_; |
| EchoCancellation::Metrics echo_metrics_ref_; |
| |
| while (runningFiles) { |
| i++; |
| // Read far end frame |
| read_count = fread(&tmpData[0], |
| sizeof(WebRtc_Word16), |
| render_audio._payloadDataLengthInSamples * 2, |
| far_file_); |
| if (read_count != render_audio._payloadDataLengthInSamples * 2) { |
| break; // This is expected. |
| } |
| if (render_audio._audioChannel == 1) { |
| for (int jj = 0; jj < render_audio._payloadDataLengthInSamples; |
| ++jj) { |
| tmp_int = (static_cast<int>(tmpData[jj * 2]) + |
| static_cast<int>(tmpData[jj * 2 + 1])) >> 1; |
| render_audio._payloadData[jj] = |
| static_cast<WebRtc_Word16>(tmp_int); |
| } |
| } else { |
| memcpy(render_audio._payloadData, |
| &tmpData[0], |
| sizeof(WebRtc_Word16) * read_count); |
| } |
| EXPECT_EQ(apm_->kNoError, |
| apm_->AnalyzeReverseStream(&render_audio)); |
| |
| EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_stream_analog_level(analog_level)); |
| |
| // Read near end frame |
| read_count = fread(&tmpData[0], |
| sizeof(WebRtc_Word16), |
| capture_audio._payloadDataLengthInSamples * 2, |
| near_file_); |
| if (read_count != capture_audio._payloadDataLengthInSamples * 2) { |
| break; // This is expected. |
| } |
| if (capture_audio._audioChannel == 1) { |
| for (int jj = 0; jj < capture_audio._payloadDataLengthInSamples; ++jj) { |
| tmp_int = (static_cast<int>(tmpData[jj * 2]) + |
| static_cast<int>(tmpData[jj * 2 + 1])) >> 1; |
| capture_audio._payloadData[jj] = |
| static_cast<WebRtc_Word16>(tmp_int); |
| } |
| } else { |
| memcpy(capture_audio._payloadData, |
| &tmpData[0], |
| sizeof(WebRtc_Word16) * read_count); |
| } |
| WebRtc_Word32 tmpF = 0; |
| for (int jj = 0; jj < read_count; ++jj) { |
| tmpF = (WebRtc_Word32)capture_audio._payloadData[jj] * sat_gain; |
| if (tmpF > WEBRTC_SPL_WORD16_MAX) { |
| capture_audio._payloadData[jj] = WEBRTC_SPL_WORD16_MAX; |
| } else if (tmpF < WEBRTC_SPL_WORD16_MIN) { |
| capture_audio._payloadData[jj] = WEBRTC_SPL_WORD16_MIN; |
| } else { |
| capture_audio._payloadData[jj] = (WebRtc_Word16)tmpF; |
| } |
| } |
| EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(&capture_audio)); |
| |
| if (apm_->echo_cancellation()->stream_has_echo()) { |
| echo_count++; |
| } |
| |
| analog_level = apm_->gain_control()->stream_analog_level(); |
| if (apm_->gain_control()->stream_is_saturated()) { |
| sat_count++; |
| sat_gain = 1; |
| } |
| if (apm_->voice_detection()->stream_has_voice()) { |
| vad_count++; |
| } |
| } |
| //<-- Statistics --> |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->GetMetrics(&echo_metrics)); |
| //EXPECT_EQ(apm_->kNoError, |
| // apm_->level_estimator()->GetMetrics(&near_metrics, |
| |
| // TODO(ajm): Perhaps we don't have to check every value? The average |
| // could be sufficient. Or, how about hashing the output? |
| if (read_stat_) { |
| // Read from statData |
| fread(&echo_count_ref_, 1, sizeof(echo_count), stat_file_); |
| EXPECT_EQ(echo_count_ref_, echo_count); |
| fread(&echo_metrics_ref_, |
| 1, |
| sizeof(EchoCancellation::Metrics), |
| stat_file_); |
| EXPECT_EQ(echo_metrics_ref_.residual_echo_return_loss.instant, |
| echo_metrics.residual_echo_return_loss.instant); |
| EXPECT_EQ(echo_metrics_ref_.residual_echo_return_loss.average, |
| echo_metrics.residual_echo_return_loss.average); |
| EXPECT_EQ(echo_metrics_ref_.residual_echo_return_loss.maximum, |
| echo_metrics.residual_echo_return_loss.maximum); |
| EXPECT_EQ(echo_metrics_ref_.residual_echo_return_loss.minimum, |
| echo_metrics.residual_echo_return_loss.minimum); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss.instant, |
| echo_metrics.echo_return_loss.instant); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss.average, |
| echo_metrics.echo_return_loss.average); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss.maximum, |
| echo_metrics.echo_return_loss.maximum); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss.minimum, |
| echo_metrics.echo_return_loss.minimum); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss_enhancement.instant, |
| echo_metrics.echo_return_loss_enhancement.instant); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss_enhancement.average, |
| echo_metrics.echo_return_loss_enhancement.average); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss_enhancement.maximum, |
| echo_metrics.echo_return_loss_enhancement.maximum); |
| EXPECT_EQ(echo_metrics_ref_.echo_return_loss_enhancement.minimum, |
| echo_metrics.echo_return_loss_enhancement.minimum); |
| EXPECT_EQ(echo_metrics_ref_.a_nlp.instant, |
| echo_metrics.a_nlp.instant); |
| EXPECT_EQ(echo_metrics_ref_.a_nlp.average, |
| echo_metrics.a_nlp.average); |
| EXPECT_EQ(echo_metrics_ref_.a_nlp.maximum, |
| echo_metrics.a_nlp.maximum); |
| EXPECT_EQ(echo_metrics_ref_.a_nlp.minimum, |
| echo_metrics.a_nlp.minimum); |
| |
| fread(&vad_count_ref_, 1, sizeof(vad_count), stat_file_); |
| EXPECT_EQ(vad_count_ref_, vad_count); |
| fread(&sat_count_ref_, 1, sizeof(sat_count), stat_file_); |
| EXPECT_EQ(sat_count_ref_, sat_count); |
| |
| /*fread(&far_metrics_ref_, |
| 1, |
| sizeof(LevelEstimator::Metrics), |
| stat_file_); |
| EXPECT_EQ(far_metrics_ref_.signal.instant, |
| far_metrics.signal.instant); |
| EXPECT_EQ(far_metrics_ref_.signal.average, |
| far_metrics.signal.average); |
| EXPECT_EQ(far_metrics_ref_.signal.maximum, |
| far_metrics.signal.maximum); |
| EXPECT_EQ(far_metrics_ref_.signal.minimum, |
| far_metrics.signal.minimum); |
| |
| EXPECT_EQ(far_metrics_ref_.speech.instant, |
| far_metrics.speech.instant); |
| EXPECT_EQ(far_metrics_ref_.speech.average, |
| far_metrics.speech.average); |
| EXPECT_EQ(far_metrics_ref_.speech.maximum, |
| far_metrics.speech.maximum); |
| EXPECT_EQ(far_metrics_ref_.speech.minimum, |
| far_metrics.speech.minimum); |
| |
| EXPECT_EQ(far_metrics_ref_.noise.instant, |
| far_metrics.noise.instant); |
| EXPECT_EQ(far_metrics_ref_.noise.average, |
| far_metrics.noise.average); |
| EXPECT_EQ(far_metrics_ref_.noise.maximum, |
| far_metrics.noise.maximum); |
| EXPECT_EQ(far_metrics_ref_.noise.minimum, |
| far_metrics.noise.minimum); |
| |
| fread(&near_metrics_ref_, |
| 1, |
| sizeof(LevelEstimator::Metrics), |
| stat_file_); |
| EXPECT_EQ(near_metrics_ref_.signal.instant, |
| near_metrics.signal.instant); |
| EXPECT_EQ(near_metrics_ref_.signal.average, |
| near_metrics.signal.average); |
| EXPECT_EQ(near_metrics_ref_.signal.maximum, |
| near_metrics.signal.maximum); |
| EXPECT_EQ(near_metrics_ref_.signal.minimum, |
| near_metrics.signal.minimum); |
| |
| EXPECT_EQ(near_metrics_ref_.speech.instant, |
| near_metrics.speech.instant); |
| EXPECT_EQ(near_metrics_ref_.speech.average, |
| near_metrics.speech.average); |
| EXPECT_EQ(near_metrics_ref_.speech.maximum, |
| near_metrics.speech.maximum); |
| EXPECT_EQ(near_metrics_ref_.speech.minimum, |
| near_metrics.speech.minimum); |
| |
| EXPECT_EQ(near_metrics_ref_.noise.instant, |
| near_metrics.noise.instant); |
| EXPECT_EQ(near_metrics_ref_.noise.average, |
| near_metrics.noise.average); |
| EXPECT_EQ(near_metrics_ref_.noise.maximum, |
| near_metrics.noise.maximum); |
| EXPECT_EQ(near_metrics_ref_.noise.minimum, |
| near_metrics.noise.minimum);*/ |
| } else { |
| // Write to statData |
| fwrite(&echo_count, 1, sizeof(echo_count), stat_file_); |
| fwrite(&echo_metrics, |
| 1, |
| sizeof(EchoCancellation::Metrics), |
| stat_file_); |
| fwrite(&vad_count, 1, sizeof(vad_count), stat_file_); |
| fwrite(&sat_count, 1, sizeof(sat_count), stat_file_); |
| //fwrite(&far_metrics, 1, sizeof(LevelEstimator::Metrics), stat_file_); |
| //fwrite(&near_metrics, 1, sizeof(LevelEstimator::Metrics), stat_file_); |
| } |
| |
| rewind(far_file_); |
| rewind(near_file_); |
| testCnt++; |
| printf("Loop %d of %d\n", testCnt, nRevCh * nCh * nFs); |
| } |
| } |
| } |
| if (!read_stat_) { |
| if (stat_file_ != NULL) { |
| ASSERT_EQ(0, fclose(stat_file_)); |
| } |
| stat_file_ = NULL; |
| } |
| } |
| |
| TEST_F(ApmTest, EchoCancellation) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_drift_compensation(true)); |
| EXPECT_TRUE(apm_->echo_cancellation()->is_drift_compensation_enabled()); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_drift_compensation(false)); |
| EXPECT_FALSE(apm_->echo_cancellation()->is_drift_compensation_enabled()); |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->echo_cancellation()->set_device_sample_rate_hz(4000)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->echo_cancellation()->set_device_sample_rate_hz(100000)); |
| |
| int rate[] = {16000, 44100, 48000}; |
| for (size_t i = 0; i < sizeof(rate)/sizeof(*rate); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_device_sample_rate_hz(rate[i])); |
| EXPECT_EQ(rate[i], |
| apm_->echo_cancellation()->device_sample_rate_hz()); |
| } |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->echo_cancellation()->set_suppression_level( |
| static_cast<EchoCancellation::SuppressionLevel>(-1))); |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->echo_cancellation()->set_suppression_level( |
| static_cast<EchoCancellation::SuppressionLevel>(4))); |
| |
| EchoCancellation::SuppressionLevel level[] = { |
| EchoCancellation::kLowSuppression, |
| EchoCancellation::kModerateSuppression, |
| EchoCancellation::kHighSuppression, |
| }; |
| for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->set_suppression_level(level[i])); |
| EXPECT_EQ(level[i], |
| apm_->echo_cancellation()->suppression_level()); |
| } |
| |
| EchoCancellation::Metrics metrics; |
| EXPECT_EQ(apm_->kNotEnabledError, |
| apm_->echo_cancellation()->GetMetrics(&metrics)); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_metrics(true)); |
| EXPECT_TRUE(apm_->echo_cancellation()->are_metrics_enabled()); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_cancellation()->enable_metrics(false)); |
| EXPECT_FALSE(apm_->echo_cancellation()->are_metrics_enabled()); |
| |
| EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true)); |
| EXPECT_TRUE(apm_->echo_cancellation()->is_enabled()); |
| EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false)); |
| EXPECT_FALSE(apm_->echo_cancellation()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, EchoControlMobile) { |
| // Turn AECM on (and AEC off) |
| EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true)); |
| EXPECT_TRUE(apm_->echo_control_mobile()->is_enabled()); |
| // Toggle routing modes |
| EchoControlMobile::RoutingMode mode[] = { |
| EchoControlMobile::kQuietEarpieceOrHeadset, |
| EchoControlMobile::kEarpiece, |
| EchoControlMobile::kLoudEarpiece, |
| EchoControlMobile::kSpeakerphone, |
| EchoControlMobile::kLoudSpeakerphone, |
| }; |
| for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_control_mobile()->set_routing_mode(mode[i])); |
| EXPECT_EQ(mode[i], |
| apm_->echo_control_mobile()->routing_mode()); |
| } |
| // Turn comfort noise off/on |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_control_mobile()->enable_comfort_noise(false)); |
| EXPECT_FALSE(apm_->echo_control_mobile()->is_comfort_noise_enabled()); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->echo_control_mobile()->enable_comfort_noise(true)); |
| EXPECT_TRUE(apm_->echo_control_mobile()->is_comfort_noise_enabled()); |
| // Turn AECM off |
| EXPECT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false)); |
| EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, GainControl) { |
| // Testing gain modes |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_mode(static_cast<GainControl::Mode>(-1))); |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_mode(static_cast<GainControl::Mode>(3))); |
| |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_mode( |
| apm_->gain_control()->mode())); |
| |
| GainControl::Mode mode[] = { |
| GainControl::kAdaptiveAnalog, |
| GainControl::kAdaptiveDigital, |
| GainControl::kFixedDigital |
| }; |
| for (size_t i = 0; i < sizeof(mode)/sizeof(*mode); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_mode(mode[i])); |
| EXPECT_EQ(mode[i], apm_->gain_control()->mode()); |
| } |
| // Testing invalid target levels |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_target_level_dbfs(-3)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_target_level_dbfs(-40)); |
| // Testing valid target levels |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_target_level_dbfs( |
| apm_->gain_control()->target_level_dbfs())); |
| |
| int level_dbfs[] = {0, 6, 31}; |
| for (size_t i = 0; i < sizeof(level_dbfs)/sizeof(*level_dbfs); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_target_level_dbfs(level_dbfs[i])); |
| EXPECT_EQ(level_dbfs[i], apm_->gain_control()->target_level_dbfs()); |
| } |
| |
| // Testing invalid compression gains |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_compression_gain_db(-1)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_compression_gain_db(100)); |
| |
| // Testing valid compression gains |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_compression_gain_db( |
| apm_->gain_control()->compression_gain_db())); |
| |
| int gain_db[] = {0, 10, 90}; |
| for (size_t i = 0; i < sizeof(gain_db)/sizeof(*gain_db); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_compression_gain_db(gain_db[i])); |
| EXPECT_EQ(gain_db[i], apm_->gain_control()->compression_gain_db()); |
| } |
| |
| // Testing limiter off/on |
| EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(false)); |
| EXPECT_FALSE(apm_->gain_control()->is_limiter_enabled()); |
| EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(true)); |
| EXPECT_TRUE(apm_->gain_control()->is_limiter_enabled()); |
| |
| // Testing invalid level limits |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_analog_level_limits(-1, 512)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_analog_level_limits(100000, 512)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_analog_level_limits(512, -1)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_analog_level_limits(512, 100000)); |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->gain_control()->set_analog_level_limits(512, 255)); |
| |
| // Testing valid level limits |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_analog_level_limits( |
| apm_->gain_control()->analog_level_minimum(), |
| apm_->gain_control()->analog_level_maximum())); |
| |
| int min_level[] = {0, 255, 1024}; |
| for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_analog_level_limits(min_level[i], 1024)); |
| EXPECT_EQ(min_level[i], apm_->gain_control()->analog_level_minimum()); |
| } |
| |
| int max_level[] = {0, 1024, 65535}; |
| for (size_t i = 0; i < sizeof(min_level)/sizeof(*min_level); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->gain_control()->set_analog_level_limits(0, max_level[i])); |
| EXPECT_EQ(max_level[i], apm_->gain_control()->analog_level_maximum()); |
| } |
| |
| // TODO(ajm): stream_is_saturated() and stream_analog_level() |
| |
| // Turn AGC off |
| EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false)); |
| EXPECT_FALSE(apm_->gain_control()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, NoiseSuppression) { |
| // Tesing invalid suppression levels |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->noise_suppression()->set_level( |
| static_cast<NoiseSuppression::Level>(-1))); |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->noise_suppression()->set_level( |
| static_cast<NoiseSuppression::Level>(5))); |
| |
| // Tesing valid suppression levels |
| NoiseSuppression::Level level[] = { |
| NoiseSuppression::kLow, |
| NoiseSuppression::kModerate, |
| NoiseSuppression::kHigh, |
| NoiseSuppression::kVeryHigh |
| }; |
| for (size_t i = 0; i < sizeof(level)/sizeof(*level); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->noise_suppression()->set_level(level[i])); |
| EXPECT_EQ(level[i], apm_->noise_suppression()->level()); |
| } |
| |
| // Turing NS on/off |
| EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); |
| EXPECT_TRUE(apm_->noise_suppression()->is_enabled()); |
| EXPECT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(false)); |
| EXPECT_FALSE(apm_->noise_suppression()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, HighPassFilter) { |
| // Turing HP filter on/off |
| EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(true)); |
| EXPECT_TRUE(apm_->high_pass_filter()->is_enabled()); |
| EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(false)); |
| EXPECT_FALSE(apm_->high_pass_filter()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, LevelEstimator) { |
| // Turing Level estimator on/off |
| EXPECT_EQ(apm_->kUnsupportedComponentError, |
| apm_->level_estimator()->Enable(true)); |
| EXPECT_FALSE(apm_->level_estimator()->is_enabled()); |
| EXPECT_EQ(apm_->kUnsupportedComponentError, |
| apm_->level_estimator()->Enable(false)); |
| EXPECT_FALSE(apm_->level_estimator()->is_enabled()); |
| } |
| |
| TEST_F(ApmTest, VoiceDetection) { |
| // Test external VAD |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->set_stream_has_voice(true)); |
| EXPECT_TRUE(apm_->voice_detection()->stream_has_voice()); |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->set_stream_has_voice(false)); |
| EXPECT_FALSE(apm_->voice_detection()->stream_has_voice()); |
| |
| // Tesing invalid likelihoods |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->voice_detection()->set_likelihood( |
| static_cast<VoiceDetection::Likelihood>(-1))); |
| |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->voice_detection()->set_likelihood( |
| static_cast<VoiceDetection::Likelihood>(5))); |
| |
| // Tesing valid likelihoods |
| VoiceDetection::Likelihood likelihood[] = { |
| VoiceDetection::kVeryLowLikelihood, |
| VoiceDetection::kLowLikelihood, |
| VoiceDetection::kModerateLikelihood, |
| VoiceDetection::kHighLikelihood |
| }; |
| for (size_t i = 0; i < sizeof(likelihood)/sizeof(*likelihood); i++) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->set_likelihood(likelihood[i])); |
| EXPECT_EQ(likelihood[i], apm_->voice_detection()->likelihood()); |
| } |
| |
| /* TODO(bjornv): Enable once VAD supports other frame lengths than 10 ms |
| // Tesing invalid frame sizes |
| EXPECT_EQ(apm_->kBadParameterError, |
| apm_->voice_detection()->set_frame_size_ms(12)); |
| |
| // Tesing valid frame sizes |
| for (int i = 10; i <= 30; i += 10) { |
| EXPECT_EQ(apm_->kNoError, |
| apm_->voice_detection()->set_frame_size_ms(i)); |
| EXPECT_EQ(i, apm_->voice_detection()->frame_size_ms()); |
| } |
| */ |
| |
| // Turing VAD on/off |
| EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); |
| EXPECT_TRUE(apm_->voice_detection()->is_enabled()); |
| EXPECT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(false)); |
| EXPECT_FALSE(apm_->voice_detection()->is_enabled()); |
| |
| // TODO(bjornv): Add tests for streamed voice; stream_has_voice() |
| } |
| |
| // Below are some ideas for tests from VPM. |
| |
| /*TEST_F(VideoProcessingModuleTest, GetVersionTest) |
| { |
| } |
| |
| TEST_F(VideoProcessingModuleTest, HandleNullBuffer) |
| { |
| } |
| |
| TEST_F(VideoProcessingModuleTest, HandleBadSize) |
| { |
| } |
| |
| TEST_F(VideoProcessingModuleTest, IdenticalResultsAfterReset) |
| { |
| } |
| */ |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| ApmEnvironment* env = new ApmEnvironment; |
| ::testing::AddGlobalTestEnvironment(env); |
| |
| return RUN_ALL_TESTS(); |
| } |
| } |