Chromium Code Reviews| Index: webrtc/test/fake_audio_device.cc |
| diff --git a/webrtc/test/fake_audio_device.cc b/webrtc/test/fake_audio_device.cc |
| index 623ff518d7b0e9f3aba9e0e98e4d0505f77dbb3f..5e757125c84e99d9631cfa9788940bcdd25a18a5 100644 |
| --- a/webrtc/test/fake_audio_device.cc |
| +++ b/webrtc/test/fake_audio_device.cc |
| @@ -11,10 +11,11 @@ |
| #include "webrtc/test/fake_audio_device.h" |
| #include <algorithm> |
| +#include <utility> |
| -#include "webrtc/base/array_view.h" |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/random.h" |
| +#include "webrtc/common_audio/wav_file.h" |
| #include "webrtc/system_wrappers/include/event_wrapper.h" |
| namespace webrtc { |
| @@ -27,19 +28,30 @@ constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; |
| } // namespace |
|
kwiberg-webrtc
2017/03/09 10:04:10
The Capturers and Renderers should be in an anonym
oprypin_webrtc
2017/03/10 10:44:27
Done.
|
| namespace test { |
| +FakeAudioDevice::Streamer::Streamer(int sampling_frequency_in_hz) |
| + : sampling_frequency_in_hz_(sampling_frequency_in_hz), |
| + num_samples_per_frame_( |
| + rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond)) { |
| + RTC_CHECK( |
| + sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || |
| + sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || |
| + sampling_frequency_in_hz == 48000); |
| +} |
| + |
| // Assuming 10ms audio packets.. |
| -class FakeAudioDevice::PulsedNoiseCapturer { |
| +class FakeAudioDevice::PulsedNoiseCapturer : public FakeAudioDevice::Capturer { |
| public: |
| - PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude) |
| - : fill_with_zero_(false), |
| + PulsedNoiseCapturer(int sampling_frequency_in_hz, int16_t max_amplitude) |
| + : Capturer(sampling_frequency_in_hz), |
| + fill_with_zero_(false), |
| random_generator_(1), |
| max_amplitude_(max_amplitude), |
| - random_audio_(num_samples_per_frame), |
| - silent_audio_(num_samples_per_frame, 0) { |
| + random_audio_(SamplesPerFrame()), |
| + silent_audio_(SamplesPerFrame(), 0) { |
| RTC_DCHECK_GT(max_amplitude, 0); |
| } |
| - rtc::ArrayView<const int16_t> Capture() { |
| + rtc::ArrayView<const int16_t> Capture() override { |
| fill_with_zero_ = !fill_with_zero_; |
| if (!fill_with_zero_) { |
| std::generate(random_audio_.begin(), random_audio_.end(), [&]() { |
| @@ -57,27 +69,112 @@ class FakeAudioDevice::PulsedNoiseCapturer { |
| std::vector<int16_t> silent_audio_; |
| }; |
| -FakeAudioDevice::FakeAudioDevice(float speed, |
| - int sampling_frequency_in_hz, |
| - int16_t max_amplitude) |
| - : sampling_frequency_in_hz_(sampling_frequency_in_hz), |
| - num_samples_per_frame_( |
| - rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)), |
| +class FakeAudioDevice::WavFileReader : public FakeAudioDevice::Capturer { |
|
kwiberg-webrtc
2017/03/09 10:04:10
This class (and the other three) can be final.
oprypin_webrtc
2017/03/10 10:44:27
Done.
|
| + public: |
| + WavFileReader(std::string filename, int sampling_frequency_in_hz) |
| + : FakeAudioDevice::Capturer(sampling_frequency_in_hz), |
| + wav_reader_(filename), |
| + buffer_(SamplesPerFrame(), 0) { |
| + RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); |
| + RTC_CHECK_EQ(wav_reader_.num_channels(), 1); |
| + } |
| + |
| + rtc::ArrayView<const int16_t> Capture() override { |
| + const size_t samples_out = wav_reader_.ReadSamples(buffer_.size(), |
| + buffer_.data()); |
| + RTC_CHECK_LE(samples_out, buffer_.size()); |
| + return rtc::ArrayView<const int16_t>(buffer_.data(), samples_out); |
| + } |
| + |
| + private: |
| + WavReader wav_reader_; |
| + std::vector<int16_t> buffer_; |
| + // This event is set when the input audio file ends |
|
kwiberg-webrtc
2017/03/09 10:04:10
Orphaned comment.
oprypin_webrtc
2017/03/10 10:44:27
Done. Removed.
|
| +}; |
| + |
| +class FakeAudioDevice::WavFileWriter : public FakeAudioDevice::Renderer { |
| + public: |
| + WavFileWriter(std::string filename, int sampling_frequency_in_hz) |
| + : FakeAudioDevice::Renderer(sampling_frequency_in_hz), |
| + wav_writer_(filename, sampling_frequency_in_hz, 1) {} |
| + |
| + bool Render(rtc::ArrayView<const int16_t> data) { |
|
kwiberg-webrtc
2017/03/09 10:04:10
override?
oprypin_webrtc
2017/03/10 10:44:27
Done.
|
| + wav_writer_.WriteSamples(data.data(), data.size()); |
| + return true; |
| + } |
| + |
| + private: |
| + WavWriter wav_writer_; |
| +}; |
| + |
| +class FakeAudioDevice::Discarder : public FakeAudioDevice::Renderer { |
| + public: |
| + using Renderer::Renderer; |
| + |
| + bool Render(rtc::ArrayView<const int16_t> data) { |
| + return true; |
| + } |
| +}; |
| + |
| +std::unique_ptr<FakeAudioDevice::Capturer> |
| + FakeAudioDevice::CreatePulsedNoiseCapturer( |
| + int sampling_frequency_in_hz, int16_t max_amplitude) { |
| + return std::unique_ptr<FakeAudioDevice::Capturer>( |
| + new FakeAudioDevice::PulsedNoiseCapturer( |
| + sampling_frequency_in_hz, max_amplitude)); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( |
| + std::string filename, int sampling_frequency_in_hz) { |
| + return std::unique_ptr<FakeAudioDevice::Capturer>( |
| + new FakeAudioDevice::WavFileReader(filename, sampling_frequency_in_hz)); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( |
| + std::string filename) { |
| + int sampling_frequency_in_hz = WavReader(filename).sample_rate(); |
| + return std::unique_ptr<FakeAudioDevice::Capturer>( |
| + new FakeAudioDevice::WavFileReader(filename, sampling_frequency_in_hz)); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter( |
| + std::string filename, int sampling_frequency_in_hz) { |
| + return std::unique_ptr<FakeAudioDevice::Renderer>( |
| + new FakeAudioDevice::WavFileWriter(filename, sampling_frequency_in_hz)); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateDiscarder( |
| + int sampling_frequency_in_hz) { |
| + return std::unique_ptr<FakeAudioDevice::Renderer>( |
| + new FakeAudioDevice::Discarder(sampling_frequency_in_hz)); |
| +} |
| + |
| + |
| +FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer, |
| + std::unique_ptr<Renderer> renderer, |
| + float speed) |
| + : capturer_(std::move(capturer)), |
| + renderer_(std::move(renderer)), |
| speed_(speed), |
| audio_callback_(nullptr), |
| rendering_(false), |
| capturing_(false), |
| - capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_, |
| - max_amplitude)), |
| - playout_buffer_(num_samples_per_frame_, 0), |
| + done_rendering_(true, true), |
| + done_capturing_(true, true), |
| tick_(EventTimerWrapper::Create()), |
| thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { |
| - RTC_DCHECK( |
| - sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || |
| - sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || |
| - sampling_frequency_in_hz == 48000); |
| + if (renderer_) { |
| + playout_buffer_.resize(renderer_->SamplesPerFrame(), 0); |
| + } |
| } |
| +FakeAudioDevice::FakeAudioDevice(float speed, |
| + int sampling_frequency_in_hz, |
| + int16_t max_amplitude) |
| + : FakeAudioDevice( |
| + CreatePulsedNoiseCapturer(sampling_frequency_in_hz, max_amplitude), |
| + CreateDiscarder(sampling_frequency_in_hz), speed) {} |
| + |
| FakeAudioDevice::~FakeAudioDevice() { |
| StopPlayout(); |
| StopRecording(); |
| @@ -86,25 +183,31 @@ FakeAudioDevice::~FakeAudioDevice() { |
| int32_t FakeAudioDevice::StartPlayout() { |
| rtc::CritScope cs(&lock_); |
| + RTC_CHECK(renderer_); |
| rendering_ = true; |
| + done_rendering_.Reset(); |
| return 0; |
| } |
| int32_t FakeAudioDevice::StopPlayout() { |
| rtc::CritScope cs(&lock_); |
| rendering_ = false; |
| + done_rendering_.Set(); |
| return 0; |
| } |
| int32_t FakeAudioDevice::StartRecording() { |
| rtc::CritScope cs(&lock_); |
| + RTC_CHECK(capturer_); |
| capturing_ = true; |
| + done_capturing_.Reset(); |
| return 0; |
| } |
| int32_t FakeAudioDevice::StopRecording() { |
| rtc::CritScope cs(&lock_); |
| capturing_ = false; |
| + done_capturing_.Set(); |
| return 0; |
| } |
| @@ -117,7 +220,7 @@ int32_t FakeAudioDevice::Init() { |
| int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { |
| rtc::CritScope cs(&lock_); |
| - RTC_DCHECK(callback || audio_callback_ != nullptr); |
| + RTC_DCHECK(callback || audio_callback_); |
| audio_callback_ = callback; |
| return 0; |
| } |
| @@ -132,6 +235,14 @@ bool FakeAudioDevice::Recording() const { |
| return capturing_; |
| } |
| +bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) { |
| + return done_rendering_.Wait(timeout_ms); |
| +} |
| + |
| +bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) { |
| + return done_capturing_.Wait(timeout_ms); |
| +} |
| + |
| bool FakeAudioDevice::Run(void* obj) { |
| static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); |
| return true; |
| @@ -144,17 +255,26 @@ void FakeAudioDevice::ProcessAudio() { |
| // Capture 10ms of audio. 2 bytes per sample. |
| rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); |
| uint32_t new_mic_level = 0; |
| - audio_callback_->RecordedDataIsAvailable( |
| - audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_, |
| - 0, 0, 0, false, new_mic_level); |
| + if (audio_data.size() > 0) { |
| + audio_callback_->RecordedDataIsAvailable( |
| + audio_data.data(), audio_data.size(), 2, 1, |
| + capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level); |
| + } else { |
| + StopRecording(); |
| + } |
| } |
| if (rendering_) { |
| - size_t samples_out = 0; |
| - int64_t elapsed_time_ms = -1; |
| - int64_t ntp_time_ms = -1; |
| + size_t samples_out; |
| + int64_t elapsed_time_ms; |
| + int64_t ntp_time_ms; |
| audio_callback_->NeedMorePlayData( |
| - num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_, |
| + renderer_->SamplesPerFrame(), 2, 1, renderer_->SamplingFrequency(), |
| playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); |
| + bool keep_rendering = renderer_->Render( |
|
kwiberg-webrtc
2017/03/09 10:04:10
const?
oprypin_webrtc
2017/03/10 10:44:27
Done.
|
| + rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); |
| + if (!keep_rendering) { |
| + StopPlayout(); |
| + } |
| } |
| } |
| tick_->Wait(WEBRTC_EVENT_INFINITE); |