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 |
| 28 // Assuming 10ms audio packets.. |
| 29 class PulsedNoiseCapturer final : public test::FakeAudioDevice::Capturer { |
| 30 public: |
| 31 PulsedNoiseCapturer(int16_t max_amplitude, int sampling_frequency_in_hz) |
| 32 : sampling_frequency_in_hz_(sampling_frequency_in_hz), |
| 33 fill_with_zero_(false), |
| 34 random_generator_(1), |
| 35 max_amplitude_(max_amplitude) { |
| 36 RTC_DCHECK_GT(max_amplitude, 0); |
| 37 } |
| 38 |
| 39 int SamplingFrequency() const override { |
| 40 return sampling_frequency_in_hz_; |
| 41 } |
| 42 |
| 43 bool Capture(rtc::BufferT<int16_t>* buffer) override { |
| 44 fill_with_zero_ = !fill_with_zero_; |
| 45 buffer->SetData( |
| 46 test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), |
| 47 [&](rtc::ArrayView<int16_t> data) { |
| 48 if (fill_with_zero_) { |
| 49 std::fill(data.begin(), data.end(), 0); |
| 50 } else { |
| 51 std::generate(data.begin(), data.end(), [&]() { |
| 52 return random_generator_.Rand(-max_amplitude_, max_amplitude_); |
| 53 }); |
| 54 } |
| 55 return data.size(); |
| 56 }); |
| 57 return true; |
| 58 } |
| 59 |
| 60 private: |
| 61 int sampling_frequency_in_hz_; |
| 62 bool fill_with_zero_; |
| 63 Random random_generator_; |
| 64 const int16_t max_amplitude_; |
| 65 }; |
| 66 |
| 67 class WavFileReader final : public test::FakeAudioDevice::Capturer { |
| 68 public: |
| 69 WavFileReader(std::string filename, int sampling_frequency_in_hz) |
| 70 : sampling_frequency_in_hz_(sampling_frequency_in_hz), |
| 71 wav_reader_(filename) { |
| 72 RTC_CHECK_EQ(wav_reader_.sample_rate(), sampling_frequency_in_hz); |
| 73 RTC_CHECK_EQ(wav_reader_.num_channels(), 1); |
| 74 } |
| 75 |
| 76 int SamplingFrequency() const override { |
| 77 return sampling_frequency_in_hz_; |
| 78 } |
| 79 |
| 80 bool Capture(rtc::BufferT<int16_t>* buffer) override { |
| 81 buffer->SetData( |
| 82 test::FakeAudioDevice::SamplesPerFrame(sampling_frequency_in_hz_), |
| 83 [&](rtc::ArrayView<int16_t> data) { |
| 84 return wav_reader_.ReadSamples(data.size(), data.data()); |
| 85 }); |
| 86 return buffer->size() > 0; |
| 87 } |
| 88 |
| 89 private: |
| 90 int sampling_frequency_in_hz_; |
| 91 WavReader wav_reader_; |
| 92 }; |
| 93 |
| 94 class WavFileWriter final : public test::FakeAudioDevice::Renderer { |
| 95 public: |
| 96 WavFileWriter(std::string filename, int sampling_frequency_in_hz) |
| 97 : sampling_frequency_in_hz_(sampling_frequency_in_hz), |
| 98 wav_writer_(filename, sampling_frequency_in_hz, 1) {} |
| 99 |
| 100 int SamplingFrequency() const override { |
| 101 return sampling_frequency_in_hz_; |
| 102 } |
| 103 |
| 104 bool Render(rtc::ArrayView<const int16_t> data) override { |
| 105 wav_writer_.WriteSamples(data.data(), data.size()); |
| 106 return true; |
| 107 } |
| 108 |
| 109 private: |
| 110 int sampling_frequency_in_hz_; |
| 111 WavWriter wav_writer_; |
| 112 }; |
| 113 |
| 114 class DiscardRenderer final : public test::FakeAudioDevice::Renderer { |
| 115 public: |
| 116 explicit DiscardRenderer(int sampling_frequency_in_hz) |
| 117 : sampling_frequency_in_hz_(sampling_frequency_in_hz) {} |
| 118 |
| 119 int SamplingFrequency() const override { |
| 120 return sampling_frequency_in_hz_; |
| 121 } |
| 122 |
| 123 bool Render(rtc::ArrayView<const int16_t> data) override { |
| 124 return true; |
| 125 } |
| 126 |
| 127 private: |
| 128 int sampling_frequency_in_hz_; |
| 129 }; |
| 130 |
27 } // namespace | 131 } // namespace |
28 namespace test { | 132 namespace test { |
29 | 133 |
30 // Assuming 10ms audio packets.. | 134 size_t FakeAudioDevice::SamplesPerFrame(int sampling_frequency_in_hz) { |
31 class FakeAudioDevice::PulsedNoiseCapturer { | 135 return rtc::CheckedDivExact(sampling_frequency_in_hz, kFramesPerSecond); |
32 public: | 136 } |
33 PulsedNoiseCapturer(size_t num_samples_per_frame, int16_t max_amplitude) | |
34 : fill_with_zero_(false), | |
35 random_generator_(1), | |
36 max_amplitude_(max_amplitude), | |
37 random_audio_(num_samples_per_frame), | |
38 silent_audio_(num_samples_per_frame, 0) { | |
39 RTC_DCHECK_GT(max_amplitude, 0); | |
40 } | |
41 | 137 |
42 rtc::ArrayView<const int16_t> Capture() { | 138 std::unique_ptr<FakeAudioDevice::Capturer> |
43 fill_with_zero_ = !fill_with_zero_; | 139 FakeAudioDevice::CreatePulsedNoiseCapturer( |
44 if (!fill_with_zero_) { | 140 int16_t max_amplitude, int sampling_frequency_in_hz) { |
45 std::generate(random_audio_.begin(), random_audio_.end(), [&]() { | 141 return std::unique_ptr<FakeAudioDevice::Capturer>( |
46 return random_generator_.Rand(-max_amplitude_, max_amplitude_); | 142 new PulsedNoiseCapturer(max_amplitude, sampling_frequency_in_hz)); |
47 }); | 143 } |
48 } | |
49 return fill_with_zero_ ? silent_audio_ : random_audio_; | |
50 } | |
51 | 144 |
52 private: | 145 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( |
53 bool fill_with_zero_; | 146 std::string filename, int sampling_frequency_in_hz) { |
54 Random random_generator_; | 147 return std::unique_ptr<FakeAudioDevice::Capturer>( |
55 const int16_t max_amplitude_; | 148 new WavFileReader(filename, sampling_frequency_in_hz)); |
56 std::vector<int16_t> random_audio_; | 149 } |
57 std::vector<int16_t> silent_audio_; | |
58 }; | |
59 | 150 |
60 FakeAudioDevice::FakeAudioDevice(float speed, | 151 std::unique_ptr<FakeAudioDevice::Capturer> FakeAudioDevice::CreateWavFileReader( |
61 int sampling_frequency_in_hz, | 152 std::string filename) { |
62 int16_t max_amplitude) | 153 int sampling_frequency_in_hz = WavReader(filename).sample_rate(); |
63 : sampling_frequency_in_hz_(sampling_frequency_in_hz), | 154 return std::unique_ptr<FakeAudioDevice::Capturer>( |
64 num_samples_per_frame_( | 155 new WavFileReader(filename, sampling_frequency_in_hz)); |
65 rtc::CheckedDivExact(sampling_frequency_in_hz_, kFramesPerSecond)), | 156 } |
| 157 |
| 158 std::unique_ptr<FakeAudioDevice::Renderer> FakeAudioDevice::CreateWavFileWriter( |
| 159 std::string filename, int sampling_frequency_in_hz) { |
| 160 return std::unique_ptr<FakeAudioDevice::Renderer>( |
| 161 new WavFileWriter(filename, sampling_frequency_in_hz)); |
| 162 } |
| 163 |
| 164 std::unique_ptr<FakeAudioDevice::Renderer> |
| 165 FakeAudioDevice::CreateDiscardRenderer(int sampling_frequency_in_hz) { |
| 166 return std::unique_ptr<FakeAudioDevice::Renderer>( |
| 167 new DiscardRenderer(sampling_frequency_in_hz)); |
| 168 } |
| 169 |
| 170 |
| 171 FakeAudioDevice::FakeAudioDevice(std::unique_ptr<Capturer> capturer, |
| 172 std::unique_ptr<Renderer> renderer, |
| 173 float speed) |
| 174 : capturer_(std::move(capturer)), |
| 175 renderer_(std::move(renderer)), |
66 speed_(speed), | 176 speed_(speed), |
67 audio_callback_(nullptr), | 177 audio_callback_(nullptr), |
68 rendering_(false), | 178 rendering_(false), |
69 capturing_(false), | 179 capturing_(false), |
70 capturer_(new FakeAudioDevice::PulsedNoiseCapturer(num_samples_per_frame_, | 180 done_rendering_(true, true), |
71 max_amplitude)), | 181 done_capturing_(true, true), |
72 playout_buffer_(num_samples_per_frame_, 0), | |
73 tick_(EventTimerWrapper::Create()), | 182 tick_(EventTimerWrapper::Create()), |
74 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { | 183 thread_(FakeAudioDevice::Run, this, "FakeAudioDevice") { |
75 RTC_DCHECK( | 184 auto good_sample_rate = [](int sr) { |
76 sampling_frequency_in_hz == 8000 || sampling_frequency_in_hz == 16000 || | 185 return sr == 8000 || sr == 16000 || sr == 32000 |
77 sampling_frequency_in_hz == 32000 || sampling_frequency_in_hz == 44100 || | 186 || sr == 44100 || sr == 48000; |
78 sampling_frequency_in_hz == 48000); | 187 }; |
| 188 |
| 189 if (renderer_) { |
| 190 const int sample_rate = renderer_->SamplingFrequency(); |
| 191 playout_buffer_.resize(SamplesPerFrame(sample_rate), 0); |
| 192 RTC_CHECK(good_sample_rate(sample_rate)); |
| 193 } |
| 194 if (capturer_) { |
| 195 RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency())); |
| 196 } |
79 } | 197 } |
80 | 198 |
81 FakeAudioDevice::~FakeAudioDevice() { | 199 FakeAudioDevice::~FakeAudioDevice() { |
82 StopPlayout(); | 200 StopPlayout(); |
83 StopRecording(); | 201 StopRecording(); |
84 thread_.Stop(); | 202 thread_.Stop(); |
85 } | 203 } |
86 | 204 |
87 int32_t FakeAudioDevice::StartPlayout() { | 205 int32_t FakeAudioDevice::StartPlayout() { |
88 rtc::CritScope cs(&lock_); | 206 rtc::CritScope cs(&lock_); |
| 207 RTC_CHECK(renderer_); |
89 rendering_ = true; | 208 rendering_ = true; |
| 209 done_rendering_.Reset(); |
90 return 0; | 210 return 0; |
91 } | 211 } |
92 | 212 |
93 int32_t FakeAudioDevice::StopPlayout() { | 213 int32_t FakeAudioDevice::StopPlayout() { |
94 rtc::CritScope cs(&lock_); | 214 rtc::CritScope cs(&lock_); |
95 rendering_ = false; | 215 rendering_ = false; |
| 216 done_rendering_.Set(); |
96 return 0; | 217 return 0; |
97 } | 218 } |
98 | 219 |
99 int32_t FakeAudioDevice::StartRecording() { | 220 int32_t FakeAudioDevice::StartRecording() { |
100 rtc::CritScope cs(&lock_); | 221 rtc::CritScope cs(&lock_); |
| 222 RTC_CHECK(capturer_); |
101 capturing_ = true; | 223 capturing_ = true; |
| 224 done_capturing_.Reset(); |
102 return 0; | 225 return 0; |
103 } | 226 } |
104 | 227 |
105 int32_t FakeAudioDevice::StopRecording() { | 228 int32_t FakeAudioDevice::StopRecording() { |
106 rtc::CritScope cs(&lock_); | 229 rtc::CritScope cs(&lock_); |
107 capturing_ = false; | 230 capturing_ = false; |
| 231 done_capturing_.Set(); |
108 return 0; | 232 return 0; |
109 } | 233 } |
110 | 234 |
111 int32_t FakeAudioDevice::Init() { | 235 int32_t FakeAudioDevice::Init() { |
112 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); | 236 RTC_CHECK(tick_->StartTimer(true, kFrameLengthMs / speed_)); |
113 thread_.Start(); | 237 thread_.Start(); |
114 thread_.SetPriority(rtc::kHighPriority); | 238 thread_.SetPriority(rtc::kHighPriority); |
115 return 0; | 239 return 0; |
116 } | 240 } |
117 | 241 |
118 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { | 242 int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { |
119 rtc::CritScope cs(&lock_); | 243 rtc::CritScope cs(&lock_); |
120 RTC_DCHECK(callback || audio_callback_ != nullptr); | 244 RTC_DCHECK(callback || audio_callback_); |
121 audio_callback_ = callback; | 245 audio_callback_ = callback; |
122 return 0; | 246 return 0; |
123 } | 247 } |
124 | 248 |
125 bool FakeAudioDevice::Playing() const { | 249 bool FakeAudioDevice::Playing() const { |
126 rtc::CritScope cs(&lock_); | 250 rtc::CritScope cs(&lock_); |
127 return rendering_; | 251 return rendering_; |
128 } | 252 } |
129 | 253 |
130 bool FakeAudioDevice::Recording() const { | 254 bool FakeAudioDevice::Recording() const { |
131 rtc::CritScope cs(&lock_); | 255 rtc::CritScope cs(&lock_); |
132 return capturing_; | 256 return capturing_; |
133 } | 257 } |
134 | 258 |
| 259 bool FakeAudioDevice::WaitForPlayoutEnd(int timeout_ms) { |
| 260 return done_rendering_.Wait(timeout_ms); |
| 261 } |
| 262 |
| 263 bool FakeAudioDevice::WaitForRecordingEnd(int timeout_ms) { |
| 264 return done_capturing_.Wait(timeout_ms); |
| 265 } |
| 266 |
135 bool FakeAudioDevice::Run(void* obj) { | 267 bool FakeAudioDevice::Run(void* obj) { |
136 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); | 268 static_cast<FakeAudioDevice*>(obj)->ProcessAudio(); |
137 return true; | 269 return true; |
138 } | 270 } |
139 | 271 |
140 void FakeAudioDevice::ProcessAudio() { | 272 void FakeAudioDevice::ProcessAudio() { |
141 { | 273 { |
142 rtc::CritScope cs(&lock_); | 274 rtc::CritScope cs(&lock_); |
143 if (capturing_) { | 275 if (capturing_) { |
144 // Capture 10ms of audio. 2 bytes per sample. | 276 // Capture 10ms of audio. 2 bytes per sample. |
145 rtc::ArrayView<const int16_t> audio_data = capturer_->Capture(); | 277 const bool keep_capturing = capturer_->Capture(&recording_buffer_); |
146 uint32_t new_mic_level = 0; | 278 uint32_t new_mic_level; |
147 audio_callback_->RecordedDataIsAvailable( | 279 if (recording_buffer_.size() > 0) { |
148 audio_data.data(), audio_data.size(), 2, 1, sampling_frequency_in_hz_, | 280 audio_callback_->RecordedDataIsAvailable( |
149 0, 0, 0, false, new_mic_level); | 281 recording_buffer_.data(), recording_buffer_.size(), 2, 1, |
| 282 capturer_->SamplingFrequency(), 0, 0, 0, false, new_mic_level); |
| 283 } |
| 284 if (!keep_capturing) { |
| 285 capturing_ = false; |
| 286 done_capturing_.Set(); |
| 287 } |
150 } | 288 } |
151 if (rendering_) { | 289 if (rendering_) { |
152 size_t samples_out = 0; | 290 size_t samples_out; |
153 int64_t elapsed_time_ms = -1; | 291 int64_t elapsed_time_ms; |
154 int64_t ntp_time_ms = -1; | 292 int64_t ntp_time_ms; |
| 293 const int sampling_frequency = renderer_->SamplingFrequency(); |
155 audio_callback_->NeedMorePlayData( | 294 audio_callback_->NeedMorePlayData( |
156 num_samples_per_frame_, 2, 1, sampling_frequency_in_hz_, | 295 SamplesPerFrame(sampling_frequency), 2, 1, sampling_frequency, |
157 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); | 296 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms); |
| 297 const bool keep_rendering = renderer_->Render( |
| 298 rtc::ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); |
| 299 if (!keep_rendering) { |
| 300 rendering_ = false; |
| 301 done_rendering_.Set(); |
| 302 } |
158 } | 303 } |
159 } | 304 } |
160 tick_->Wait(WEBRTC_EVENT_INFINITE); | 305 tick_->Wait(WEBRTC_EVENT_INFINITE); |
161 } | 306 } |
162 | 307 |
163 | 308 |
164 } // namespace test | 309 } // namespace test |
165 } // namespace webrtc | 310 } // namespace webrtc |
OLD | NEW |