From 0f039733657082f4d2cb1ff6ae0fe8263145e0c6 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Wed, 7 Mar 2018 12:20:51 +0100 Subject: [PATCH] Separate test/fake_audio_device on API and implementation. Step 1. Adding ability of injecting audio in end to end tests, that are using WebRTC. It will be done in 3 steps: 1. Test/fake_audio_device will be moved to production part of WebRTC source code and renamed to test_audio_device_module. Old header is replaced with alias to the new one. 2. Internal usage of FakeAudioDevice will be switch to TestAudioDevice. 3. test/fake_audio_device will be removed. This CL implements 1st step. Bug: webrtc:8946 Change-Id: Ia8df5155d369d83b3c2818a1129f78dd0848b01f Reviewed-on: https://webrtc-review.googlesource.com/59740 Commit-Queue: Artem Titov Reviewed-by: Karl Wiberg Cr-Commit-Position: refs/heads/master@{#22325} --- modules/audio_device/BUILD.gn | 6 + .../include/audio_device_default.h | 130 +++++ .../audio_device/include/fake_audio_device.h | 97 +--- .../audio_device/include/test_audio_device.h | 131 +++++ .../include/test_audio_device_impl.cc | 547 ++++++++++-------- .../include/test_audio_device_impl.h | 91 +++ .../test_audio_device_impl_unittest.cc | 49 +- test/BUILD.gn | 4 +- test/fake_audio_device.h | 148 +---- 9 files changed, 678 insertions(+), 525 deletions(-) create mode 100644 modules/audio_device/include/audio_device_default.h create mode 100644 modules/audio_device/include/test_audio_device.h rename test/fake_audio_device.cc => modules/audio_device/include/test_audio_device_impl.cc (50%) create mode 100644 modules/audio_device/include/test_audio_device_impl.h rename test/fake_audio_device_unittest.cc => modules/audio_device/include/test_audio_device_impl_unittest.cc (79%) diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn index 09732202e2..be53d36452 100644 --- a/modules/audio_device/BUILD.gn +++ b/modules/audio_device/BUILD.gn @@ -130,8 +130,12 @@ rtc_source_set("audio_device_generic") { "fine_audio_buffer.cc", "fine_audio_buffer.h", "include/audio_device.h", + "include/audio_device_default.h", "include/audio_device_defines.h", "include/fake_audio_device.h", + "include/test_audio_device.h", + "include/test_audio_device_impl.cc", + "include/test_audio_device_impl.h", ] if (build_with_mozilla) { @@ -340,12 +344,14 @@ if (rtc_include_tests) { sources = [ "fine_audio_buffer_unittest.cc", + "include/test_audio_device_impl_unittest.cc", ] deps = [ ":audio_device", ":mock_audio_device", "../../api:array_view", "../../api:optional", + "../../common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../system_wrappers", diff --git a/modules/audio_device/include/audio_device_default.h b/modules/audio_device/include/audio_device_default.h new file mode 100644 index 0000000000..8b052fb340 --- /dev/null +++ b/modules/audio_device/include/audio_device_default.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018 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 MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_ +#define MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_ + +#include "modules/audio_device/include/audio_device.h" + +namespace webrtc { +namespace webrtc_impl { + +// AudioDeviceModuleDefault template adds default implementation for all +// AudioDeviceModule methods to the class, which inherits from +// AudioDeviceModuleDefault. +template +class AudioDeviceModuleDefault : public T { + public: + AudioDeviceModuleDefault() {} + virtual ~AudioDeviceModuleDefault() {} + + int32_t RegisterAudioCallback(AudioTransport* audioCallback) override { + return 0; + } + int32_t Init() override { return 0; } + int32_t InitSpeaker() override { return 0; } + int32_t SetPlayoutDevice(uint16_t index) override { return 0; } + int32_t SetPlayoutDevice( + AudioDeviceModule::WindowsDeviceType device) override { + return 0; + } + int32_t SetStereoPlayout(bool enable) override { return 0; } + int32_t StopPlayout() override { return 0; } + int32_t InitMicrophone() override { return 0; } + int32_t SetRecordingDevice(uint16_t index) override { return 0; } + int32_t SetRecordingDevice( + AudioDeviceModule::WindowsDeviceType device) override { + return 0; + } + int32_t SetStereoRecording(bool enable) override { return 0; } + int32_t StopRecording() override { return 0; } + + int32_t Terminate() override { return 0; } + + int32_t ActiveAudioLayer( + AudioDeviceModule::AudioLayer* audioLayer) const override { + return 0; + } + bool Initialized() const override { return true; } + int16_t PlayoutDevices() override { return 0; } + int16_t RecordingDevices() override { return 0; } + int32_t PlayoutDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) override { + return 0; + } + int32_t RecordingDeviceName(uint16_t index, + char name[kAdmMaxDeviceNameSize], + char guid[kAdmMaxGuidSize]) override { + return 0; + } + int32_t PlayoutIsAvailable(bool* available) override { return 0; } + int32_t InitPlayout() override { return 0; } + bool PlayoutIsInitialized() const override { return true; } + int32_t RecordingIsAvailable(bool* available) override { return 0; } + int32_t InitRecording() override { return 0; } + bool RecordingIsInitialized() const override { return true; } + int32_t StartPlayout() override { return 0; } + bool Playing() const override { return false; } + int32_t StartRecording() override { return 0; } + bool Recording() const override { return false; } + bool SpeakerIsInitialized() const override { return true; } + bool MicrophoneIsInitialized() const override { return true; } + int32_t SpeakerVolumeIsAvailable(bool* available) override { return 0; } + int32_t SetSpeakerVolume(uint32_t volume) override { return 0; } + int32_t SpeakerVolume(uint32_t* volume) const override { return 0; } + int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override { return 0; } + int32_t MinSpeakerVolume(uint32_t* minVolume) const override { return 0; } + int32_t MicrophoneVolumeIsAvailable(bool* available) override { return 0; } + int32_t SetMicrophoneVolume(uint32_t volume) override { return 0; } + int32_t MicrophoneVolume(uint32_t* volume) const override { return 0; } + int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override { return 0; } + int32_t MinMicrophoneVolume(uint32_t* minVolume) const override { return 0; } + int32_t SpeakerMuteIsAvailable(bool* available) override { return 0; } + int32_t SetSpeakerMute(bool enable) override { return 0; } + int32_t SpeakerMute(bool* enabled) const override { return 0; } + int32_t MicrophoneMuteIsAvailable(bool* available) override { return 0; } + int32_t SetMicrophoneMute(bool enable) override { return 0; } + int32_t MicrophoneMute(bool* enabled) const override { return 0; } + int32_t StereoPlayoutIsAvailable(bool* available) const override { + *available = false; + return 0; + } + int32_t StereoPlayout(bool* enabled) const override { return 0; } + int32_t StereoRecordingIsAvailable(bool* available) const override { + *available = false; + return 0; + } + int32_t StereoRecording(bool* enabled) const override { return 0; } + int32_t PlayoutDelay(uint16_t* delayMS) const override { + *delayMS = 0; + return 0; + } + bool BuiltInAECIsAvailable() const override { return false; } + int32_t EnableBuiltInAEC(bool enable) override { return -1; } + bool BuiltInAGCIsAvailable() const override { return false; } + int32_t EnableBuiltInAGC(bool enable) override { return -1; } + bool BuiltInNSIsAvailable() const override { return false; } + int32_t EnableBuiltInNS(bool enable) override { return -1; } + +#if defined(WEBRTC_IOS) + int GetPlayoutAudioParameters(AudioParameters* params) const override { + return -1; + } + int GetRecordAudioParameters(AudioParameters* params) const override { + return -1; + } +#endif // WEBRTC_IOS +}; + +} // namespace webrtc_impl +} // namespace webrtc + +#endif // MODULES_AUDIO_DEVICE_INCLUDE_AUDIO_DEVICE_DEFAULT_H_ diff --git a/modules/audio_device/include/fake_audio_device.h b/modules/audio_device/include/fake_audio_device.h index f66cbfdadf..9949627a73 100644 --- a/modules/audio_device/include/fake_audio_device.h +++ b/modules/audio_device/include/fake_audio_device.h @@ -12,110 +12,19 @@ #define MODULES_AUDIO_DEVICE_INCLUDE_FAKE_AUDIO_DEVICE_H_ #include "modules/audio_device/include/audio_device.h" +#include "modules/audio_device/include/audio_device_default.h" namespace webrtc { -class FakeAudioDeviceModule : public AudioDeviceModule { +class FakeAudioDeviceModule + : public webrtc_impl::AudioDeviceModuleDefault { public: - FakeAudioDeviceModule() {} - virtual ~FakeAudioDeviceModule() {} - // TODO(nisse): Fix all users of this class to managed references using // scoped_refptr. Current code doesn't always use refcounting for this class. void AddRef() const override {} rtc::RefCountReleaseStatus Release() const override { return rtc::RefCountReleaseStatus::kDroppedLastRef; } - - private: - int32_t RegisterAudioCallback(AudioTransport* audioCallback) override { - return 0; - } - int32_t Init() override { return 0; } - int32_t InitSpeaker() override { return 0; } - int32_t SetPlayoutDevice(uint16_t index) override { return 0; } - int32_t SetPlayoutDevice(WindowsDeviceType device) override { return 0; } - int32_t SetStereoPlayout(bool enable) override { return 0; } - int32_t StopPlayout() override { return 0; } - int32_t InitMicrophone() override { return 0; } - int32_t SetRecordingDevice(uint16_t index) override { return 0; } - int32_t SetRecordingDevice(WindowsDeviceType device) override { return 0; } - int32_t SetStereoRecording(bool enable) override { return 0; } - int32_t StopRecording() override { return 0; } - - int32_t Terminate() override { return 0; } - - int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override { return 0; } - bool Initialized() const override { return true; } - int16_t PlayoutDevices() override { return 0; } - int16_t RecordingDevices() override { return 0; } - int32_t PlayoutDeviceName(uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]) override { - return 0; - } - int32_t RecordingDeviceName(uint16_t index, - char name[kAdmMaxDeviceNameSize], - char guid[kAdmMaxGuidSize]) override { - return 0; - } - int32_t PlayoutIsAvailable(bool* available) override { return 0; } - int32_t InitPlayout() override { return 0; } - bool PlayoutIsInitialized() const override { return true; } - int32_t RecordingIsAvailable(bool* available) override { return 0; } - int32_t InitRecording() override { return 0; } - bool RecordingIsInitialized() const override { return true; } - int32_t StartPlayout() override { return 0; } - bool Playing() const override { return false; } - int32_t StartRecording() override { return 0; } - bool Recording() const override { return false; } - bool SpeakerIsInitialized() const override { return true; } - bool MicrophoneIsInitialized() const override { return true; } - int32_t SpeakerVolumeIsAvailable(bool* available) override { return 0; } - int32_t SetSpeakerVolume(uint32_t volume) override { return 0; } - int32_t SpeakerVolume(uint32_t* volume) const override { return 0; } - int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override { return 0; } - int32_t MinSpeakerVolume(uint32_t* minVolume) const override { return 0; } - int32_t MicrophoneVolumeIsAvailable(bool* available) override { return 0; } - int32_t SetMicrophoneVolume(uint32_t volume) override { return 0; } - int32_t MicrophoneVolume(uint32_t* volume) const override { return 0; } - int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override { return 0; } - int32_t MinMicrophoneVolume(uint32_t* minVolume) const override { return 0; } - int32_t SpeakerMuteIsAvailable(bool* available) override { return 0; } - int32_t SetSpeakerMute(bool enable) override { return 0; } - int32_t SpeakerMute(bool* enabled) const override { return 0; } - int32_t MicrophoneMuteIsAvailable(bool* available) override { return 0; } - int32_t SetMicrophoneMute(bool enable) override { return 0; } - int32_t MicrophoneMute(bool* enabled) const override { return 0; } - int32_t StereoPlayoutIsAvailable(bool* available) const override { - *available = false; - return 0; - } - int32_t StereoPlayout(bool* enabled) const override { return 0; } - int32_t StereoRecordingIsAvailable(bool* available) const override { - *available = false; - return 0; - } - int32_t StereoRecording(bool* enabled) const override { return 0; } - int32_t PlayoutDelay(uint16_t* delayMS) const override { - *delayMS = 0; - return 0; - } - bool BuiltInAECIsAvailable() const override { return false; } - int32_t EnableBuiltInAEC(bool enable) override { return -1; } - bool BuiltInAGCIsAvailable() const override { return false; } - int32_t EnableBuiltInAGC(bool enable) override { return -1; } - bool BuiltInNSIsAvailable() const override { return false; } - int32_t EnableBuiltInNS(bool enable) override { return -1; } - -#if defined(WEBRTC_IOS) - int GetPlayoutAudioParameters(AudioParameters* params) const override { - return -1; - } - int GetRecordAudioParameters(AudioParameters* params) const override { - return -1; - } -#endif // WEBRTC_IOS }; } // namespace webrtc diff --git a/modules/audio_device/include/test_audio_device.h b/modules/audio_device/include/test_audio_device.h new file mode 100644 index 0000000000..08060396db --- /dev/null +++ b/modules/audio_device/include/test_audio_device.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018 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 MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_ +#define MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_ + +#include +#include +#include + +#include "modules/audio_device/include/audio_device.h" +#include "rtc_base/buffer.h" +#include "rtc_base/event.h" +#include "typedefs.h" // NOLINT(build/include) + +namespace webrtc { + +// TestAudioDeviceModule implements an AudioDevice module that can act both as a +// capturer and a renderer. It will use 10ms audio frames. +class TestAudioDeviceModule : public AudioDeviceModule { + public: + // Returns the number of samples that Capturers and Renderers with this + // sampling frequency will work with every time Capture or Render is called. + static size_t SamplesPerFrame(int sampling_frequency_in_hz); + + class Capturer { + public: + virtual ~Capturer() {} + // Returns the sampling frequency in Hz of the audio data that this + // capturer produces. + virtual int SamplingFrequency() const = 0; + // Replaces the contents of |buffer| with 10ms of captured audio data + // (see TestAudioDeviceModule::SamplesPerFrame). Returns true if the + // capturer can keep producing data, or false when the capture finishes. + virtual bool Capture(rtc::BufferT* buffer) = 0; + }; + + class Renderer { + public: + virtual ~Renderer() {} + // Returns the sampling frequency in Hz of the audio data that this + // renderer receives. + virtual int SamplingFrequency() const = 0; + // Renders the passed audio data and returns true if the renderer wants + // to keep receiving data, or false otherwise. + virtual bool Render(rtc::ArrayView data) = 0; + }; + + // A fake capturer that generates pulses with random samples between + // -max_amplitude and +max_amplitude. + class PulsedNoiseCapturer : public Capturer { + public: + virtual ~PulsedNoiseCapturer() {} + + virtual void SetMaxAmplitude(int16_t amplitude) = 0; + }; + + virtual ~TestAudioDeviceModule() {} + + // Creates a new TestAudioDeviceModule. When capturing or playing, 10 ms audio + // frames will be processed every 10ms / |speed|. + // |capturer| is an object that produces audio data. Can be nullptr if this + // device is never used for recording. + // |renderer| is an object that receives audio data that would have been + // played out. Can be nullptr if this device is never used for playing. + // Use one of the Create... functions to get these instances. + static rtc::scoped_refptr CreateTestAudioDeviceModule( + std::unique_ptr capturer, + std::unique_ptr renderer, + float speed = 1); + + // Returns a Capturer instance that generates a signal where every second + // frame is zero and every second frame is evenly distributed random noise + // with max amplitude |max_amplitude|. + static std::unique_ptr CreatePulsedNoiseCapturer( + int16_t max_amplitude, + int sampling_frequency_in_hz); + + // Returns a Capturer instance that gets its data from a file. + static std::unique_ptr CreateWavFileReader( + std::string filename, + int sampling_frequency_in_hz); + + // Returns a Capturer instance that gets its data from a file. + // Automatically detects sample rate. + 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); + + // 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( + std::string filename, + 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); + + virtual int32_t Init() = 0; + virtual int32_t RegisterAudioCallback(AudioTransport* callback) = 0; + + virtual int32_t StartPlayout() = 0; + virtual int32_t StopPlayout() = 0; + virtual int32_t StartRecording() = 0; + virtual int32_t StopRecording() = 0; + + virtual bool Playing() const = 0; + virtual bool Recording() const = 0; + + // Blocks until the Renderer refuses to receive data. + // Returns false if |timeout_ms| passes before that happens. + virtual bool WaitForPlayoutEnd(int timeout_ms = rtc::Event::kForever) = 0; + // Blocks until the Recorder stops producing data. + // Returns false if |timeout_ms| passes before that happens. + virtual bool WaitForRecordingEnd(int timeout_ms = rtc::Event::kForever) = 0; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_H_ diff --git a/test/fake_audio_device.cc b/modules/audio_device/include/test_audio_device_impl.cc similarity index 50% rename from test/fake_audio_device.cc rename to modules/audio_device/include/test_audio_device_impl.cc index 8e640366cf..d4f1ab6d6e 100644 --- a/test/fake_audio_device.cc +++ b/modules/audio_device/include/test_audio_device_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * Copyright (c) 2018 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 @@ -7,239 +7,45 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ - -#include "test/fake_audio_device.h" +#include "modules/audio_device/include/test_audio_device_impl.h" #include +#include +#include #include +#include +#include "api/array_view.h" #include "common_audio/wav_file.h" +#include "modules/audio_device/include/audio_device_default.h" +#include "modules/audio_device/include/test_audio_device.h" +#include "rtc_base/buffer.h" #include "rtc_base/checks.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" +#include "rtc_base/random.h" +#include "rtc_base/refcountedobject.h" #include "system_wrappers/include/event_wrapper.h" +#include "typedefs.h" // NOLINT(build/include) namespace webrtc { -namespace { +class EventTimerWrapper; + +// todo(titovartem): use anonymous namespace here after downstream projects +// won't use test/FakeAudioDevice +namespace webrtc_impl { constexpr int kFrameLengthMs = 10; constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; -class WavFileReader final : public test::FakeAudioDevice::Capturer { - public: - WavFileReader(std::string filename, int sampling_frequency_in_hz) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - wav_reader_(filename) { - RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); - RTC_CHECK_EQ(wav_reader_.num_channels(), 1); - } - - int SamplingFrequency() const override { - return sampling_frequency_in_hz_; - } - - bool Capture(rtc::BufferT* buffer) override { - buffer->SetData( - test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), - [&](rtc::ArrayView data) { - return wav_reader_.ReadSamples(data.size(), data.data()); - }); - return buffer->size() > 0; - } - - private: - int sampling_frequency_in_hz_; - WavReader wav_reader_; -}; - -class WavFileWriter final : public test::FakeAudioDevice::Renderer { - public: - WavFileWriter(std::string filename, int sampling_frequency_in_hz) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - wav_writer_(filename, sampling_frequency_in_hz, 1) {} - - int SamplingFrequency() const override { - return sampling_frequency_in_hz_; - } - - bool Render(rtc::ArrayView data) override { - wav_writer_.WriteSamples(data.data(), data.size()); - return true; - } - - private: - int sampling_frequency_in_hz_; - WavWriter wav_writer_; -}; - -class BoundedWavFileWriter : public test::FakeAudioDevice::Renderer { - public: - BoundedWavFileWriter(std::string filename, int sampling_frequency_in_hz) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - wav_writer_(filename, sampling_frequency_in_hz, 1), - silent_audio_(test::FakeAudioDevice::SamplesPerFrame( - sampling_frequency_in_hz), 0), - started_writing_(false), - trailing_zeros_(0) {} - - int SamplingFrequency() const override { - return sampling_frequency_in_hz_; - } - - bool Render(rtc::ArrayView data) override { - const int16_t kAmplitudeThreshold = 5; - - const int16_t* begin = data.begin(); - const int16_t* end = data.end(); - if (!started_writing_) { - // Cut off silence at the beginning. - while (begin < end) { - if (std::abs(*begin) > kAmplitudeThreshold) { - started_writing_ = true; - break; - } - ++begin; - } - } - if (started_writing_) { - // Cut off silence at the end. - while (begin < end) { - if (*(end - 1) != 0) { - break; - } - --end; - } - if (begin < end) { - // If it turns out that the silence was not final, need to write all the - // skipped zeros and continue writing audio. - while (trailing_zeros_ > 0) { - const size_t zeros_to_write = std::min(trailing_zeros_, - silent_audio_.size()); - wav_writer_.WriteSamples(silent_audio_.data(), zeros_to_write); - trailing_zeros_ -= zeros_to_write; - } - wav_writer_.WriteSamples(begin, end - begin); - } - // Save the number of zeros we skipped in case this needs to be restored. - trailing_zeros_ += data.end() - end; - } - return true; - } - - private: - int sampling_frequency_in_hz_; - WavWriter wav_writer_; - std::vector silent_audio_; - bool started_writing_; - size_t trailing_zeros_; -}; - - -class DiscardRenderer final : public test::FakeAudioDevice::Renderer { - public: - explicit DiscardRenderer(int sampling_frequency_in_hz) - : sampling_frequency_in_hz_(sampling_frequency_in_hz) {} - - int SamplingFrequency() const override { - return sampling_frequency_in_hz_; - } - - bool Render(rtc::ArrayView data) override { - return true; - } - - private: - int sampling_frequency_in_hz_; -}; - -} // namespace -namespace test { - -// Assuming 10ms audio packets. -FakeAudioDevice::PulsedNoiseCapturer::PulsedNoiseCapturer( - int16_t max_amplitude, - int sampling_frequency_in_hz) - : sampling_frequency_in_hz_(sampling_frequency_in_hz), - fill_with_zero_(false), - random_generator_(1), - max_amplitude_(max_amplitude) { - RTC_DCHECK_GT(max_amplitude, 0); -} - -bool FakeAudioDevice::PulsedNoiseCapturer::Capture( - rtc::BufferT* buffer) { - fill_with_zero_ = !fill_with_zero_; - int16_t max_amplitude; - { - rtc::CritScope cs(&lock_); - max_amplitude = max_amplitude_; - } - buffer->SetData(FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), - [&](rtc::ArrayView data) { - if (fill_with_zero_) { - std::fill(data.begin(), data.end(), 0); - } else { - std::generate(data.begin(), data.end(), [&]() { - return random_generator_.Rand(-max_amplitude, - max_amplitude); - }); - } - return data.size(); - }); - return true; -} - -void FakeAudioDevice::PulsedNoiseCapturer::SetMaxAmplitude(int16_t amplitude) { - rtc::CritScope cs(&lock_); - max_amplitude_ = amplitude; -} - -size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) { - return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond); -} - -std::unique_ptr -FakeAudioDevice::CreatePulsedNoiseCapturer(int16_t max_amplitude, - int sampling_frequency_in_hz) { - return std::unique_ptr( - new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz)); -} - -std::unique_ptr FakeAudioDevice::CreateWavFileReader( - std::string filename, int sampling_frequency_in_hz) { - return std::unique_ptr( - new WavFileReader(filename, sampling_frequency_in_hz)); -} - -std::unique_ptr FakeAudioDevice::CreateWavFileReader( - std::string filename) { - int sampling_frequency_in_hz = WavReader(filename).sample_rate(); - return std::unique_ptr( - new WavFileReader(filename, sampling_frequency_in_hz)); -} - -std::unique_ptr FakeAudioDevice::CreateWavFileWriter( - std::string filename, int sampling_frequency_in_hz) { - return std::unique_ptr( - new WavFileWriter(filename, sampling_frequency_in_hz)); -} - -std::unique_ptr - FakeAudioDevice::CreateBoundedWavFileWriter( - std::string filename, int sampling_frequency_in_hz) { - return std::unique_ptr( - new BoundedWavFileWriter(filename, sampling_frequency_in_hz)); -} - -std::unique_ptr - FakeAudioDevice::CreateDiscardRenderer(int sampling_frequency_in_hz) { - return std::unique_ptr( - new DiscardRenderer(sampling_frequency_in_hz)); -} - - -FakeAudioDevice::FakeAudioDevice(std::unique_ptr capturer, - std::unique_ptr renderer, - float speed) +// TestAudioDeviceModule implements an AudioDevice module that can act both as a +// capturer and a renderer. It will use 10ms audio frames. +TestAudioDeviceModuleImpl::TestAudioDeviceModuleImpl( + std::unique_ptr capturer, + std::unique_ptr renderer, + float speed) : capturer_(std::move(capturer)), renderer_(std::move(renderer)), speed_(speed), @@ -249,10 +55,12 @@ FakeAudioDevice::FakeAudioDevice(std::unique_ptr capturer, done_rendering_(true, true), done_capturing_(true, true), tick_(EventTimerWrapper::Create()), - thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { + thread_(TestAudioDeviceModuleImpl::Run, + this, + "TestAudioDeviceModuleImpl") { auto good_sample_rate = [](int sr) { - return sr == 8000 || sr == 16000 || sr == 32000 - || sr == 44100 || sr == 48000; + return sr == 8000 || sr == 16000 || sr == 32000 || sr == 44100 || + sr == 48000; }; if (renderer_) { @@ -265,13 +73,28 @@ FakeAudioDevice::FakeAudioDevice(std::unique_ptr capturer, } } -FakeAudioDevice::~FakeAudioDevice() { +TestAudioDeviceModuleImpl::~TestAudioDeviceModuleImpl() { StopPlayout(); StopRecording(); thread_.Stop(); } -int32_t FakeAudioDevice::StartPlayout() { +int32_t TestAudioDeviceModuleImpl::Init() { + RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); + thread_.Start(); + thread_.SetPriority(rtc::kHighPriority); + return 0; +} + +int32_t TestAudioDeviceModuleImpl::RegisterAudioCallback( + AudioTransport* callback) { + rtc::CritScope cs(&lock_); + RTC_DCHECK(callback || audio_callback_); + audio_callback_ = callback; + return 0; +} + +int32_t TestAudioDeviceModuleImpl::StartPlayout() { rtc::CritScope cs(&lock_); RTC_CHECK(renderer_); rendering_ = true; @@ -279,14 +102,14 @@ int32_t FakeAudioDevice::StartPlayout() { return 0; } -int32_t FakeAudioDevice::StopPlayout() { +int32_t TestAudioDeviceModuleImpl::StopPlayout() { rtc::CritScope cs(&lock_); rendering_ = false; done_rendering_.Set(); return 0; } -int32_t FakeAudioDevice::StartRecording() { +int32_t TestAudioDeviceModuleImpl::StartRecording() { rtc::CritScope cs(&lock_); RTC_CHECK(capturer_); capturing_ = true; @@ -294,51 +117,35 @@ int32_t FakeAudioDevice::StartRecording() { return 0; } -int32_t FakeAudioDevice::StopRecording() { +int32_t TestAudioDeviceModuleImpl::StopRecording() { rtc::CritScope cs(&lock_); capturing_ = false; done_capturing_.Set(); return 0; } -int32_t FakeAudioDevice::Init() { - RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); - thread_.Start(); - thread_.SetPriority(rtc::kHighPriority); - return 0; -} - -int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { - rtc::CritScope cs(&lock_); - RTC_DCHECK(callback || audio_callback_); - audio_callback_ = callback; - return 0; -} - -bool FakeAudioDevice::Playing() const { +bool TestAudioDeviceModuleImpl::Playing() const { rtc::CritScope cs(&lock_); return rendering_; } -bool FakeAudioDevice::Recording() const { +bool TestAudioDeviceModuleImpl::Recording() const { rtc::CritScope cs(&lock_); return capturing_; } -bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) { +// Blocks until the Renderer refuses to receive data. +// Returns false if |timeout_ms| passes before that happens. +bool TestAudioDeviceModuleImpl::WaitForPlayoutEnd(int timeout_ms) { return done_rendering_.Wait(timeout_ms); } - -bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) { +// Blocks until the Recorder stops producing data. +// Returns false if |timeout_ms| passes before that happens. +bool TestAudioDeviceModuleImpl::WaitForRecordingEnd(int timeout_ms) { return done_capturing_.Wait(timeout_ms); } -bool FakeAudioDevice::Run(void* obj) { - static_cast(obj)->ProcessAudio(); - return true; -} - -void FakeAudioDevice::ProcessAudio() { +void TestAudioDeviceModuleImpl::ProcessAudio() { { rtc::CritScope cs(&lock_); if (capturing_) { @@ -374,6 +181,238 @@ void FakeAudioDevice::ProcessAudio() { tick_->Wait(WEBRTC_EVENT_INFINITE); } +bool TestAudioDeviceModuleImpl::Run(void* obj) { + static_cast(obj)->ProcessAudio(); + return true; +} + +} // namespace webrtc_impl + +namespace { +// A fake capturer that generates pulses with random samples between +// -max_amplitude and +max_amplitude. +class PulsedNoiseCapturerImpl final + : public TestAudioDeviceModule::PulsedNoiseCapturer { + public: + // Assuming 10ms audio packets. + PulsedNoiseCapturerImpl(int16_t max_amplitude, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + fill_with_zero_(false), + random_generator_(1), + max_amplitude_(max_amplitude) { + RTC_DCHECK_GT(max_amplitude, 0); + } + + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } + + bool Capture(rtc::BufferT* buffer) override { + fill_with_zero_ = !fill_with_zero_; + int16_t max_amplitude; + { + rtc::CritScope cs(&lock_); + max_amplitude = max_amplitude_; + } + buffer->SetData( + TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz_), + [&](rtc::ArrayView data) { + if (fill_with_zero_) { + std::fill(data.begin(), data.end(), 0); + } else { + std::generate(data.begin(), data.end(), [&]() { + return random_generator_.Rand(-max_amplitude, max_amplitude); + }); + } + return data.size(); + }); + return true; + } + + void SetMaxAmplitude(int16_t amplitude) override { + rtc::CritScope cs(&lock_); + max_amplitude_ = amplitude; + } + + private: + int sampling_frequency_in_hz_; + bool fill_with_zero_; + Random random_generator_; + rtc::CriticalSection lock_; + int16_t max_amplitude_ RTC_GUARDED_BY(lock_); +}; + +class WavFileReader final : public TestAudioDeviceModule::Capturer { + public: + WavFileReader(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_reader_(filename) { + RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); + RTC_CHECK_EQ(wav_reader_.num_channels(), 1); + } + + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } + + bool Capture(rtc::BufferT* buffer) override { + buffer->SetData( + TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz_), + [&](rtc::ArrayView data) { + return wav_reader_.ReadSamples(data.size(), data.data()); + }); + return buffer->size() > 0; + } + + private: + int sampling_frequency_in_hz_; + WavReader wav_reader_; +}; + +class WavFileWriter final : public TestAudioDeviceModule::Renderer { + public: + WavFileWriter(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(filename, sampling_frequency_in_hz, 1) {} + + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } + + bool Render(rtc::ArrayView data) override { + wav_writer_.WriteSamples(data.data(), data.size()); + return true; + } + + private: + int sampling_frequency_in_hz_; + WavWriter wav_writer_; +}; + +class BoundedWavFileWriter : public TestAudioDeviceModule::Renderer { + public: + BoundedWavFileWriter(std::string filename, int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz), + wav_writer_(filename, sampling_frequency_in_hz, 1), + silent_audio_( + TestAudioDeviceModule::SamplesPerFrame(sampling_frequency_in_hz), + 0), + started_writing_(false), + trailing_zeros_(0) {} + + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } + + bool Render(rtc::ArrayView data) override { + const int16_t kAmplitudeThreshold = 5; + + const int16_t* begin = data.begin(); + const int16_t* end = data.end(); + if (!started_writing_) { + // Cut off silence at the beginning. + while (begin < end) { + if (std::abs(*begin) > kAmplitudeThreshold) { + started_writing_ = true; + break; + } + ++begin; + } + } + if (started_writing_) { + // Cut off silence at the end. + while (begin < end) { + if (*(end - 1) != 0) { + break; + } + --end; + } + if (begin < end) { + // If it turns out that the silence was not final, need to write all the + // skipped zeros and continue writing audio. + while (trailing_zeros_ > 0) { + const size_t zeros_to_write = + std::min(trailing_zeros_, silent_audio_.size()); + wav_writer_.WriteSamples(silent_audio_.data(), zeros_to_write); + trailing_zeros_ -= zeros_to_write; + } + wav_writer_.WriteSamples(begin, end - begin); + } + // Save the number of zeros we skipped in case this needs to be restored. + trailing_zeros_ += data.end() - end; + } + return true; + } + + private: + int sampling_frequency_in_hz_; + WavWriter wav_writer_; + std::vector silent_audio_; + bool started_writing_; + size_t trailing_zeros_; +}; + +class DiscardRenderer final : public TestAudioDeviceModule::Renderer { + public: + explicit DiscardRenderer(int sampling_frequency_in_hz) + : sampling_frequency_in_hz_(sampling_frequency_in_hz) {} + + int SamplingFrequency() const override { return sampling_frequency_in_hz_; } + + bool Render(rtc::ArrayView data) override { return true; } + + private: + int sampling_frequency_in_hz_; +}; + +} // namespace + +size_t TestAudioDeviceModule::SamplesPerFrame(int sampling_frequency_in_hz) { + return rtc::CheckedDivExact(sampling_frequency_in_hz, + webrtc_impl::kFramesPerSecond); +} + +rtc::scoped_refptr +TestAudioDeviceModule::CreateTestAudioDeviceModule( + std::unique_ptr capturer, + std::unique_ptr renderer, + float speed) { + return new rtc::RefCountedObject( + std::move(capturer), std::move(renderer), speed); +} + +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)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateWavFileReader(std::string filename, + int sampling_frequency_in_hz) { + return std::unique_ptr( + new WavFileReader(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateWavFileReader(std::string filename) { + int sampling_frequency_in_hz = WavReader(filename).sample_rate(); + return std::unique_ptr( + new WavFileReader(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateWavFileWriter(std::string filename, + int sampling_frequency_in_hz) { + return std::unique_ptr( + new WavFileWriter(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateBoundedWavFileWriter( + std::string filename, + int sampling_frequency_in_hz) { + return std::unique_ptr( + new BoundedWavFileWriter(filename, sampling_frequency_in_hz)); +} + +std::unique_ptr +TestAudioDeviceModule::CreateDiscardRenderer(int sampling_frequency_in_hz) { + return std::unique_ptr( + new DiscardRenderer(sampling_frequency_in_hz)); +} -} // namespace test } // namespace webrtc diff --git a/modules/audio_device/include/test_audio_device_impl.h b/modules/audio_device/include/test_audio_device_impl.h new file mode 100644 index 0000000000..f570073151 --- /dev/null +++ b/modules/audio_device/include/test_audio_device_impl.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018 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 MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_IMPL_H_ +#define MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_IMPL_H_ + +#include +#include +#include + +#include "modules/audio_device/include/audio_device_default.h" +#include "modules/audio_device/include/test_audio_device.h" +#include "rtc_base/buffer.h" +#include "rtc_base/criticalsection.h" +#include "rtc_base/event.h" +#include "rtc_base/platform_thread.h" + +namespace webrtc { + +class EventTimerWrapper; + +namespace webrtc_impl { + +// TestAudioDeviceModule implements an AudioDevice module that can act both as a +// capturer and a renderer. It will use 10ms audio frames. +// todo(titovartem): hide implementation after downstream projects won't use +// test/FakeAudioDevice +class TestAudioDeviceModuleImpl + : public AudioDeviceModuleDefault { + public: + // Creates a new TestAudioDeviceModule. When capturing or playing, 10 ms audio + // frames will be processed every 10ms / |speed|. + // |capturer| is an object that produces audio data. Can be nullptr if this + // device is never used for recording. + // |renderer| is an object that receives audio data that would have been + // played out. Can be nullptr if this device is never used for playing. + // Use one of the Create... functions to get these instances. + TestAudioDeviceModuleImpl(std::unique_ptr capturer, + std::unique_ptr renderer, + float speed = 1); + + ~TestAudioDeviceModuleImpl() override; + + int32_t Init() override; + int32_t RegisterAudioCallback(AudioTransport* callback) override; + int32_t StartPlayout() override; + int32_t StopPlayout() override; + int32_t StartRecording() override; + int32_t StopRecording() override; + bool Playing() const override; + bool Recording() const override; + + // Blocks until the Renderer refuses to receive data. + // Returns false if |timeout_ms| passes before that happens. + bool WaitForPlayoutEnd(int timeout_ms = rtc::Event::kForever) override; + // Blocks until the Recorder stops producing data. + // Returns false if |timeout_ms| passes before that happens. + bool WaitForRecordingEnd(int timeout_ms = rtc::Event::kForever) override; + + private: + void ProcessAudio(); + static bool Run(void* obj); + + const std::unique_ptr capturer_ RTC_GUARDED_BY(lock_); + const std::unique_ptr renderer_ RTC_GUARDED_BY(lock_); + const float speed_; + + rtc::CriticalSection lock_; + AudioTransport* audio_callback_ RTC_GUARDED_BY(lock_); + bool rendering_ RTC_GUARDED_BY(lock_); + bool capturing_ RTC_GUARDED_BY(lock_); + rtc::Event done_rendering_; + rtc::Event done_capturing_; + + std::vector playout_buffer_ RTC_GUARDED_BY(lock_); + rtc::BufferT recording_buffer_ RTC_GUARDED_BY(lock_); + + std::unique_ptr tick_; + rtc::PlatformThread thread_; +}; + +} // namespace webrtc_impl +} // namespace webrtc + +#endif // MODULES_AUDIO_DEVICE_INCLUDE_TEST_AUDIO_DEVICE_IMPL_H_ diff --git a/test/fake_audio_device_unittest.cc b/modules/audio_device/include/test_audio_device_impl_unittest.cc similarity index 79% rename from test/fake_audio_device_unittest.cc rename to modules/audio_device/include/test_audio_device_impl_unittest.cc index 1529deaa97..674df1ba7e 100644 --- a/test/fake_audio_device_unittest.cc +++ b/modules/audio_device/include/test_audio_device_impl_unittest.cc @@ -13,12 +13,11 @@ #include "common_audio/wav_file.h" #include "common_audio/wav_header.h" -#include "test/fake_audio_device.h" +#include "modules/audio_device/include/test_audio_device.h" #include "test/gtest.h" #include "test/testsupport/fileutils.h" namespace webrtc { -namespace test { namespace { void RunTest(const std::vector& input_samples, @@ -28,15 +27,17 @@ void RunTest(const std::vector& input_samples, ::testing::UnitTest::GetInstance()->current_test_info(); const std::string output_filename = test::OutputPath() + - "BoundedWavFileWriterTest_" + test_info->name() + ".wav"; + "BoundedWavFileWriterTest_" + + test_info->name() + ".wav"; static const size_t kSamplesPerFrame = 8; static const int kSampleRate = kSamplesPerFrame * 100; - EXPECT_EQ(FakeAudioDevice::SamplesPerFrame(kSampleRate), kSamplesPerFrame); + EXPECT_EQ(TestAudioDeviceModule::SamplesPerFrame(kSampleRate), + kSamplesPerFrame); { - std::unique_ptr writer = - FakeAudioDevice::CreateBoundedWavFileWriter(output_filename, 800); + std::unique_ptr writer = + TestAudioDeviceModule::CreateBoundedWavFileWriter(output_filename, 800); for (size_t i = 0; i < input_samples.size(); i += kSamplesPerFrame) { EXPECT_TRUE(writer->Render(rtc::ArrayView( @@ -61,18 +62,15 @@ void RunTest(const std::vector& input_samples, TEST(BoundedWavFileWriterTest, NoSilence) { static const std::vector kInputSamples = { - 75, 1234, 243, -1231, -22222, 0, 3, 88, - 1222, -1213, -13222, -7, -3525, 5787, -25247, 8 - }; + 75, 1234, 243, -1231, -22222, 0, 3, 88, + 1222, -1213, -13222, -7, -3525, 5787, -25247, 8}; static const std::vector kExpectedSamples = kInputSamples; RunTest(kInputSamples, kExpectedSamples, 8); } TEST(BoundedWavFileWriterTest, SomeStartSilence) { static const std::vector kInputSamples = { - 0, 0, 0, 0, 3, 0, 0, 0, - 0, 3, -13222, -7, -3525, 5787, -25247, 8 - }; + 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()); RunTest(kInputSamples, kExpectedSamples, 8); @@ -80,9 +78,7 @@ TEST(BoundedWavFileWriterTest, SomeStartSilence) { TEST(BoundedWavFileWriterTest, NegativeStartSilence) { static const std::vector kInputSamples = { - 0, -4, -6, 0, 3, 0, 0, 0, - 0, 3, -13222, -7, -3525, 5787, -25247, 8 - }; + 0, -4, -6, 0, 3, 0, 0, 0, 0, 3, -13222, -7, -3525, 5787, -25247, 8}; static const std::vector kExpectedSamples(kInputSamples.begin() + 2, kInputSamples.end()); RunTest(kInputSamples, kExpectedSamples, 8); @@ -90,9 +86,7 @@ TEST(BoundedWavFileWriterTest, NegativeStartSilence) { TEST(BoundedWavFileWriterTest, SomeEndSilence) { static const std::vector kInputSamples = { - 75, 1234, 243, -1231, -22222, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }; + 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const std::vector kExpectedSamples(kInputSamples.begin(), kInputSamples.end() - 9); RunTest(kInputSamples, kExpectedSamples, 8); @@ -100,18 +94,16 @@ TEST(BoundedWavFileWriterTest, SomeEndSilence) { TEST(BoundedWavFileWriterTest, DoubleEndSilence) { static const std::vector kInputSamples = { - 75, 1234, 243, -1231, -22222, 0, 0, 0, - 0, -1213, -13222, -7, -3525, 5787, 0, 0 - }; + 75, 1234, 243, -1231, -22222, 0, 0, 0, + 0, -1213, -13222, -7, -3525, 5787, 0, 0}; static const std::vector kExpectedSamples(kInputSamples.begin(), kInputSamples.end() - 2); RunTest(kInputSamples, kExpectedSamples, 8); } TEST(BoundedWavFileWriterTest, DoubleSilence) { - static const std::vector kInputSamples = { - 0, -1213, -13222, -7, -3525, 5787, 0, 0 - }; + static const std::vector kInputSamples = {0, -1213, -13222, -7, + -3525, 5787, 0, 0}; static const std::vector kExpectedSamples(kInputSamples.begin() + 1, kInputSamples.end() - 2); RunTest(kInputSamples, kExpectedSamples, 8); @@ -119,9 +111,7 @@ TEST(BoundedWavFileWriterTest, DoubleSilence) { TEST(BoundedWavFileWriterTest, EndSilenceCutoff) { static const std::vector kInputSamples = { - 75, 1234, 243, -1231, -22222, 0, 1, 0, - 0, 0, 0 - }; + 75, 1234, 243, -1231, -22222, 0, 1, 0, 0, 0, 0}; static const std::vector kExpectedSamples(kInputSamples.begin(), kInputSamples.end() - 4); RunTest(kInputSamples, kExpectedSamples, 8); @@ -129,8 +119,8 @@ TEST(BoundedWavFileWriterTest, EndSilenceCutoff) { TEST(PulsedNoiseCapturerTest, SetMaxAmplitude) { const int16_t kAmplitude = 50; - std::unique_ptr capturer = - FakeAudioDevice::CreatePulsedNoiseCapturer( + std::unique_ptr capturer = + TestAudioDeviceModule::CreatePulsedNoiseCapturer( kAmplitude, /*sampling_frequency_in_hz=*/8000); rtc::BufferT recording_buffer; @@ -153,5 +143,4 @@ TEST(PulsedNoiseCapturerTest, SetMaxAmplitude) { EXPECT_GT(max_sample, kAmplitude); } -} // namespace test } // namespace webrtc diff --git a/test/BUILD.gn b/test/BUILD.gn index f021c141c3..fcde65f40b 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -338,7 +338,6 @@ if (rtc_include_tests) { "../system_wrappers", ] sources = [ - "fake_audio_device_unittest.cc", "fake_network_pipe_unittest.cc", "frame_generator_unittest.cc", "rtp_file_reader_unittest.cc", @@ -533,7 +532,6 @@ rtc_source_set("fake_audio_device") { visibility = [ "*" ] testonly = true sources = [ - "fake_audio_device.cc", "fake_audio_device.h", ] if (!build_with_chromium && is_clang) { @@ -545,7 +543,7 @@ rtc_source_set("fake_audio_device") { "../:typedefs", "../api:array_view", "../common_audio:common_audio", - "../modules/audio_device:audio_device", + "../modules/audio_device", "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../system_wrappers", diff --git a/test/fake_audio_device.h b/test/fake_audio_device.h index 0cc44f0c8d..b8b2ff9388 100644 --- a/test/fake_audio_device.h +++ b/test/fake_audio_device.h @@ -10,156 +10,16 @@ #ifndef TEST_FAKE_AUDIO_DEVICE_H_ #define TEST_FAKE_AUDIO_DEVICE_H_ -#include -#include -#include - -#include "api/array_view.h" -#include "modules/audio_device/include/fake_audio_device.h" -#include "rtc_base/buffer.h" -#include "rtc_base/criticalsection.h" -#include "rtc_base/event.h" -#include "rtc_base/platform_thread.h" -#include "rtc_base/random.h" -#include "typedefs.h" // NOLINT(build/include) +#include "modules/audio_device/include/test_audio_device_impl.h" namespace webrtc { -class EventTimerWrapper; - namespace test { -// FakeAudioDevice implements an AudioDevice module that can act both as a -// capturer and a renderer. It will use 10ms audio frames. -class FakeAudioDevice : public FakeAudioDeviceModule { - public: - // Returns the number of samples that Capturers and Renderers with this - // sampling frequency will work with every time Capture or Render is called. - static size_t SamplesPerFrame(int sampling_frequency_in_hz); +// This class is deprecated. Use webrtc::TestAudioDevice from +// modules/audio_device/include/test_audio_device.h instead. +using FakeAudioDevice = webrtc::webrtc_impl::TestAudioDeviceModuleImpl; - class Capturer { - public: - virtual ~Capturer() {} - // Returns the sampling frequency in Hz of the audio data that this - // capturer produces. - virtual int SamplingFrequency() const = 0; - // Replaces the contents of |buffer| with 10ms of captured audio data - // (see FakeAudioDevice::SamplesPerFrame). Returns true if the capturer can - // keep producing data, or false when the capture finishes. - virtual bool Capture(rtc::BufferT* buffer) = 0; - }; - - class Renderer { - public: - virtual ~Renderer() {} - // Returns the sampling frequency in Hz of the audio data that this - // renderer receives. - virtual int SamplingFrequency() const = 0; - // Renders the passed audio data and returns true if the renderer wants - // to keep receiving data, or false otherwise. - virtual bool Render(rtc::ArrayView data) = 0; - }; - - // A fake capturer that generates pulses with random samples between - // -max_amplitude and +max_amplitude. - class PulsedNoiseCapturer final : public Capturer { - public: - PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz); - - int SamplingFrequency() const override { return sampling_frequency_in_hz_; } - - bool Capture(rtc::BufferT* buffer) override; - - void SetMaxAmplitude(int16_t amplitude); - - private: - int sampling_frequency_in_hz_; - bool fill_with_zero_; - Random random_generator_; - rtc::CriticalSection lock_; - int16_t max_amplitude_ RTC_GUARDED_BY(lock_); - }; - - // Creates a new FakeAudioDevice. When capturing or playing, 10 ms audio - // frames will be processed every 10ms / |speed|. - // |capturer| is an object that produces audio data. Can be nullptr if this - // device is never used for recording. - // |renderer| is an object that receives audio data that would have been - // played out. Can be nullptr if this device is never used for playing. - // Use one of the Create... functions to get these instances. - FakeAudioDevice(std::unique_ptr capturer, - std::unique_ptr renderer, - float speed = 1); - ~FakeAudioDevice() override; - - // Returns a Capturer instance that generates a signal where every second - // frame is zero and every second frame is evenly distributed random noise - // with max amplitude |max_amplitude|. - static std::unique_ptr CreatePulsedNoiseCapturer( - int16_t max_amplitude, - int sampling_frequency_in_hz); - - // Returns a Capturer instance that gets its data from a file. - static std::unique_ptr CreateWavFileReader( - std::string filename, int sampling_frequency_in_hz); - - // Returns a Capturer instance that gets its data from a file. - // Automatically detects sample rate. - 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); - - // 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( - std::string filename, 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); - - int32_t Init() override; - int32_t RegisterAudioCallback(AudioTransport* callback) override; - - int32_t StartPlayout() override; - int32_t StopPlayout() override; - int32_t StartRecording() override; - int32_t StopRecording() override; - - bool Playing() const override; - bool Recording() const override; - - // Blocks until the Renderer refuses to receive data. - // Returns false if |timeout_ms| passes before that happens. - bool WaitForPlayoutEnd(int timeout_ms = rtc::Event::kForever); - // Blocks until the Recorder stops producing data. - // Returns false if |timeout_ms| passes before that happens. - bool WaitForRecordingEnd(int timeout_ms = rtc::Event::kForever); - - private: - static bool Run(void* obj); - void ProcessAudio(); - - const std::unique_ptr capturer_ RTC_GUARDED_BY(lock_); - const std::unique_ptr renderer_ RTC_GUARDED_BY(lock_); - const float speed_; - - rtc::CriticalSection lock_; - AudioTransport* audio_callback_ RTC_GUARDED_BY(lock_); - bool rendering_ RTC_GUARDED_BY(lock_); - bool capturing_ RTC_GUARDED_BY(lock_); - rtc::Event done_rendering_; - rtc::Event done_capturing_; - - std::vector playout_buffer_ RTC_GUARDED_BY(lock_); - rtc::BufferT recording_buffer_ RTC_GUARDED_BY(lock_); - - std::unique_ptr tick_; - rtc::PlatformThread thread_; -}; } // namespace test } // namespace webrtc