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 |