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..9e81c6f2687f6e95642d7f6b04b723e9d0ac8434 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 { |
| @@ -24,58 +25,144 @@ namespace { |
| constexpr int kFrameLengthMs = 10; |
| constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; |
| -} // namespace |
| -namespace test { |
| - |
| // Assuming 10ms audio packets.. |
| -class FakeAudioDevice::PulsedNoiseCapturer { |
| +class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer { |
| public: |
| - PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude) |
| - : fill_with_zero_(false), |
| + PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz) |
| + : 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) { |
| + max_amplitude_(max_amplitude) { |
| RTC_DCHECK_GT(max_amplitude, 0); |
| } |
| - rtc::ArrayView<const int16_t> Capture() { |
| + bool Capture(rtc::BufferT<int16_t>* buffer) override { |
| fill_with_zero_ = !fill_with_zero_; |
| - if (!fill_with_zero_) { |
| - std::generate(random_audio_.begin(), random_audio_.end(), [&]() { |
| - return random_generator_.Rand(-max_amplitude_, max_amplitude_); |
| - }); |
| - } |
| - return fill_with_zero_ ? silent_audio_ : random_audio_; |
| + buffer->SetData(SamplesPerFrame(), [&](rtc::ArrayView<int16_t> 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(); |
| + }); |
|
kwiberg-webrtc
2017/03/13 10:18:22
Excellent use of SetData with a lambda!
|
| + return true; |
| } |
| private: |
| bool fill_with_zero_; |
| Random random_generator_; |
| const int16_t max_amplitude_; |
| - std::vector<int16_t> random_audio_; |
| - std::vector<int16_t> silent_audio_; |
| }; |
| -FakeAudioDevice::FakeAudioDevice(float speed, |
| - int sampling_frequency_in_hz, |
| - int16_t max_amplitude) |
| +class WavFileReader final : public test::FakeAudioDevice::Capturer { |
| + public: |
| + WavFileReader(std::string filename, int sampling_frequency_in_hz) |
| + : test::FakeAudioDevice::Capturer(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); |
| + } |
| + |
| + bool Capture(rtc::BufferT<int16_t>* buffer) override { |
| + buffer->SetData(SamplesPerFrame(), [&](rtc::ArrayView<int16_t> data) { |
| + return wav_reader_.ReadSamples(data.size(), data.data()); |
| + }); |
| + return buffer->size() > 0; |
| + } |
| + |
| + private: |
| + WavReader wav_reader_; |
| +}; |
| + |
| +class WavFileWriter final : public test::FakeAudioDevice::Renderer { |
| + public: |
| + WavFileWriter(std::string filename, int sampling_frequency_in_hz) |
| + : test::FakeAudioDevice::Renderer(sampling_frequency_in_hz), |
| + wav_writer_(filename, sampling_frequency_in_hz, 1) {} |
| + |
| + bool Render(rtc::ArrayView<const int16_t> data) override { |
| + wav_writer_.WriteSamples(data.data(), data.size()); |
| + return true; |
| + } |
| + |
| + private: |
| + WavWriter wav_writer_; |
| +}; |
| + |
| +class Discarder final : public test::FakeAudioDevice::Renderer { |
| + public: |
| + using Renderer::Renderer; |
| + |
| + bool Render(rtc::ArrayView<const int16_t> data) override { |
| + return true; |
| + } |
| +}; |
| + |
| +} // namespace |
| +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)), |
| + 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); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Capturer> |
| + FakeAudioDevice::CreatePulsedNoiseCapturer( |
| + int16_t max_amplitude, int sampling_frequency_in_hz) { |
| + return std::unique_ptr<FakeAudioDevice::Capturer>( |
| + new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz)); |
| +} |
| + |
| +std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( |
| + std::string filename, int sampling_frequency_in_hz) { |
| + return std::unique_ptr<FakeAudioDevice::Capturer>( |
| + new 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 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 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 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() { |
| @@ -86,25 +173,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 +210,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 +225,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; |
| @@ -142,19 +243,31 @@ void FakeAudioDevice::ProcessAudio() { |
| rtc::CritScope cs(&lock_); |
| if (capturing_) { |
| // 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); |
| + const bool keep_recording = capturer_->Capture(&recording_buffer_); |
| + uint32_t new_mic_level; |
| + if (recording_buffer_.size() > 0) { |
| + audio_callback_->RecordedDataIsAvailable( |
| + recording_buffer_.data(), recording_buffer_.size(), 2, 1, |
| + capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level); |
| + } |
| + if (!keep_recording) { |
| + capturing_ = false; |
| + done_capturing_.Set(); |
|
kwiberg-webrtc
2017/03/13 10:18:21
Nit: It looks like keep_recording could be named k
oprypin_webrtc
2017/03/13 13:55:14
Done.
|
| + } |
| } |
| 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); |
| + const bool keep_rendering = renderer_->Render( |
| + rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); |
| + if (!keep_rendering) { |
| + rendering_ = false; |
| + done_rendering_.Set(); |
| + } |
| } |
| } |
| tick_->Wait(WEBRTC_EVENT_INFINITE); |