Adding more output data checks to APM unittest. Blowing out the protobuf definition (changing the tags) since we're still in the formative stages. Later, this would be very bad. Leaving a Frame message in case we want frame-by-frame data, but we prefer to keep the output storage small in general so avoiding it thus far.
Review URL: http://webrtc-codereview.appspot.com/68004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@203 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/audio_processing/main/test/unit_test/unit_test.cc b/src/modules/audio_processing/main/test/unit_test/unit_test.cc
index 275ac3f..6946d82 100644
--- a/src/modules/audio_processing/main/test/unit_test/unit_test.cc
+++ b/src/modules/audio_processing/main/test/unit_test/unit_test.cc
@@ -61,7 +61,6 @@
webrtc::AudioFrame* revframe_;
FILE* far_file_;
FILE* near_file_;
- bool update_output_data_;
};
ApmTest::ApmTest()
@@ -122,16 +121,52 @@
apm_ = NULL;
}
-void MixStereoToMono(WebRtc_Word16* stereo,
+void MixStereoToMono(const WebRtc_Word16* stereo,
WebRtc_Word16* mono,
- int numSamples) {
- for (int i = 0; i < numSamples; i++) {
+ int num_samples) {
+ for (int i = 0; i < num_samples; i++) {
int int32 = (static_cast<int>(stereo[i * 2]) +
static_cast<int>(stereo[i * 2 + 1])) >> 1;
mono[i] = static_cast<WebRtc_Word16>(int32);
}
}
+template <class T>
+T MaxValue(T a, T b) {
+ return a > b ? a : b;
+}
+
+template <class T>
+T AbsValue(T a) {
+ return a > 0 ? a : -a;
+}
+
+WebRtc_Word16 MaxAudioFrame(const AudioFrame& frame) {
+ const int length = frame._payloadDataLengthInSamples * frame._audioChannel;
+ WebRtc_Word16 max = AbsValue(frame._payloadData[0]);
+ for (int i = 1; i < length; i++) {
+ max = MaxValue(max, AbsValue(frame._payloadData[i]));
+ }
+
+ return max;
+}
+
+void TestStats(const AudioProcessing::Statistic& test,
+ const audio_processing_unittest::Test::Statistic& reference) {
+ EXPECT_EQ(reference.instant(), test.instant);
+ EXPECT_EQ(reference.average(), test.average);
+ EXPECT_EQ(reference.maximum(), test.maximum);
+ EXPECT_EQ(reference.minimum(), test.minimum);
+}
+
+void WriteStatsMessage(const AudioProcessing::Statistic& output,
+ audio_processing_unittest::Test::Statistic* message) {
+ message->set_instant(output.instant);
+ message->set_average(output.average);
+ message->set_maximum(output.maximum);
+ message->set_minimum(output.minimum);
+}
+
void WriteMessageLiteToFile(const char* filename,
const ::google::protobuf::MessageLite& message) {
assert(filename != NULL);
@@ -376,16 +411,19 @@
} else {
// We don't have a file; add the required tests to the protobuf.
- int rev_ch[] = {1, 2};
- int ch[] = {1, 2};
- int fs[] = {8000, 16000, 32000};
- for (size_t i = 0; i < sizeof(rev_ch) / sizeof(*rev_ch); i++) {
- for (size_t j = 0; j < sizeof(ch) / sizeof(*ch); j++) {
- for (size_t k = 0; k < sizeof(fs) / sizeof(*fs); k++) {
+ // TODO(ajm): vary the output channels as well?
+ const int channels[] = {1, 2};
+ const int channels_size = sizeof(channels) / sizeof(*channels);
+ const int sample_rates[] = {8000, 16000, 32000};
+ const int sample_rates_size = sizeof(sample_rates) / sizeof(*sample_rates);
+ for (size_t i = 0; i < channels_size; i++) {
+ for (size_t j = 0; j < channels_size; j++) {
+ for (size_t k = 0; k < sample_rates_size; k++) {
audio_processing_unittest::Test* test = output_data.add_test();
- test->set_numreversechannels(rev_ch[i]);
- test->set_numchannels(ch[j]);
- test->set_samplerate(fs[k]);
+ test->set_num_reverse_channels(channels[i]);
+ test->set_num_input_channels(channels[j]);
+ test->set_num_output_channels(channels[j]);
+ test->set_sample_rate(sample_rates[k]);
}
}
}
@@ -419,29 +457,31 @@
printf("Running test %d of %d...\n", i + 1, output_data.test_size());
audio_processing_unittest::Test* test = output_data.mutable_test(i);
- const int num_samples = test->samplerate() / 100;
+ const int num_samples = test->sample_rate() / 100;
revframe_->_payloadDataLengthInSamples = num_samples;
- revframe_->_audioChannel = test->numreversechannels();
- revframe_->_frequencyInHz = test->samplerate();
+ revframe_->_audioChannel = test->num_reverse_channels();
+ revframe_->_frequencyInHz = test->sample_rate();
frame_->_payloadDataLengthInSamples = num_samples;
- frame_->_audioChannel = test->numchannels();
- frame_->_frequencyInHz = test->samplerate();
+ frame_->_audioChannel = test->num_input_channels();
+ frame_->_frequencyInHz = test->sample_rate();
EXPECT_EQ(apm_->kNoError, apm_->Initialize());
- ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(test->samplerate()));
+ ASSERT_EQ(apm_->kNoError, apm_->set_sample_rate_hz(test->sample_rate()));
ASSERT_EQ(apm_->kNoError, apm_->set_num_channels(frame_->_audioChannel,
frame_->_audioChannel));
ASSERT_EQ(apm_->kNoError,
apm_->set_num_reverse_channels(revframe_->_audioChannel));
-
+ int frame_count = 0;
int has_echo_count = 0;
int has_voice_count = 0;
int is_saturated_count = 0;
+ int analog_level = 127;
+ int analog_level_average = 0;
+ int max_output_average = 0;
while (1) {
WebRtc_Word16 temp_data[640];
- int analog_level = 127;
// Read far-end frame
size_t read_count = fread(temp_data,
@@ -493,43 +533,73 @@
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
+ max_output_average += MaxAudioFrame(*frame_);
+
if (apm_->echo_cancellation()->stream_has_echo()) {
has_echo_count++;
}
analog_level = apm_->gain_control()->stream_analog_level();
+ analog_level_average += analog_level;
if (apm_->gain_control()->stream_is_saturated()) {
is_saturated_count++;
}
if (apm_->voice_detection()->stream_has_voice()) {
has_voice_count++;
}
- }
- //<-- Statistics -->
+ frame_count++;
+ }
+ max_output_average /= frame_count;
+ analog_level_average /= frame_count;
+
//LevelEstimator::Metrics far_metrics;
//LevelEstimator::Metrics near_metrics;
- //EchoCancellation::Metrics echo_metrics;
- //LevelEstimator::Metrics far_metrics_ref_;
- //LevelEstimator::Metrics near_metrics_ref_;
- //EchoCancellation::Metrics echo_metrics_ref_;
- //EXPECT_EQ(apm_->kNoError,
- // apm_->echo_cancellation()->GetMetrics(&echo_metrics));
//EXPECT_EQ(apm_->kNoError,
// apm_->level_estimator()->GetMetrics(&near_metrics,
+ EchoCancellation::Metrics echo_metrics;
+ EXPECT_EQ(apm_->kNoError,
+ apm_->echo_cancellation()->GetMetrics(&echo_metrics));
+
// TODO(ajm): check echo metrics and output audio.
if (global_read_output_data) {
- EXPECT_EQ(has_echo_count,
- test->hasechocount());
- EXPECT_EQ(has_voice_count,
- test->hasvoicecount());
- EXPECT_EQ(is_saturated_count,
- test->issaturatedcount());
+ EXPECT_EQ(test->has_echo_count(), has_echo_count);
+ EXPECT_EQ(test->has_voice_count(), has_voice_count);
+ EXPECT_EQ(test->is_saturated_count(), is_saturated_count);
+
+ EXPECT_EQ(test->analog_level_average(), analog_level_average);
+ EXPECT_EQ(test->max_output_average(), max_output_average);
+
+ audio_processing_unittest::Test::EchoMetrics reference =
+ test->echo_metrics();
+ TestStats(echo_metrics.residual_echo_return_loss,
+ reference.residual_echo_return_loss());
+ TestStats(echo_metrics.echo_return_loss,
+ reference.echo_return_loss());
+ TestStats(echo_metrics.echo_return_loss_enhancement,
+ reference.echo_return_loss_enhancement());
+ TestStats(echo_metrics.a_nlp,
+ reference.a_nlp());
+
} else {
- test->set_hasechocount(has_echo_count);
- test->set_hasvoicecount(has_voice_count);
- test->set_issaturatedcount(is_saturated_count);
+ test->set_has_echo_count(has_echo_count);
+ test->set_has_voice_count(has_voice_count);
+ test->set_is_saturated_count(is_saturated_count);
+
+ test->set_analog_level_average(analog_level_average);
+ test->set_max_output_average(max_output_average);
+
+ audio_processing_unittest::Test::EchoMetrics* message =
+ test->mutable_echo_metrics();
+ WriteStatsMessage(echo_metrics.residual_echo_return_loss,
+ message->mutable_residual_echo_return_loss());
+ WriteStatsMessage(echo_metrics.echo_return_loss,
+ message->mutable_echo_return_loss());
+ WriteStatsMessage(echo_metrics.echo_return_loss_enhancement,
+ message->mutable_echo_return_loss_enhancement());
+ WriteStatsMessage(echo_metrics.a_nlp,
+ message->mutable_a_nlp());
}
rewind(far_file_);