1 /*
2 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/test/fake_audio_capture_module.h"
12
13 #include <string.h>
14
15 #include "rtc_base/checks.h"
16 #include "rtc_base/location.h"
17 #include "rtc_base/ref_counted_object.h"
18 #include "rtc_base/thread.h"
19 #include "rtc_base/time_utils.h"
20
21 // Audio sample value that is high enough that it doesn't occur naturally when
22 // frames are being faked. E.g. NetEq will not generate this large sample value
23 // unless it has received an audio frame containing a sample of this value.
24 // Even simpler buffers would likely just contain audio sample values of 0.
25 static const int kHighSampleValue = 10000;
26
27 // Constants here are derived by running VoE using a real ADM.
28 // The constants correspond to 10ms of mono audio at 44kHz.
29 static const int kTimePerFrameMs = 10;
30 static const uint8_t kNumberOfChannels = 1;
31 static const int kSamplesPerSecond = 44000;
32 static const int kTotalDelayMs = 0;
33 static const int kClockDriftMs = 0;
34 static const uint32_t kMaxVolume = 14392;
35
36 enum {
37 MSG_START_PROCESS,
38 MSG_RUN_PROCESS,
39 };
40
FakeAudioCaptureModule()41 FakeAudioCaptureModule::FakeAudioCaptureModule()
42 : audio_callback_(nullptr),
43 recording_(false),
44 playing_(false),
45 play_is_initialized_(false),
46 rec_is_initialized_(false),
47 current_mic_level_(kMaxVolume),
48 started_(false),
49 next_frame_time_(0),
50 frames_received_(0) {
51 process_thread_checker_.Detach();
52 }
53
~FakeAudioCaptureModule()54 FakeAudioCaptureModule::~FakeAudioCaptureModule() {
55 if (process_thread_) {
56 process_thread_->Stop();
57 }
58 }
59
Create()60 rtc::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create() {
61 rtc::scoped_refptr<FakeAudioCaptureModule> capture_module(
62 new rtc::RefCountedObject<FakeAudioCaptureModule>());
63 if (!capture_module->Initialize()) {
64 return nullptr;
65 }
66 return capture_module;
67 }
68
frames_received() const69 int FakeAudioCaptureModule::frames_received() const {
70 webrtc::MutexLock lock(&mutex_);
71 return frames_received_;
72 }
73
ActiveAudioLayer(AudioLayer *) const74 int32_t FakeAudioCaptureModule::ActiveAudioLayer(
75 AudioLayer* /*audio_layer*/) const {
76 RTC_NOTREACHED();
77 return 0;
78 }
79
RegisterAudioCallback(webrtc::AudioTransport * audio_callback)80 int32_t FakeAudioCaptureModule::RegisterAudioCallback(
81 webrtc::AudioTransport* audio_callback) {
82 webrtc::MutexLock lock(&mutex_);
83 audio_callback_ = audio_callback;
84 return 0;
85 }
86
Init()87 int32_t FakeAudioCaptureModule::Init() {
88 // Initialize is called by the factory method. Safe to ignore this Init call.
89 return 0;
90 }
91
Terminate()92 int32_t FakeAudioCaptureModule::Terminate() {
93 // Clean up in the destructor. No action here, just success.
94 return 0;
95 }
96
Initialized() const97 bool FakeAudioCaptureModule::Initialized() const {
98 RTC_NOTREACHED();
99 return 0;
100 }
101
PlayoutDevices()102 int16_t FakeAudioCaptureModule::PlayoutDevices() {
103 RTC_NOTREACHED();
104 return 0;
105 }
106
RecordingDevices()107 int16_t FakeAudioCaptureModule::RecordingDevices() {
108 RTC_NOTREACHED();
109 return 0;
110 }
111
PlayoutDeviceName(uint16_t,char[webrtc::kAdmMaxDeviceNameSize],char[webrtc::kAdmMaxGuidSize])112 int32_t FakeAudioCaptureModule::PlayoutDeviceName(
113 uint16_t /*index*/,
114 char /*name*/[webrtc::kAdmMaxDeviceNameSize],
115 char /*guid*/[webrtc::kAdmMaxGuidSize]) {
116 RTC_NOTREACHED();
117 return 0;
118 }
119
RecordingDeviceName(uint16_t,char[webrtc::kAdmMaxDeviceNameSize],char[webrtc::kAdmMaxGuidSize])120 int32_t FakeAudioCaptureModule::RecordingDeviceName(
121 uint16_t /*index*/,
122 char /*name*/[webrtc::kAdmMaxDeviceNameSize],
123 char /*guid*/[webrtc::kAdmMaxGuidSize]) {
124 RTC_NOTREACHED();
125 return 0;
126 }
127
SetPlayoutDevice(uint16_t)128 int32_t FakeAudioCaptureModule::SetPlayoutDevice(uint16_t /*index*/) {
129 // No playout device, just playing from file. Return success.
130 return 0;
131 }
132
SetPlayoutDevice(WindowsDeviceType)133 int32_t FakeAudioCaptureModule::SetPlayoutDevice(WindowsDeviceType /*device*/) {
134 if (play_is_initialized_) {
135 return -1;
136 }
137 return 0;
138 }
139
SetRecordingDevice(uint16_t)140 int32_t FakeAudioCaptureModule::SetRecordingDevice(uint16_t /*index*/) {
141 // No recording device, just dropping audio. Return success.
142 return 0;
143 }
144
SetRecordingDevice(WindowsDeviceType)145 int32_t FakeAudioCaptureModule::SetRecordingDevice(
146 WindowsDeviceType /*device*/) {
147 if (rec_is_initialized_) {
148 return -1;
149 }
150 return 0;
151 }
152
PlayoutIsAvailable(bool *)153 int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) {
154 RTC_NOTREACHED();
155 return 0;
156 }
157
InitPlayout()158 int32_t FakeAudioCaptureModule::InitPlayout() {
159 play_is_initialized_ = true;
160 return 0;
161 }
162
PlayoutIsInitialized() const163 bool FakeAudioCaptureModule::PlayoutIsInitialized() const {
164 return play_is_initialized_;
165 }
166
RecordingIsAvailable(bool *)167 int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) {
168 RTC_NOTREACHED();
169 return 0;
170 }
171
InitRecording()172 int32_t FakeAudioCaptureModule::InitRecording() {
173 rec_is_initialized_ = true;
174 return 0;
175 }
176
RecordingIsInitialized() const177 bool FakeAudioCaptureModule::RecordingIsInitialized() const {
178 return rec_is_initialized_;
179 }
180
StartPlayout()181 int32_t FakeAudioCaptureModule::StartPlayout() {
182 if (!play_is_initialized_) {
183 return -1;
184 }
185 {
186 webrtc::MutexLock lock(&mutex_);
187 playing_ = true;
188 }
189 bool start = true;
190 UpdateProcessing(start);
191 return 0;
192 }
193
StopPlayout()194 int32_t FakeAudioCaptureModule::StopPlayout() {
195 bool start = false;
196 {
197 webrtc::MutexLock lock(&mutex_);
198 playing_ = false;
199 start = ShouldStartProcessing();
200 }
201 UpdateProcessing(start);
202 return 0;
203 }
204
Playing() const205 bool FakeAudioCaptureModule::Playing() const {
206 webrtc::MutexLock lock(&mutex_);
207 return playing_;
208 }
209
StartRecording()210 int32_t FakeAudioCaptureModule::StartRecording() {
211 if (!rec_is_initialized_) {
212 return -1;
213 }
214 {
215 webrtc::MutexLock lock(&mutex_);
216 recording_ = true;
217 }
218 bool start = true;
219 UpdateProcessing(start);
220 return 0;
221 }
222
StopRecording()223 int32_t FakeAudioCaptureModule::StopRecording() {
224 bool start = false;
225 {
226 webrtc::MutexLock lock(&mutex_);
227 recording_ = false;
228 start = ShouldStartProcessing();
229 }
230 UpdateProcessing(start);
231 return 0;
232 }
233
Recording() const234 bool FakeAudioCaptureModule::Recording() const {
235 webrtc::MutexLock lock(&mutex_);
236 return recording_;
237 }
238
InitSpeaker()239 int32_t FakeAudioCaptureModule::InitSpeaker() {
240 // No speaker, just playing from file. Return success.
241 return 0;
242 }
243
SpeakerIsInitialized() const244 bool FakeAudioCaptureModule::SpeakerIsInitialized() const {
245 RTC_NOTREACHED();
246 return 0;
247 }
248
InitMicrophone()249 int32_t FakeAudioCaptureModule::InitMicrophone() {
250 // No microphone, just playing from file. Return success.
251 return 0;
252 }
253
MicrophoneIsInitialized() const254 bool FakeAudioCaptureModule::MicrophoneIsInitialized() const {
255 RTC_NOTREACHED();
256 return 0;
257 }
258
SpeakerVolumeIsAvailable(bool *)259 int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) {
260 RTC_NOTREACHED();
261 return 0;
262 }
263
SetSpeakerVolume(uint32_t)264 int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) {
265 RTC_NOTREACHED();
266 return 0;
267 }
268
SpeakerVolume(uint32_t *) const269 int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const {
270 RTC_NOTREACHED();
271 return 0;
272 }
273
MaxSpeakerVolume(uint32_t *) const274 int32_t FakeAudioCaptureModule::MaxSpeakerVolume(
275 uint32_t* /*max_volume*/) const {
276 RTC_NOTREACHED();
277 return 0;
278 }
279
MinSpeakerVolume(uint32_t *) const280 int32_t FakeAudioCaptureModule::MinSpeakerVolume(
281 uint32_t* /*min_volume*/) const {
282 RTC_NOTREACHED();
283 return 0;
284 }
285
MicrophoneVolumeIsAvailable(bool *)286 int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable(
287 bool* /*available*/) {
288 RTC_NOTREACHED();
289 return 0;
290 }
291
SetMicrophoneVolume(uint32_t volume)292 int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) {
293 webrtc::MutexLock lock(&mutex_);
294 current_mic_level_ = volume;
295 return 0;
296 }
297
MicrophoneVolume(uint32_t * volume) const298 int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const {
299 webrtc::MutexLock lock(&mutex_);
300 *volume = current_mic_level_;
301 return 0;
302 }
303
MaxMicrophoneVolume(uint32_t * max_volume) const304 int32_t FakeAudioCaptureModule::MaxMicrophoneVolume(
305 uint32_t* max_volume) const {
306 *max_volume = kMaxVolume;
307 return 0;
308 }
309
MinMicrophoneVolume(uint32_t *) const310 int32_t FakeAudioCaptureModule::MinMicrophoneVolume(
311 uint32_t* /*min_volume*/) const {
312 RTC_NOTREACHED();
313 return 0;
314 }
315
SpeakerMuteIsAvailable(bool *)316 int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) {
317 RTC_NOTREACHED();
318 return 0;
319 }
320
SetSpeakerMute(bool)321 int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) {
322 RTC_NOTREACHED();
323 return 0;
324 }
325
SpeakerMute(bool *) const326 int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const {
327 RTC_NOTREACHED();
328 return 0;
329 }
330
MicrophoneMuteIsAvailable(bool *)331 int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) {
332 RTC_NOTREACHED();
333 return 0;
334 }
335
SetMicrophoneMute(bool)336 int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) {
337 RTC_NOTREACHED();
338 return 0;
339 }
340
MicrophoneMute(bool *) const341 int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const {
342 RTC_NOTREACHED();
343 return 0;
344 }
345
StereoPlayoutIsAvailable(bool * available) const346 int32_t FakeAudioCaptureModule::StereoPlayoutIsAvailable(
347 bool* available) const {
348 // No recording device, just dropping audio. Stereo can be dropped just
349 // as easily as mono.
350 *available = true;
351 return 0;
352 }
353
SetStereoPlayout(bool)354 int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) {
355 // No recording device, just dropping audio. Stereo can be dropped just
356 // as easily as mono.
357 return 0;
358 }
359
StereoPlayout(bool *) const360 int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const {
361 RTC_NOTREACHED();
362 return 0;
363 }
364
StereoRecordingIsAvailable(bool * available) const365 int32_t FakeAudioCaptureModule::StereoRecordingIsAvailable(
366 bool* available) const {
367 // Keep thing simple. No stereo recording.
368 *available = false;
369 return 0;
370 }
371
SetStereoRecording(bool enable)372 int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) {
373 if (!enable) {
374 return 0;
375 }
376 return -1;
377 }
378
StereoRecording(bool *) const379 int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const {
380 RTC_NOTREACHED();
381 return 0;
382 }
383
PlayoutDelay(uint16_t * delay_ms) const384 int32_t FakeAudioCaptureModule::PlayoutDelay(uint16_t* delay_ms) const {
385 // No delay since audio frames are dropped.
386 *delay_ms = 0;
387 return 0;
388 }
389
OnMessage(rtc::Message * msg)390 void FakeAudioCaptureModule::OnMessage(rtc::Message* msg) {
391 switch (msg->message_id) {
392 case MSG_START_PROCESS:
393 StartProcessP();
394 break;
395 case MSG_RUN_PROCESS:
396 ProcessFrameP();
397 break;
398 default:
399 // All existing messages should be caught. Getting here should never
400 // happen.
401 RTC_NOTREACHED();
402 }
403 }
404
Initialize()405 bool FakeAudioCaptureModule::Initialize() {
406 // Set the send buffer samples high enough that it would not occur on the
407 // remote side unless a packet containing a sample of that magnitude has been
408 // sent to it. Note that the audio processing pipeline will likely distort the
409 // original signal.
410 SetSendBuffer(kHighSampleValue);
411 return true;
412 }
413
SetSendBuffer(int value)414 void FakeAudioCaptureModule::SetSendBuffer(int value) {
415 Sample* buffer_ptr = reinterpret_cast<Sample*>(send_buffer_);
416 const size_t buffer_size_in_samples =
417 sizeof(send_buffer_) / kNumberBytesPerSample;
418 for (size_t i = 0; i < buffer_size_in_samples; ++i) {
419 buffer_ptr[i] = value;
420 }
421 }
422
ResetRecBuffer()423 void FakeAudioCaptureModule::ResetRecBuffer() {
424 memset(rec_buffer_, 0, sizeof(rec_buffer_));
425 }
426
CheckRecBuffer(int value)427 bool FakeAudioCaptureModule::CheckRecBuffer(int value) {
428 const Sample* buffer_ptr = reinterpret_cast<const Sample*>(rec_buffer_);
429 const size_t buffer_size_in_samples =
430 sizeof(rec_buffer_) / kNumberBytesPerSample;
431 for (size_t i = 0; i < buffer_size_in_samples; ++i) {
432 if (buffer_ptr[i] >= value)
433 return true;
434 }
435 return false;
436 }
437
ShouldStartProcessing()438 bool FakeAudioCaptureModule::ShouldStartProcessing() {
439 return recording_ || playing_;
440 }
441
UpdateProcessing(bool start)442 void FakeAudioCaptureModule::UpdateProcessing(bool start) {
443 if (start) {
444 if (!process_thread_) {
445 process_thread_ = rtc::Thread::Create();
446 process_thread_->Start();
447 }
448 process_thread_->Post(RTC_FROM_HERE, this, MSG_START_PROCESS);
449 } else {
450 if (process_thread_) {
451 process_thread_->Stop();
452 process_thread_.reset(nullptr);
453 process_thread_checker_.Detach();
454 }
455 webrtc::MutexLock lock(&mutex_);
456 started_ = false;
457 }
458 }
459
StartProcessP()460 void FakeAudioCaptureModule::StartProcessP() {
461 RTC_DCHECK_RUN_ON(&process_thread_checker_);
462 {
463 webrtc::MutexLock lock(&mutex_);
464 if (started_) {
465 // Already started.
466 return;
467 }
468 }
469 ProcessFrameP();
470 }
471
ProcessFrameP()472 void FakeAudioCaptureModule::ProcessFrameP() {
473 RTC_DCHECK_RUN_ON(&process_thread_checker_);
474 {
475 webrtc::MutexLock lock(&mutex_);
476 if (!started_) {
477 next_frame_time_ = rtc::TimeMillis();
478 started_ = true;
479 }
480
481 // Receive and send frames every kTimePerFrameMs.
482 if (playing_) {
483 ReceiveFrameP();
484 }
485 if (recording_) {
486 SendFrameP();
487 }
488 }
489
490 next_frame_time_ += kTimePerFrameMs;
491 const int64_t current_time = rtc::TimeMillis();
492 const int64_t wait_time =
493 (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0;
494 process_thread_->PostDelayed(RTC_FROM_HERE, wait_time, this, MSG_RUN_PROCESS);
495 }
496
ReceiveFrameP()497 void FakeAudioCaptureModule::ReceiveFrameP() {
498 RTC_DCHECK_RUN_ON(&process_thread_checker_);
499 if (!audio_callback_) {
500 return;
501 }
502 ResetRecBuffer();
503 size_t nSamplesOut = 0;
504 int64_t elapsed_time_ms = 0;
505 int64_t ntp_time_ms = 0;
506 if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample,
507 kNumberOfChannels, kSamplesPerSecond,
508 rec_buffer_, nSamplesOut,
509 &elapsed_time_ms, &ntp_time_ms) != 0) {
510 RTC_NOTREACHED();
511 }
512 RTC_CHECK(nSamplesOut == kNumberSamples);
513
514 // The SetBuffer() function ensures that after decoding, the audio buffer
515 // should contain samples of similar magnitude (there is likely to be some
516 // distortion due to the audio pipeline). If one sample is detected to
517 // have the same or greater magnitude somewhere in the frame, an actual frame
518 // has been received from the remote side (i.e. faked frames are not being
519 // pulled).
520 if (CheckRecBuffer(kHighSampleValue)) {
521 ++frames_received_;
522 }
523 }
524
SendFrameP()525 void FakeAudioCaptureModule::SendFrameP() {
526 RTC_DCHECK_RUN_ON(&process_thread_checker_);
527 if (!audio_callback_) {
528 return;
529 }
530 bool key_pressed = false;
531 uint32_t current_mic_level = current_mic_level_;
532 if (audio_callback_->RecordedDataIsAvailable(
533 send_buffer_, kNumberSamples, kNumberBytesPerSample,
534 kNumberOfChannels, kSamplesPerSecond, kTotalDelayMs, kClockDriftMs,
535 current_mic_level, key_pressed, current_mic_level) != 0) {
536 RTC_NOTREACHED();
537 }
538 current_mic_level_ = current_mic_level;
539 }
540