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