From 36e6a8f1bd1fd91ed5d9f6c29e6e0ae77881a710 Mon Sep 17 00:00:00 2001 From: alessiob Date: Mon, 10 Apr 2017 00:53:53 -0700 Subject: [PATCH] WavReaderAdaptor is a simple adaptor of the existing class WavReader from webrtc/common_audio/wav_file.h. The adaptor was mainly needed to use dependency injection and easily test the MultiEndCall class (see https://codereview.webrtc.org/2761853002/). The unit test ConversationalSpeechTest.MultiEndCallWavReaderAdaptorSine uses CreateSineWavFile() and writes temporary wav files that are used for test (deleted only if the test passes). BUG=webrtc:7218 Review-Url: https://codereview.webrtc.org/2774423005 Cr-Commit-Position: refs/heads/master@{#17608} --- .../test/conversational_speech/BUILD.gn | 3 +- .../generator_unittest.cc | 55 +++++++++++++++++- .../conversational_speech/mock_wavreader.cc | 6 +- .../conversational_speech/mock_wavreader.h | 11 ++-- .../conversational_speech/multiend_call.cc | 6 +- .../wavreader_adaptor.cc | 58 ------------------- .../conversational_speech/wavreader_adaptor.h | 42 -------------- .../wavreader_factory.cc | 43 +++++++++++++- .../wavreader_interface.h | 11 ++-- 9 files changed, 115 insertions(+), 120 deletions(-) delete mode 100644 webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.cc delete mode 100644 webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h diff --git a/webrtc/modules/audio_processing/test/conversational_speech/BUILD.gn b/webrtc/modules/audio_processing/test/conversational_speech/BUILD.gn index 10601fed3c..b74c05bf97 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/BUILD.gn +++ b/webrtc/modules/audio_processing/test/conversational_speech/BUILD.gn @@ -38,8 +38,6 @@ rtc_static_library("lib") { "timing.cc", "timing.h", "wavreader_abstract_factory.h", - "wavreader_adaptor.cc", - "wavreader_adaptor.h", "wavreader_factory.cc", "wavreader_factory.h", "wavreader_interface.h", @@ -65,6 +63,7 @@ rtc_source_set("unittest") { ":lib", "../../../../../webrtc:webrtc_common", "../../../../../webrtc/base:rtc_base_approved", + "../../../../../webrtc/common_audio", "../../../../../webrtc/test:test_support", "//testing/gmock", "//testing/gtest", diff --git a/webrtc/modules/audio_processing/test/conversational_speech/generator_unittest.cc b/webrtc/modules/audio_processing/test/conversational_speech/generator_unittest.cc index 406d95cf21..6797beb983 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/generator_unittest.cc +++ b/webrtc/modules/audio_processing/test/conversational_speech/generator_unittest.cc @@ -33,15 +33,22 @@ // cases in which there are wrong offsets leading to self cross-talk (which is // rejected). +// MSVC++ requires this to be set before any other includes to get M_PI. +#define _USE_MATH_DEFINES + #include +#include #include #include #include "webrtc/base/logging.h" +#include "webrtc/base/pathutils.h" +#include "webrtc/common_audio/wav_file.h" #include "webrtc/modules/audio_processing/test/conversational_speech/config.h" #include "webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader_factory.h" #include "webrtc/modules/audio_processing/test/conversational_speech/multiend_call.h" #include "webrtc/modules/audio_processing/test/conversational_speech/timing.h" +#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.h" #include "webrtc/test/gmock.h" #include "webrtc/test/gtest.h" #include "webrtc/test/testsupport/fileutils.h" @@ -55,7 +62,7 @@ using conversational_speech::SaveTiming; using conversational_speech::MockWavReaderFactory; using conversational_speech::MultiEndCall; using conversational_speech::Turn; -using conversational_speech::WavReaderAbstractFactory; +using conversational_speech::WavReaderFactory; const char* const audiotracks_path = "/path/to/audiotracks"; const char* const timing_filepath = "/path/to/timing_file.txt"; @@ -89,6 +96,23 @@ std::unique_ptr CreateMockWavReaderFactory() { kDefaultMockWavReaderFactoryParamsMap)); } +void CreateSineWavFile(const std::string& filepath, + const MockWavReaderFactory::Params& params, + float frequency = 440.0f) { + // Create samples. + constexpr double two_pi = 2.0 * M_PI; + std::vector samples(params.num_samples); + for (std::size_t i = 0; i < params.num_samples; ++i) { + // TODO(alessiob): the produced tone is not pure, improve. + samples[i] = std::lround(32767.0f * std::sin( + two_pi * i * frequency / params.sample_rate)); + } + + // Write samples. + WavWriter wav_writer(filepath, params.sample_rate, params.num_channels); + wav_writer.WriteSamples(samples.data(), params.num_samples); +} + } // namespace using testing::_; @@ -487,5 +511,34 @@ TEST_F(ConversationalSpeechTest, MultiEndCallSetupLongSequenceInvalid) { EXPECT_FALSE(multiend_call.valid()); } +TEST_F(ConversationalSpeechTest, MultiEndCallWavReaderAdaptorSine) { + // Parameters with which wav files are created. + constexpr int duration_seconds = 5; + const int sample_rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000}; + + for (int sample_rate : sample_rates) { + const rtc::Pathname temp_filename( + OutputPath(), "TempSineWavFile_" + std::to_string(sample_rate) + + ".wav"); + + // Write wav file. + const std::size_t num_samples = duration_seconds * sample_rate; + MockWavReaderFactory::Params params = {sample_rate, 1u, num_samples}; + CreateSineWavFile(temp_filename.pathname(), params); + LOG(LS_VERBOSE) << "wav file @" << sample_rate << " Hz created (" + << num_samples << " samples)"; + + // Load wav file and check if params match. + WavReaderFactory wav_reader_factory; + auto wav_reader = wav_reader_factory.Create(temp_filename.pathname()); + EXPECT_EQ(sample_rate, wav_reader->SampleRate()); + EXPECT_EQ(1u, wav_reader->NumChannels()); + EXPECT_EQ(num_samples, wav_reader->NumSamples()); + + // Clean up. + remove(temp_filename.pathname().c_str()); + } +} + } // namespace test } // namespace webrtc diff --git a/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.cc b/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.cc index 7d2f2b663e..6b92339adc 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.cc +++ b/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.cc @@ -20,9 +20,9 @@ MockWavReader::MockWavReader( int sample_rate, size_t num_channels, size_t num_samples) : sample_rate_(sample_rate), num_channels_(num_channels), num_samples_(num_samples) { - ON_CALL(*this, sample_rate()).WillByDefault(Return(sample_rate_)); - ON_CALL(*this, num_channels()).WillByDefault(Return(num_channels_)); - ON_CALL(*this, num_samples()).WillByDefault(Return(num_samples_)); + ON_CALL(*this, SampleRate()).WillByDefault(Return(sample_rate_)); + ON_CALL(*this, NumChannels()).WillByDefault(Return(num_channels_)); + ON_CALL(*this, NumSamples()).WillByDefault(Return(num_samples_)); } MockWavReader::~MockWavReader() = default; diff --git a/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.h b/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.h index d71e6f896b..030e163e80 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.h +++ b/webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader.h @@ -14,6 +14,7 @@ #include #include +#include "webrtc/base/array_view.h" #include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h" #include "webrtc/test/gmock.h" #include "webrtc/typedefs.h" @@ -28,12 +29,12 @@ class MockWavReader : public WavReaderInterface { ~MockWavReader(); // TODO(alessiob): use ON_CALL to return random samples. - MOCK_METHOD2(ReadFloatSamples, size_t(size_t, float*)); - MOCK_METHOD2(ReadInt16Samples, size_t(size_t, int16_t*)); + MOCK_METHOD1(ReadFloatSamples, size_t(rtc::ArrayView)); + MOCK_METHOD1(ReadInt16Samples, size_t(rtc::ArrayView)); - MOCK_CONST_METHOD0(sample_rate, int()); - MOCK_CONST_METHOD0(num_channels, size_t()); - MOCK_CONST_METHOD0(num_samples, size_t()); + MOCK_CONST_METHOD0(SampleRate, int()); + MOCK_CONST_METHOD0(NumChannels, size_t()); + MOCK_CONST_METHOD0(NumSamples, size_t()); private: const int sample_rate_; diff --git a/webrtc/modules/audio_processing/test/conversational_speech/multiend_call.cc b/webrtc/modules/audio_processing/test/conversational_speech/multiend_call.cc index ad1d9a0c87..624f981ae5 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/multiend_call.cc +++ b/webrtc/modules/audio_processing/test/conversational_speech/multiend_call.cc @@ -120,9 +120,9 @@ bool MultiEndCall::CheckTiming() { // Begin and end timestamps for the current turn. int offset_samples = millisecond_to_samples( - turn.offset, it->second->sample_rate()); - size_t begin_timestamp = last_turn.end + offset_samples; - size_t end_timestamp = begin_timestamp + it->second->num_samples(); + turn.offset, it->second->SampleRate()); + std::size_t begin_timestamp = last_turn.end + offset_samples; + std::size_t end_timestamp = begin_timestamp + it->second->NumSamples(); LOG(LS_INFO) << "turn #" << turn_index << " " << begin_timestamp << "-" << end_timestamp << " ms"; diff --git a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.cc b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.cc deleted file mode 100644 index b441a044ee..0000000000 --- a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017 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 "webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h" - -#include "webrtc/base/checks.h" - -namespace webrtc { -namespace test { -namespace conversational_speech { - -WavReaderAdaptor::WavReaderAdaptor(const std::string& filepath) { - // TODO(alessiob): implement. -} - -WavReaderAdaptor::~WavReaderAdaptor() {} - -size_t WavReaderAdaptor::ReadFloatSamples(size_t num_samples, float* samples) { - // TODO(alessiob): implement. - FATAL(); - return 0u; -} - -size_t WavReaderAdaptor::ReadInt16Samples( - size_t num_samples, int16_t* samples) { - // TODO(alessiob): implement. - FATAL(); - return 0u; -} - -int WavReaderAdaptor::sample_rate() const { - // TODO(alessiob): implement. - FATAL(); - return 0; -} - -size_t WavReaderAdaptor::num_channels() const { - // TODO(alessiob): implement. - FATAL(); - return 0u; -} - -size_t WavReaderAdaptor::num_samples() const { - // TODO(alessiob): implement. - FATAL(); - return 0u; -} - -} // namespace conversational_speech -} // namespace test -} // namespace webrtc diff --git a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h deleted file mode 100644 index 54894934db..0000000000 --- a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2017 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. - */ - -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_ - -#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h" - -#include -#include - -#include "webrtc/typedefs.h" - -namespace webrtc { -namespace test { -namespace conversational_speech { - -class WavReaderAdaptor : public WavReaderInterface { - public: - explicit WavReaderAdaptor(const std::string& filepath); - ~WavReaderAdaptor() override; - - size_t ReadFloatSamples(size_t num_samples, float* samples) override; - size_t ReadInt16Samples(size_t num_samples, int16_t* samples) override; - - int sample_rate() const override; - size_t num_channels() const override; - size_t num_samples() const override; -}; - -} // namespace conversational_speech -} // namespace test -} // namespace webrtc - -#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_ diff --git a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.cc b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.cc index f9d43f8070..db126d04e3 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.cc +++ b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.cc @@ -10,10 +10,51 @@ #include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.h" -#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h" +#include + +#include "webrtc/base/array_view.h" +#include "webrtc/base/checks.h" +#include "webrtc/common_audio/wav_file.h" +#include "webrtc/typedefs.h" namespace webrtc { namespace test { +namespace { + +using conversational_speech::WavReaderInterface; + +class WavReaderAdaptor final : public WavReaderInterface { + public: + explicit WavReaderAdaptor(const std::string& filepath) + : wav_reader_(filepath) {} + ~WavReaderAdaptor() override = default; + + size_t ReadFloatSamples(rtc::ArrayView samples) override { + return wav_reader_.ReadSamples(samples.size(), samples.begin()); + } + + size_t ReadInt16Samples(rtc::ArrayView samples) override { + return wav_reader_.ReadSamples(samples.size(), samples.begin()); + } + + int SampleRate() const override { + return wav_reader_.sample_rate(); + } + + size_t NumChannels() const override { + return wav_reader_.num_channels(); + } + + size_t NumSamples() const override { + return wav_reader_.num_samples(); + } + + private: + WavReader wav_reader_; +}; + +} // namespace + namespace conversational_speech { WavReaderFactory::WavReaderFactory() = default; diff --git a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h index 0c99591788..57342b4d1f 100644 --- a/webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h +++ b/webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h @@ -13,6 +13,7 @@ #include +#include "webrtc/base/array_view.h" #include "webrtc/typedefs.h" namespace webrtc { @@ -24,13 +25,13 @@ class WavReaderInterface { virtual ~WavReaderInterface() = default; // Returns the number of samples read. - virtual size_t ReadFloatSamples(size_t num_samples, float* samples) = 0; - virtual size_t ReadInt16Samples(size_t num_samples, int16_t* samples) = 0; + virtual size_t ReadFloatSamples(rtc::ArrayView samples) = 0; + virtual size_t ReadInt16Samples(rtc::ArrayView samples) = 0; // Getters. - virtual int sample_rate() const = 0; - virtual size_t num_channels() const = 0; - virtual size_t num_samples() const = 0; + virtual int SampleRate() const = 0; + virtual size_t NumChannels() const = 0; + virtual size_t NumSamples() const = 0; }; } // namespace conversational_speech