Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Unified Diff: webrtc/test/fake_audio_device.cc

Issue 2717623003: Add the ability to read/write to WAV files in FakeAudioDevice (Closed)
Patch Set: Address review feedback Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« webrtc/test/fake_audio_device.h ('K') | « webrtc/test/fake_audio_device.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..ad7e49bf0471735b8cdef7be146b169fdbdf9113 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,171 @@ 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)
+ : sampling_frequency_in_hz_(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() {
+ int SamplingFrequency() const override {
+ return sampling_frequency_in_hz_;
+ }
+
+ 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(buffer->size(), [&](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();
+ });
+ return true;
}
private:
+ int sampling_frequency_in_hz_;
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)
- : sampling_frequency_in_hz_(sampling_frequency_in_hz),
- num_samples_per_frame_(
- rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)),
+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<int16_t>* buffer) override {
+ buffer->SetData(buffer->size(), [&](rtc::ArrayView<int16_t> 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<const int16_t> data) override {
+ wav_writer_.WriteSamples(data.data(), data.size());
+ return true;
+ }
+
+ private:
+ int sampling_frequency_in_hz_;
+ WavWriter wav_writer_;
+};
+
+class DiscardRenderer final : public test::FakeAudioDevice::Renderer {
+ public:
+ 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<const int16_t> data) override {
+ return true;
+ }
+
+ private:
+ int sampling_frequency_in_hz_;
+};
+
+} // namespace
+namespace test {
+
+size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) {
+ return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond);
+}
+
+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::CreateDiscardRenderer(int sampling_frequency_in_hz) {
+ return std::unique_ptr<FakeAudioDevice::Renderer>(
+ new DiscardRenderer(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_) {
+ const int sample_rate = renderer_->SamplingFrequency();
+ playout_buffer_.resize(SamplesPerFrame(sample_rate), 0);
+ RTC_CHECK(
+ sample_rate == 8000 || sample_rate == 16000 || sample_rate == 32000 ||
+ sample_rate == 44100 || sample_rate == 48000);
+ }
+ if (capturer_) {
+ const int sample_rate = capturer_->SamplingFrequency();
+ RTC_CHECK(
+ sample_rate == 8000 || sample_rate == 16000 || sample_rate == 32000 ||
+ sample_rate == 44100 || sample_rate == 48000);
kwiberg-webrtc 2017/03/13 14:22:28 Do the CHECK first in this function, so you don't
oprypin_webrtc 2017/03/13 15:11:36 I'm checking two different sample rates.
kwiberg-webrtc 2017/03/14 10:02:03 Right, I would have seen that if I hadn't been so
oprypin_webrtc 2017/03/14 11:58:13 Done.
+ }
}
FakeAudioDevice::~FakeAudioDevice() {
@@ -86,25 +200,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 +237,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 +252,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 +270,34 @@ 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);
+ recording_buffer_.SetSize(
+ SamplesPerFrame(capturer_->SamplingFrequency()));
+ const bool keep_capturing = capturer_->Capture(&recording_buffer_);
+ uint32_t new_mic_level;
+ if (recording_buffer_.size() > 0) {
kwiberg-webrtc 2017/03/13 14:22:27 This condition is always true, right? (You could
oprypin_webrtc 2017/03/13 15:11:36 It is not true at the end of the recording. Don't
kwiberg-webrtc 2017/03/14 10:02:03 On line 273, you SetSize() the buffer to SamplesPe
oprypin_webrtc 2017/03/14 11:58:13 No. The Capture method is free to change the buffe
kwiberg-webrtc 2017/03/14 13:46:47 Ah, right! Sorry for being dense. However, since
oprypin_webrtc 2017/03/14 14:01:40 Yes, I removed that line in a later patchset. In
kwiberg-webrtc 2017/03/14 14:08:56 Acknowledged.
+ audio_callback_->RecordedDataIsAvailable(
+ recording_buffer_.data(), recording_buffer_.size(), 2, 1,
+ capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level);
+ }
+ if (!keep_capturing) {
+ capturing_ = false;
+ done_capturing_.Set();
+ }
}
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;
+ const int sampling_frequency = renderer_->SamplingFrequency();
audio_callback_->NeedMorePlayData(
- num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_,
+ SamplesPerFrame(sampling_frequency), 2, 1, sampling_frequency,
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);
« webrtc/test/fake_audio_device.h ('K') | « webrtc/test/fake_audio_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698