From 8458cff411a6a69a661993bbb479ed211fb602e8 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Thu, 22 Mar 2018 16:50:06 +0100 Subject: [PATCH] Extend TestAudioDeviceModule API. Extend TestAudioDeviceModule API to be able to create WavReader/WavWriter from rtc::PlatformFile Bug: webrtc:8946 Change-Id: Ieea16be91c40a5928689cdeaa8a17d75fee0cf82 Reviewed-on: https://webrtc-review.googlesource.com/63266 Commit-Queue: Artem Titov Reviewed-by: Karl Wiberg Cr-Commit-Position: refs/heads/master@{#22576} --- .../audio_device/include/test_audio_device.cc | 133 ++++++++++++------ .../audio_device/include/test_audio_device.h | 68 ++++----- .../include/test_audio_device_unittest.cc | 68 ++++++++- 3 files changed, 187 insertions(+), 82 deletions(-) diff --git a/modules/audio_device/include/test_audio_device.cc b/modules/audio_device/include/test_audio_device.cc index f888cd0838..b67d52970f 100644 --- a/modules/audio_device/include/test_audio_device.cc +++ b/modules/audio_device/include/test_audio_device.cc @@ -21,7 +21,9 @@ #include "rtc_base/checks.h" #include "rtc_base/criticalsection.h" #include "rtc_base/event.h" +#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/platform_thread.h" +#include "rtc_base/ptr_util.h" #include "rtc_base/random.h" #include "rtc_base/refcountedobject.h" #include "system_wrappers/include/event_wrapper.h" @@ -276,12 +278,16 @@ class WavFileReader final : public TestAudioDeviceModule::Capturer { WavFileReader(std::string filename, int sampling_frequency_in_hz, int num_channels) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - num_channels_(num_channels), - wav_reader_(filename) { - RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); - RTC_CHECK_EQ(wav_reader_.num_channels(), num_channels); - } + : WavFileReader(rtc::MakeUnique(filename), + sampling_frequency_in_hz, + num_channels) {} + + WavFileReader(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) + : WavFileReader(rtc::MakeUnique(file), + sampling_frequency_in_hz, + num_channels) {} int SamplingFrequency() const override { return sampling_frequency_in_hz_; } @@ -292,15 +298,25 @@ class WavFileReader final : public TestAudioDeviceModule::Capturer { TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz_) * num_channels_, [&](rtc::ArrayView data) { - return wav_reader_.ReadSamples(data.size(), data.data()); + return wav_reader_->ReadSamples(data.size(), data.data()); }); return buffer->size() > 0; } private: + WavFileReader(std::unique_ptr wav_reader, + int sampling_frequency_in_hz, + int num_channels) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + num_channels_(num_channels), + wav_reader_(std::move(wav_reader)) { + RTC_CHECK_EQ(wav_reader_->sample_rate(), sampling_frequency_in_hz); + RTC_CHECK_EQ(wav_reader_->num_channels(), num_channels); + } + int sampling_frequency_in_hz_; const int num_channels_; - WavReader wav_reader_; + std::unique_ptr wav_reader_; }; class WavFileWriter final : public TestAudioDeviceModule::Renderer { @@ -308,22 +324,40 @@ class WavFileWriter final : public TestAudioDeviceModule::Renderer { WavFileWriter(std::string filename, int sampling_frequency_in_hz, int num_channels) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - wav_writer_(filename, sampling_frequency_in_hz, num_channels), - num_channels_(num_channels) {} + : WavFileWriter(rtc::MakeUnique(filename, + sampling_frequency_in_hz, + num_channels), + sampling_frequency_in_hz, + num_channels) {} + + WavFileWriter(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) + : WavFileWriter(rtc::MakeUnique(file, + sampling_frequency_in_hz, + num_channels), + sampling_frequency_in_hz, + num_channels) {} int SamplingFrequency() const override { return sampling_frequency_in_hz_; } int NumChannels() const override { return num_channels_; } bool Render(rtc::ArrayView data) override { - wav_writer_.WriteSamples(data.data(), data.size()); + wav_writer_->WriteSamples(data.data(), data.size()); return true; } private: + WavFileWriter(std::unique_ptr wav_writer, + int sampling_frequency_in_hz, + int num_channels) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(std::move(wav_writer)), + num_channels_(num_channels) {} + int sampling_frequency_in_hz_; - WavWriter wav_writer_; + std::unique_ptr wav_writer_; const int num_channels_; }; @@ -342,6 +376,19 @@ class BoundedWavFileWriter : public TestAudioDeviceModule::Renderer { started_writing_(false), trailing_zeros_(0) {} + BoundedWavFileWriter(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(file, sampling_frequency_in_hz, num_channels), + num_channels_(num_channels), + silent_audio_( + TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz) * + num_channels, + 0), + started_writing_(false), + trailing_zeros_(0) {} + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } int NumChannels() const override { return num_channels_; } @@ -436,11 +483,11 @@ TestAudioDeviceModule::CreatePulsedNoiseCapturer(int16_t max_amplitude, num_channels)); } -std::unique_ptr -TestAudioDeviceModule::CreatePulsedNoiseCapturer(int16_t max_amplitude, - int sampling_frequency_in_hz) { - return std::unique_ptr( - new PulsedNoiseCapturerImpl(max_amplitude, sampling_frequency_in_hz, 1)); +std::unique_ptr +TestAudioDeviceModule::CreateDiscardRenderer(int sampling_frequency_in_hz, + int num_channels) { + return std::unique_ptr( + new DiscardRenderer(sampling_frequency_in_hz, num_channels)); } std::unique_ptr @@ -451,18 +498,11 @@ TestAudioDeviceModule::CreateWavFileReader(std::string filename, new WavFileReader(filename, sampling_frequency_in_hz, num_channels)); } -std::unique_ptr -TestAudioDeviceModule::CreateWavFileReader(std::string filename, - int sampling_frequency_in_hz) { - return std::unique_ptr( - new WavFileReader(filename, sampling_frequency_in_hz, 1)); -} - std::unique_ptr TestAudioDeviceModule::CreateWavFileReader(std::string filename) { WavReader reader(filename); int sampling_frequency_in_hz = reader.sample_rate(); - int num_channels = static_cast(reader.num_channels()); + int num_channels = rtc::checked_cast(reader.num_channels()); return std::unique_ptr( new WavFileReader(filename, sampling_frequency_in_hz, num_channels)); } @@ -475,13 +515,6 @@ TestAudioDeviceModule::CreateWavFileWriter(std::string filename, new WavFileWriter(filename, sampling_frequency_in_hz, num_channels)); } -std::unique_ptr -TestAudioDeviceModule::CreateWavFileWriter(std::string filename, - int sampling_frequency_in_hz) { - return std::unique_ptr( - new WavFileWriter(filename, sampling_frequency_in_hz, 1)); -} - std::unique_ptr TestAudioDeviceModule::CreateBoundedWavFileWriter(std::string filename, int sampling_frequency_in_hz, @@ -491,25 +524,37 @@ TestAudioDeviceModule::CreateBoundedWavFileWriter(std::string filename, num_channels)); } -std::unique_ptr -TestAudioDeviceModule::CreateBoundedWavFileWriter( - std::string filename, - int sampling_frequency_in_hz) { - return std::unique_ptr( - new BoundedWavFileWriter(filename, sampling_frequency_in_hz, 1)); +std::unique_ptr +TestAudioDeviceModule::CreateWavFileReader(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) { + return std::unique_ptr( + new WavFileReader(file, sampling_frequency_in_hz, num_channels)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateWavFileReader(rtc::PlatformFile file) { + WavReader reader(file); + int sampling_frequency_in_hz = reader.sample_rate(); + int num_channels = rtc::checked_cast(reader.num_channels()); + return std::unique_ptr( + new WavFileReader(file, sampling_frequency_in_hz, num_channels)); } std::unique_ptr -TestAudioDeviceModule::CreateDiscardRenderer(int sampling_frequency_in_hz, - int num_channels) { +TestAudioDeviceModule::CreateWavFileWriter(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) { return std::unique_ptr( - new DiscardRenderer(sampling_frequency_in_hz, num_channels)); + new WavFileWriter(file, sampling_frequency_in_hz, num_channels)); } std::unique_ptr -TestAudioDeviceModule::CreateDiscardRenderer(int sampling_frequency_in_hz) { +TestAudioDeviceModule::CreateBoundedWavFileWriter(rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels) { return std::unique_ptr( - new DiscardRenderer(sampling_frequency_in_hz, 1)); + new BoundedWavFileWriter(file, sampling_frequency_in_hz, num_channels)); } } // namespace webrtc diff --git a/modules/audio_device/include/test_audio_device.h b/modules/audio_device/include/test_audio_device.h index 58a922e750..4a75df3f86 100644 --- a/modules/audio_device/include/test_audio_device.h +++ b/modules/audio_device/include/test_audio_device.h @@ -17,6 +17,7 @@ #include "modules/audio_device/include/audio_device.h" #include "rtc_base/buffer.h" #include "rtc_base/event.h" +#include "rtc_base/platform_file.h" #include "typedefs.h" // NOLINT(build/include) namespace webrtc { @@ -85,40 +86,31 @@ class TestAudioDeviceModule : public AudioDeviceModule { static std::unique_ptr CreatePulsedNoiseCapturer( int16_t max_amplitude, int sampling_frequency_in_hz, - int num_channels); + int num_channels = 1); - // Same as calling CreatePulsedNoiseCapturer(max_amplitude, - // sampling_frequency_in_hz, 1). - static std::unique_ptr CreatePulsedNoiseCapturer( - int16_t max_amplitude, - int sampling_frequency_in_hz); + // Returns a Renderer instance that does nothing with the audio data. + static std::unique_ptr CreateDiscardRenderer( + int sampling_frequency_in_hz, + int num_channels = 1); + + // WavReader and WavWriter creation based on file name. // Returns a Capturer instance that gets its data from a file. The sample rate - // and channels will be check against the Wav file. + // and channels will be checked against the Wav file. static std::unique_ptr CreateWavFileReader( std::string filename, int sampling_frequency_in_hz, - int num_channels); - - // Same as calling CreateWavFileReader(filename, sampling_frequency_in_hz, 1). - static std::unique_ptr CreateWavFileReader( - std::string filename, - int sampling_frequency_in_hz); + int num_channels = 1); // Returns a Capturer instance that gets its data from a file. - // Automatically detects sample rate. + // Automatically detects sample rate and num of channels. static std::unique_ptr CreateWavFileReader(std::string filename); // Returns a Renderer instance that writes its data to a file. static std::unique_ptr CreateWavFileWriter( std::string filename, int sampling_frequency_in_hz, - int num_channels); - - // Same as calling CreateWavFileWriter(filename, sampling_frequency_in_hz, 1). - static std::unique_ptr CreateWavFileWriter( - std::string filename, - int sampling_frequency_in_hz); + int num_channels = 1); // Returns a Renderer instance that writes its data to a WAV file, cutting // off silence at the beginning (not necessarily perfect silence, see @@ -126,22 +118,34 @@ class TestAudioDeviceModule : public AudioDeviceModule { static std::unique_ptr CreateBoundedWavFileWriter( std::string filename, int sampling_frequency_in_hz, - int num_channels); + int num_channels = 1); - // Same as calling CreateBounderWavFileWriter(filename, - // sampling_frequency_in_hz, 1). - static std::unique_ptr CreateBoundedWavFileWriter( - std::string filename, - int sampling_frequency_in_hz); + // WavReader and WavWriter creation based on rtc::PlatformFile. - // Returns a Renderer instance that does nothing with the audio data. - static std::unique_ptr CreateDiscardRenderer( + // Returns a Capturer instance that gets its data from a file. The sample rate + // and channels will be checked against the Wav file. + static std::unique_ptr CreateWavFileReader( + rtc::PlatformFile file, int sampling_frequency_in_hz, - int num_channels); + int num_channels = 1); - // Same as calling CreateDiscardRenderer(sampling_frequency_in_hz, 1). - static std::unique_ptr CreateDiscardRenderer( - int sampling_frequency_in_hz); + // Returns a Capturer instance that gets its data from a file. + // Automatically detects sample rate and num of channels. + static std::unique_ptr CreateWavFileReader(rtc::PlatformFile file); + + // Returns a Renderer instance that writes its data to a file. + static std::unique_ptr CreateWavFileWriter( + rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels = 1); + + // Returns a Renderer instance that writes its data to a WAV file, cutting + // off silence at the beginning (not necessarily perfect silence, see + // kAmplitudeThreshold) and at the end (only actual 0 samples in this case). + static std::unique_ptr CreateBoundedWavFileWriter( + rtc::PlatformFile file, + int sampling_frequency_in_hz, + int num_channels = 1); virtual int32_t Init() = 0; virtual int32_t RegisterAudioCallback(AudioTransport* callback) = 0; diff --git a/modules/audio_device/include/test_audio_device_unittest.cc b/modules/audio_device/include/test_audio_device_unittest.cc index 674df1ba7e..bdb1285e85 100644 --- a/modules/audio_device/include/test_audio_device_unittest.cc +++ b/modules/audio_device/include/test_audio_device_unittest.cc @@ -11,30 +11,78 @@ #include #include +#include "api/array_view.h" #include "common_audio/wav_file.h" #include "common_audio/wav_header.h" #include "modules/audio_device/include/test_audio_device.h" +#include "rtc_base/logging.h" +#include "test/gmock.h" #include "test/gtest.h" #include "test/testsupport/fileutils.h" namespace webrtc { namespace { -void RunTest(const std::vector& input_samples, - const std::vector& expected_samples, - size_t samples_per_frame) { + +void RunTestViaRtcPlatformFileAPI( + rtc::ArrayView input_samples, + rtc::ArrayView expected_samples, + size_t samples_per_frame) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - const std::string output_filename = test::OutputPath() + - "BoundedWavFileWriterTest_" + - test_info->name() + ".wav"; + const std::string output_filename = + test::OutputPath() + "BoundedWavFileWriterTest_" + test_info->name() + + "_" + std::to_string(std::rand()) + ".wav"; static const size_t kSamplesPerFrame = 8; static const int kSampleRate = kSamplesPerFrame * 100; EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate), kSamplesPerFrame); + // Test through rtc::PlatformFile API. + { + auto file = rtc::CreatePlatformFile(output_filename); + std::unique_ptr writer = + TestAudioDeviceModule::CreateBoundedWavFileWriter(file, 800); + + for (size_t i = 0; i < input_samples.size(); i += kSamplesPerFrame) { + EXPECT_TRUE(writer->Render(rtc::ArrayView( + &input_samples[i], + std::min(kSamplesPerFrame, input_samples.size() - i)))); + } + } + + { + auto file = rtc::OpenPlatformFile(output_filename); + WavReader reader(file); + std::vector read_samples(expected_samples.size()); + EXPECT_EQ(expected_samples.size(), + reader.ReadSamples(read_samples.size(), read_samples.data())); + EXPECT_THAT(expected_samples, testing::ElementsAreArray(read_samples)); + + EXPECT_EQ(0u, reader.ReadSamples(read_samples.size(), read_samples.data())); + } + + remove(output_filename.c_str()); +} + +void RunTest(const std::vector& input_samples, + const std::vector& expected_samples, + size_t samples_per_frame) { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + + const std::string output_filename = + test::OutputPath() + "BoundedWavFileWriterTest_" + test_info->name() + + "_" + std::to_string(std::rand()) + ".wav"; + + static const size_t kSamplesPerFrame = 8; + static const int kSampleRate = kSamplesPerFrame * 100; + EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate), + kSamplesPerFrame); + + // Test through file name API. { std::unique_ptr writer = TestAudioDeviceModule::CreateBoundedWavFileWriter(output_filename, 800); @@ -76,6 +124,14 @@ TEST(BoundedWavFileWriterTest, SomeStartSilence) { RunTest(kInputSamples, kExpectedSamples, 8); } +TEST(BoundedWavFileWriterTest, SomeStartSilenceRtcFile) { + static const std::vector kInputSamples = { + 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8}; + static const std::vector kExpectedSamples(kInputSamples.begin() + 10, + kInputSamples.end()); + RunTestViaRtcPlatformFileAPI(kInputSamples, kExpectedSamples, 8); +} + TEST(BoundedWavFileWriterTest, NegativeStartSilence) { static const std::vector kInputSamples = { 0, -4, -6, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8};