Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/test/fake_audio_device.h" | 11 #include "webrtc/test/fake_audio_device.h" |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <utility> | |
| 14 | 15 |
| 15 #include "webrtc/base/array_view.h" | |
| 16 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
| 17 #include "webrtc/base/random.h" | 17 #include "webrtc/base/random.h" |
| 18 #include "webrtc/common_audio/wav_file.h" | |
| 18 #include "webrtc/system_wrappers/include/event_wrapper.h" | 19 #include "webrtc/system_wrappers/include/event_wrapper.h" |
| 19 | 20 |
| 20 namespace webrtc { | 21 namespace webrtc { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 constexpr int kFrameLengthMs = 10; | 25 constexpr int kFrameLengthMs = 10; |
| 25 constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; | 26 constexpr int kFramesPerSecond = 1000 / kFrameLengthMs; |
| 26 | 27 |
| 27 } // namespace | 28 } // 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.
| |
| 28 namespace test { | 29 namespace test { |
| 29 | 30 |
| 31 FakeAudioDevice::Streamer::Streamer(int sampling_frequency_in_hz) | |
| 32 : sampling_frequency_in_hz_(sampling_frequency_in_hz), | |
| 33 num_samples_per_frame_( | |
| 34 rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond)) { | |
| 35 RTC_CHECK( | |
| 36 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || | |
| 37 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || | |
| 38 sampling_frequency_in_hz == 48000); | |
| 39 } | |
| 40 | |
| 30 // Assuming 10ms audio packets.. | 41 // Assuming 10ms audio packets.. |
| 31 class FakeAudioDevice::PulsedNoiseCapturer { | 42 class FakeAudioDevice::PulsedNoiseCapturer : public FakeAudioDevice::Capturer { |
| 32 public: | 43 public: |
| 33 PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude) | 44 PulsedNoiseCapturer(int sampling_frequency_in_hz, int16_t max_amplitude) |
| 34 : fill_with_zero_(false), | 45 : Capturer(sampling_frequency_in_hz), |
| 46 fill_with_zero_(false), | |
| 35 random_generator_(1), | 47 random_generator_(1), |
| 36 max_amplitude_(max_amplitude), | 48 max_amplitude_(max_amplitude), |
| 37 random_audio_(num_samples_per_frame), | 49 random_audio_(SamplesPerFrame()), |
| 38 silent_audio_(num_samples_per_frame, 0) { | 50 silent_audio_(SamplesPerFrame(), 0) { |
| 39 RTC_DCHECK_GT(max_amplitude, 0); | 51 RTC_DCHECK_GT(max_amplitude, 0); |
| 40 } | 52 } |
| 41 | 53 |
| 42 rtc::ArrayView<const int16_t> Capture() { | 54 rtc::ArrayView<const int16_t> Capture() override { |
| 43 fill_with_zero_ = !fill_with_zero_; | 55 fill_with_zero_ = !fill_with_zero_; |
| 44 if (!fill_with_zero_) { | 56 if (!fill_with_zero_) { |
| 45 std::generate(random_audio_.begin(), random_audio_.end(), [&]() { | 57 std::generate(random_audio_.begin(), random_audio_.end(), [&]() { |
| 46 return random_generator_.Rand(-max_amplitude_, max_amplitude_); | 58 return random_generator_.Rand(-max_amplitude_, max_amplitude_); |
| 47 }); | 59 }); |
| 48 } | 60 } |
| 49 return fill_with_zero_ ? silent_audio_ : random_audio_; | 61 return fill_with_zero_ ? silent_audio_ : random_audio_; |
| 50 } | 62 } |
| 51 | 63 |
| 52 private: | 64 private: |
| 53 bool fill_with_zero_; | 65 bool fill_with_zero_; |
| 54 Random random_generator_; | 66 Random random_generator_; |
| 55 const int16_t max_amplitude_; | 67 const int16_t max_amplitude_; |
| 56 std::vector<int16_t> random_audio_; | 68 std::vector<int16_t> random_audio_; |
| 57 std::vector<int16_t> silent_audio_; | 69 std::vector<int16_t> silent_audio_; |
| 58 }; | 70 }; |
| 59 | 71 |
| 72 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.
| |
| 73 public: | |
| 74 WavFileReader(std::string filename, int sampling_frequency_in_hz) | |
| 75 : FakeAudioDevice::Capturer(sampling_frequency_in_hz), | |
| 76 wav_reader_(filename), | |
| 77 buffer_(SamplesPerFrame(), 0) { | |
| 78 RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); | |
| 79 RTC_CHECK_EQ(wav_reader_.num_channels(), 1); | |
| 80 } | |
| 81 | |
| 82 rtc::ArrayView<const int16_t> Capture() override { | |
| 83 const size_t samples_out = wav_reader_.ReadSamples(buffer_.size(), | |
| 84 buffer_.data()); | |
| 85 RTC_CHECK_LE(samples_out, buffer_.size()); | |
| 86 return rtc::ArrayView<const int16_t>(buffer_.data(), samples_out); | |
| 87 } | |
| 88 | |
| 89 private: | |
| 90 WavReader wav_reader_; | |
| 91 std::vector<int16_t> buffer_; | |
| 92 // 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.
| |
| 93 }; | |
| 94 | |
| 95 class FakeAudioDevice::WavFileWriter : public FakeAudioDevice::Renderer { | |
| 96 public: | |
| 97 WavFileWriter(std::string filename, int sampling_frequency_in_hz) | |
| 98 : FakeAudioDevice::Renderer(sampling_frequency_in_hz), | |
| 99 wav_writer_(filename, sampling_frequency_in_hz, 1) {} | |
| 100 | |
| 101 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.
| |
| 102 wav_writer_.WriteSamples(data.data(), data.size()); | |
| 103 return true; | |
| 104 } | |
| 105 | |
| 106 private: | |
| 107 WavWriter wav_writer_; | |
| 108 }; | |
| 109 | |
| 110 class FakeAudioDevice::Discarder : public FakeAudioDevice::Renderer { | |
| 111 public: | |
| 112 using Renderer::Renderer; | |
| 113 | |
| 114 bool Render(rtc::ArrayView<const int16_t> data) { | |
| 115 return true; | |
| 116 } | |
| 117 }; | |
| 118 | |
| 119 std::unique_ptr<FakeAudioDevice::Capturer> | |
| 120 FakeAudioDevice::CreatePulsedNoiseCapturer( | |
| 121 int sampling_frequency_in_hz, int16_t max_amplitude) { | |
| 122 return std::unique_ptr<FakeAudioDevice::Capturer>( | |
| 123 new FakeAudioDevice::PulsedNoiseCapturer( | |
| 124 sampling_frequency_in_hz, max_amplitude)); | |
| 125 } | |
| 126 | |
| 127 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( | |
| 128 std::string filename, int sampling_frequency_in_hz) { | |
| 129 return std::unique_ptr<FakeAudioDevice::Capturer>( | |
| 130 new FakeAudioDevice::WavFileReader(filename, sampling_frequency_in_hz)); | |
| 131 } | |
| 132 | |
| 133 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( | |
| 134 std::string filename) { | |
| 135 int sampling_frequency_in_hz = WavReader(filename).sample_rate(); | |
| 136 return std::unique_ptr<FakeAudioDevice::Capturer>( | |
| 137 new FakeAudioDevice::WavFileReader(filename, sampling_frequency_in_hz)); | |
| 138 } | |
| 139 | |
| 140 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter( | |
| 141 std::string filename, int sampling_frequency_in_hz) { | |
| 142 return std::unique_ptr<FakeAudioDevice::Renderer>( | |
| 143 new FakeAudioDevice::WavFileWriter(filename, sampling_frequency_in_hz)); | |
| 144 } | |
| 145 | |
| 146 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateDiscarder( | |
| 147 int sampling_frequency_in_hz) { | |
| 148 return std::unique_ptr<FakeAudioDevice::Renderer>( | |
| 149 new FakeAudioDevice::Discarder(sampling_frequency_in_hz)); | |
| 150 } | |
| 151 | |
| 152 | |
| 153 FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer, | |
| 154 std::unique_ptr<Renderer> renderer, | |
| 155 float speed) | |
| 156 : capturer_(std::move(capturer)), | |
| 157 renderer_(std::move(renderer)), | |
| 158 speed_(speed), | |
| 159 audio_callback_(nullptr), | |
| 160 rendering_(false), | |
| 161 capturing_(false), | |
| 162 done_rendering_(true, true), | |
| 163 done_capturing_(true, true), | |
| 164 tick_(EventTimerWrapper::Create()), | |
| 165 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { | |
| 166 if (renderer_) { | |
| 167 playout_buffer_.resize(renderer_->SamplesPerFrame(), 0); | |
| 168 } | |
| 169 } | |
| 170 | |
| 60 FakeAudioDevice::FakeAudioDevice(float speed, | 171 FakeAudioDevice::FakeAudioDevice(float speed, |
| 61 int sampling_frequency_in_hz, | 172 int sampling_frequency_in_hz, |
| 62 int16_t max_amplitude) | 173 int16_t max_amplitude) |
| 63 : sampling_frequency_in_hz_(sampling_frequency_in_hz), | 174 : FakeAudioDevice( |
| 64 num_samples_per_frame_( | 175 CreatePulsedNoiseCapturer(sampling_frequency_in_hz, max_amplitude), |
| 65 rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)), | 176 CreateDiscarder(sampling_frequency_in_hz), speed) {} |
| 66 speed_(speed), | |
| 67 audio_callback_(nullptr), | |
| 68 rendering_(false), | |
| 69 capturing_(false), | |
| 70 capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_, | |
| 71 max_amplitude)), | |
| 72 playout_buffer_(num_samples_per_frame_, 0), | |
| 73 tick_(EventTimerWrapper::Create()), | |
| 74 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { | |
| 75 RTC_DCHECK( | |
| 76 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || | |
| 77 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || | |
| 78 sampling_frequency_in_hz == 48000); | |
| 79 } | |
| 80 | 177 |
| 81 FakeAudioDevice::~FakeAudioDevice() { | 178 FakeAudioDevice::~FakeAudioDevice() { |
| 82 StopPlayout(); | 179 StopPlayout(); |
| 83 StopRecording(); | 180 StopRecording(); |
| 84 thread_.Stop(); | 181 thread_.Stop(); |
| 85 } | 182 } |
| 86 | 183 |
| 87 int32_t FakeAudioDevice::StartPlayout() { | 184 int32_t FakeAudioDevice::StartPlayout() { |
| 88 rtc::CritScope cs(&lock_); | 185 rtc::CritScope cs(&lock_); |
| 186 RTC_CHECK(renderer_); | |
| 89 rendering_ = true; | 187 rendering_ = true; |
| 188 done_rendering_.Reset(); | |
| 90 return 0; | 189 return 0; |
| 91 } | 190 } |
| 92 | 191 |
| 93 int32_t FakeAudioDevice::StopPlayout() { | 192 int32_t FakeAudioDevice::StopPlayout() { |
| 94 rtc::CritScope cs(&lock_); | 193 rtc::CritScope cs(&lock_); |
| 95 rendering_ = false; | 194 rendering_ = false; |
| 195 done_rendering_.Set(); | |
| 96 return 0; | 196 return 0; |
| 97 } | 197 } |
| 98 | 198 |
| 99 int32_t FakeAudioDevice::StartRecording() { | 199 int32_t FakeAudioDevice::StartRecording() { |
| 100 rtc::CritScope cs(&lock_); | 200 rtc::CritScope cs(&lock_); |
| 201 RTC_CHECK(capturer_); | |
| 101 capturing_ = true; | 202 capturing_ = true; |
| 203 done_capturing_.Reset(); | |
| 102 return 0; | 204 return 0; |
| 103 } | 205 } |
| 104 | 206 |
| 105 int32_t FakeAudioDevice::StopRecording() { | 207 int32_t FakeAudioDevice::StopRecording() { |
| 106 rtc::CritScope cs(&lock_); | 208 rtc::CritScope cs(&lock_); |
| 107 capturing_ = false; | 209 capturing_ = false; |
| 210 done_capturing_.Set(); | |
| 108 return 0; | 211 return 0; |
| 109 } | 212 } |
| 110 | 213 |
| 111 int32_t FakeAudioDevice::Init() { | 214 int32_t FakeAudioDevice::Init() { |
| 112 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); | 215 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); |
| 113 thread_.Start(); | 216 thread_.Start(); |
| 114 thread_.SetPriority(rtc::kHighPriority); | 217 thread_.SetPriority(rtc::kHighPriority); |
| 115 return 0; | 218 return 0; |
| 116 } | 219 } |
| 117 | 220 |
| 118 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { | 221 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { |
| 119 rtc::CritScope cs(&lock_); | 222 rtc::CritScope cs(&lock_); |
| 120 RTC_DCHECK(callback || audio_callback_ != nullptr); | 223 RTC_DCHECK(callback || audio_callback_); |
| 121 audio_callback_ = callback; | 224 audio_callback_ = callback; |
| 122 return 0; | 225 return 0; |
| 123 } | 226 } |
| 124 | 227 |
| 125 bool FakeAudioDevice::Playing() const { | 228 bool FakeAudioDevice::Playing() const { |
| 126 rtc::CritScope cs(&lock_); | 229 rtc::CritScope cs(&lock_); |
| 127 return rendering_; | 230 return rendering_; |
| 128 } | 231 } |
| 129 | 232 |
| 130 bool FakeAudioDevice::Recording() const { | 233 bool FakeAudioDevice::Recording() const { |
| 131 rtc::CritScope cs(&lock_); | 234 rtc::CritScope cs(&lock_); |
| 132 return capturing_; | 235 return capturing_; |
| 133 } | 236 } |
| 134 | 237 |
| 238 bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) { | |
| 239 return done_rendering_.Wait(timeout_ms); | |
| 240 } | |
| 241 | |
| 242 bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) { | |
| 243 return done_capturing_.Wait(timeout_ms); | |
| 244 } | |
| 245 | |
| 135 bool FakeAudioDevice::Run(void* obj) { | 246 bool FakeAudioDevice::Run(void* obj) { |
| 136 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); | 247 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); |
| 137 return true; | 248 return true; |
| 138 } | 249 } |
| 139 | 250 |
| 140 void FakeAudioDevice::ProcessAudio() { | 251 void FakeAudioDevice::ProcessAudio() { |
| 141 { | 252 { |
| 142 rtc::CritScope cs(&lock_); | 253 rtc::CritScope cs(&lock_); |
| 143 if (capturing_) { | 254 if (capturing_) { |
| 144 // Capture 10ms of audio. 2 bytes per sample. | 255 // Capture 10ms of audio. 2 bytes per sample. |
| 145 rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); | 256 rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); |
| 146 uint32_t new_mic_level = 0; | 257 uint32_t new_mic_level = 0; |
| 147 audio_callback_->RecordedDataIsAvailable( | 258 if (audio_data.size() > 0) { |
| 148 audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_, | 259 audio_callback_->RecordedDataIsAvailable( |
| 149 0, 0, 0, false, new_mic_level); | 260 audio_data.data(), audio_data.size(), 2, 1, |
| 261 capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level); | |
| 262 } else { | |
| 263 StopRecording(); | |
| 264 } | |
| 150 } | 265 } |
| 151 if (rendering_) { | 266 if (rendering_) { |
| 152 size_t samples_out = 0; | 267 size_t samples_out; |
| 153 int64_t elapsed_time_ms = -1; | 268 int64_t elapsed_time_ms; |
| 154 int64_t ntp_time_ms = -1; | 269 int64_t ntp_time_ms; |
| 155 audio_callback_->NeedMorePlayData( | 270 audio_callback_->NeedMorePlayData( |
| 156 num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_, | 271 renderer_->SamplesPerFrame(), 2, 1, renderer_->SamplingFrequency(), |
| 157 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); | 272 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); |
| 273 bool keep_rendering = renderer_->Render( | |
|
kwiberg-webrtc
2017/03/09 10:04:10
const?
oprypin_webrtc
2017/03/10 10:44:27
Done.
| |
| 274 rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); | |
| 275 if (!keep_rendering) { | |
| 276 StopPlayout(); | |
| 277 } | |
| 158 } | 278 } |
| 159 } | 279 } |
| 160 tick_->Wait(WEBRTC_EVENT_INFINITE); | 280 tick_->Wait(WEBRTC_EVENT_INFINITE); |
| 161 } | 281 } |
| 162 | 282 |
| 163 | 283 |
| 164 } // namespace test | 284 } // namespace test |
| 165 } // namespace webrtc | 285 } // namespace webrtc |
| OLD | NEW |