xref: /aosp_15_r20/external/webrtc/modules/audio_device/dummy/file_audio_device.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2014 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 "modules/audio_device/dummy/file_audio_device.h"
12 
13 #include <string.h>
14 
15 #include "absl/strings/string_view.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/logging.h"
18 #include "rtc_base/platform_thread.h"
19 #include "rtc_base/time_utils.h"
20 #include "system_wrappers/include/sleep.h"
21 
22 namespace webrtc {
23 
24 const int kRecordingFixedSampleRate = 48000;
25 const size_t kRecordingNumChannels = 2;
26 const int kPlayoutFixedSampleRate = 48000;
27 const size_t kPlayoutNumChannels = 2;
28 const size_t kPlayoutBufferSize =
29     kPlayoutFixedSampleRate / 100 * kPlayoutNumChannels * 2;
30 const size_t kRecordingBufferSize =
31     kRecordingFixedSampleRate / 100 * kRecordingNumChannels * 2;
32 
FileAudioDevice(absl::string_view inputFilename,absl::string_view outputFilename)33 FileAudioDevice::FileAudioDevice(absl::string_view inputFilename,
34                                  absl::string_view outputFilename)
35     : _ptrAudioBuffer(NULL),
36       _recordingBuffer(NULL),
37       _playoutBuffer(NULL),
38       _recordingFramesLeft(0),
39       _playoutFramesLeft(0),
40       _recordingBufferSizeIn10MS(0),
41       _recordingFramesIn10MS(0),
42       _playoutFramesIn10MS(0),
43       _playing(false),
44       _recording(false),
45       _lastCallPlayoutMillis(0),
46       _lastCallRecordMillis(0),
47       _outputFilename(outputFilename),
48       _inputFilename(inputFilename) {}
49 
~FileAudioDevice()50 FileAudioDevice::~FileAudioDevice() {}
51 
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const52 int32_t FileAudioDevice::ActiveAudioLayer(
53     AudioDeviceModule::AudioLayer& audioLayer) const {
54   return -1;
55 }
56 
Init()57 AudioDeviceGeneric::InitStatus FileAudioDevice::Init() {
58   return InitStatus::OK;
59 }
60 
Terminate()61 int32_t FileAudioDevice::Terminate() {
62   return 0;
63 }
64 
Initialized() const65 bool FileAudioDevice::Initialized() const {
66   return true;
67 }
68 
PlayoutDevices()69 int16_t FileAudioDevice::PlayoutDevices() {
70   return 1;
71 }
72 
RecordingDevices()73 int16_t FileAudioDevice::RecordingDevices() {
74   return 1;
75 }
76 
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])77 int32_t FileAudioDevice::PlayoutDeviceName(uint16_t index,
78                                            char name[kAdmMaxDeviceNameSize],
79                                            char guid[kAdmMaxGuidSize]) {
80   const char* kName = "dummy_device";
81   const char* kGuid = "dummy_device_unique_id";
82   if (index < 1) {
83     memset(name, 0, kAdmMaxDeviceNameSize);
84     memset(guid, 0, kAdmMaxGuidSize);
85     memcpy(name, kName, strlen(kName));
86     memcpy(guid, kGuid, strlen(guid));
87     return 0;
88   }
89   return -1;
90 }
91 
RecordingDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])92 int32_t FileAudioDevice::RecordingDeviceName(uint16_t index,
93                                              char name[kAdmMaxDeviceNameSize],
94                                              char guid[kAdmMaxGuidSize]) {
95   const char* kName = "dummy_device";
96   const char* kGuid = "dummy_device_unique_id";
97   if (index < 1) {
98     memset(name, 0, kAdmMaxDeviceNameSize);
99     memset(guid, 0, kAdmMaxGuidSize);
100     memcpy(name, kName, strlen(kName));
101     memcpy(guid, kGuid, strlen(guid));
102     return 0;
103   }
104   return -1;
105 }
106 
SetPlayoutDevice(uint16_t index)107 int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) {
108   if (index == 0) {
109     _playout_index = index;
110     return 0;
111   }
112   return -1;
113 }
114 
SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device)115 int32_t FileAudioDevice::SetPlayoutDevice(
116     AudioDeviceModule::WindowsDeviceType device) {
117   return -1;
118 }
119 
SetRecordingDevice(uint16_t index)120 int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) {
121   if (index == 0) {
122     _record_index = index;
123     return _record_index;
124   }
125   return -1;
126 }
127 
SetRecordingDevice(AudioDeviceModule::WindowsDeviceType device)128 int32_t FileAudioDevice::SetRecordingDevice(
129     AudioDeviceModule::WindowsDeviceType device) {
130   return -1;
131 }
132 
PlayoutIsAvailable(bool & available)133 int32_t FileAudioDevice::PlayoutIsAvailable(bool& available) {
134   if (_playout_index == 0) {
135     available = true;
136     return _playout_index;
137   }
138   available = false;
139   return -1;
140 }
141 
InitPlayout()142 int32_t FileAudioDevice::InitPlayout() {
143   MutexLock lock(&mutex_);
144 
145   if (_playing) {
146     return -1;
147   }
148 
149   _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100);
150 
151   if (_ptrAudioBuffer) {
152     // Update webrtc audio buffer with the selected parameters
153     _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
154     _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
155   }
156   return 0;
157 }
158 
PlayoutIsInitialized() const159 bool FileAudioDevice::PlayoutIsInitialized() const {
160   return _playoutFramesIn10MS != 0;
161 }
162 
RecordingIsAvailable(bool & available)163 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
164   if (_record_index == 0) {
165     available = true;
166     return _record_index;
167   }
168   available = false;
169   return -1;
170 }
171 
InitRecording()172 int32_t FileAudioDevice::InitRecording() {
173   MutexLock lock(&mutex_);
174 
175   if (_recording) {
176     return -1;
177   }
178 
179   _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100);
180 
181   if (_ptrAudioBuffer) {
182     _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
183     _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
184   }
185   return 0;
186 }
187 
RecordingIsInitialized() const188 bool FileAudioDevice::RecordingIsInitialized() const {
189   return _recordingFramesIn10MS != 0;
190 }
191 
StartPlayout()192 int32_t FileAudioDevice::StartPlayout() {
193   if (_playing) {
194     return 0;
195   }
196 
197   _playing = true;
198   _playoutFramesLeft = 0;
199 
200   if (!_playoutBuffer) {
201     _playoutBuffer = new int8_t[kPlayoutBufferSize];
202   }
203   if (!_playoutBuffer) {
204     _playing = false;
205     return -1;
206   }
207 
208   // PLAYOUT
209   if (!_outputFilename.empty()) {
210     _outputFile = FileWrapper::OpenWriteOnly(_outputFilename);
211     if (!_outputFile.is_open()) {
212       RTC_LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename;
213       _playing = false;
214       delete[] _playoutBuffer;
215       _playoutBuffer = NULL;
216       return -1;
217     }
218   }
219 
220   _ptrThreadPlay = rtc::PlatformThread::SpawnJoinable(
221       [this] {
222         while (PlayThreadProcess()) {
223         }
224       },
225       "webrtc_audio_module_play_thread",
226       rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kRealtime));
227 
228   RTC_LOG(LS_INFO) << "Started playout capture to output file: "
229                    << _outputFilename;
230   return 0;
231 }
232 
StopPlayout()233 int32_t FileAudioDevice::StopPlayout() {
234   {
235     MutexLock lock(&mutex_);
236     _playing = false;
237   }
238 
239   // stop playout thread first
240   if (!_ptrThreadPlay.empty())
241     _ptrThreadPlay.Finalize();
242 
243   MutexLock lock(&mutex_);
244 
245   _playoutFramesLeft = 0;
246   delete[] _playoutBuffer;
247   _playoutBuffer = NULL;
248   _outputFile.Close();
249 
250   RTC_LOG(LS_INFO) << "Stopped playout capture to output file: "
251                    << _outputFilename;
252   return 0;
253 }
254 
Playing() const255 bool FileAudioDevice::Playing() const {
256   return _playing;
257 }
258 
StartRecording()259 int32_t FileAudioDevice::StartRecording() {
260   _recording = true;
261 
262   // Make sure we only create the buffer once.
263   _recordingBufferSizeIn10MS =
264       _recordingFramesIn10MS * kRecordingNumChannels * 2;
265   if (!_recordingBuffer) {
266     _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
267   }
268 
269   if (!_inputFilename.empty()) {
270     _inputFile = FileWrapper::OpenReadOnly(_inputFilename);
271     if (!_inputFile.is_open()) {
272       RTC_LOG(LS_ERROR) << "Failed to open audio input file: "
273                         << _inputFilename;
274       _recording = false;
275       delete[] _recordingBuffer;
276       _recordingBuffer = NULL;
277       return -1;
278     }
279   }
280 
281   _ptrThreadRec = rtc::PlatformThread::SpawnJoinable(
282       [this] {
283         while (RecThreadProcess()) {
284         }
285       },
286       "webrtc_audio_module_capture_thread",
287       rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kRealtime));
288 
289   RTC_LOG(LS_INFO) << "Started recording from input file: " << _inputFilename;
290 
291   return 0;
292 }
293 
StopRecording()294 int32_t FileAudioDevice::StopRecording() {
295   {
296     MutexLock lock(&mutex_);
297     _recording = false;
298   }
299 
300   if (!_ptrThreadRec.empty())
301     _ptrThreadRec.Finalize();
302 
303   MutexLock lock(&mutex_);
304   _recordingFramesLeft = 0;
305   if (_recordingBuffer) {
306     delete[] _recordingBuffer;
307     _recordingBuffer = NULL;
308   }
309   _inputFile.Close();
310 
311   RTC_LOG(LS_INFO) << "Stopped recording from input file: " << _inputFilename;
312   return 0;
313 }
314 
Recording() const315 bool FileAudioDevice::Recording() const {
316   return _recording;
317 }
318 
InitSpeaker()319 int32_t FileAudioDevice::InitSpeaker() {
320   return -1;
321 }
322 
SpeakerIsInitialized() const323 bool FileAudioDevice::SpeakerIsInitialized() const {
324   return false;
325 }
326 
InitMicrophone()327 int32_t FileAudioDevice::InitMicrophone() {
328   return 0;
329 }
330 
MicrophoneIsInitialized() const331 bool FileAudioDevice::MicrophoneIsInitialized() const {
332   return true;
333 }
334 
SpeakerVolumeIsAvailable(bool & available)335 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
336   return -1;
337 }
338 
SetSpeakerVolume(uint32_t volume)339 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) {
340   return -1;
341 }
342 
SpeakerVolume(uint32_t & volume) const343 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const {
344   return -1;
345 }
346 
MaxSpeakerVolume(uint32_t & maxVolume) const347 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
348   return -1;
349 }
350 
MinSpeakerVolume(uint32_t & minVolume) const351 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
352   return -1;
353 }
354 
MicrophoneVolumeIsAvailable(bool & available)355 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
356   return -1;
357 }
358 
SetMicrophoneVolume(uint32_t volume)359 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) {
360   return -1;
361 }
362 
MicrophoneVolume(uint32_t & volume) const363 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
364   return -1;
365 }
366 
MaxMicrophoneVolume(uint32_t & maxVolume) const367 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
368   return -1;
369 }
370 
MinMicrophoneVolume(uint32_t & minVolume) const371 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
372   return -1;
373 }
374 
SpeakerMuteIsAvailable(bool & available)375 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) {
376   return -1;
377 }
378 
SetSpeakerMute(bool enable)379 int32_t FileAudioDevice::SetSpeakerMute(bool enable) {
380   return -1;
381 }
382 
SpeakerMute(bool & enabled) const383 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const {
384   return -1;
385 }
386 
MicrophoneMuteIsAvailable(bool & available)387 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
388   return -1;
389 }
390 
SetMicrophoneMute(bool enable)391 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) {
392   return -1;
393 }
394 
MicrophoneMute(bool & enabled) const395 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const {
396   return -1;
397 }
398 
StereoPlayoutIsAvailable(bool & available)399 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
400   available = true;
401   return 0;
402 }
SetStereoPlayout(bool enable)403 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
404   return 0;
405 }
406 
StereoPlayout(bool & enabled) const407 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
408   enabled = true;
409   return 0;
410 }
411 
StereoRecordingIsAvailable(bool & available)412 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
413   available = true;
414   return 0;
415 }
416 
SetStereoRecording(bool enable)417 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
418   return 0;
419 }
420 
StereoRecording(bool & enabled) const421 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
422   enabled = true;
423   return 0;
424 }
425 
PlayoutDelay(uint16_t & delayMS) const426 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
427   return 0;
428 }
429 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)430 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
431   MutexLock lock(&mutex_);
432 
433   _ptrAudioBuffer = audioBuffer;
434 
435   // Inform the AudioBuffer about default settings for this implementation.
436   // Set all values to zero here since the actual settings will be done by
437   // InitPlayout and InitRecording later.
438   _ptrAudioBuffer->SetRecordingSampleRate(0);
439   _ptrAudioBuffer->SetPlayoutSampleRate(0);
440   _ptrAudioBuffer->SetRecordingChannels(0);
441   _ptrAudioBuffer->SetPlayoutChannels(0);
442 }
443 
PlayThreadProcess()444 bool FileAudioDevice::PlayThreadProcess() {
445   if (!_playing) {
446     return false;
447   }
448   int64_t currentTime = rtc::TimeMillis();
449   mutex_.Lock();
450 
451   if (_lastCallPlayoutMillis == 0 ||
452       currentTime - _lastCallPlayoutMillis >= 10) {
453     mutex_.Unlock();
454     _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
455     mutex_.Lock();
456 
457     _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
458     RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft);
459     if (_outputFile.is_open()) {
460       _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
461     }
462     _lastCallPlayoutMillis = currentTime;
463   }
464   _playoutFramesLeft = 0;
465   mutex_.Unlock();
466 
467   int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
468   if (deltaTimeMillis < 10) {
469     SleepMs(10 - deltaTimeMillis);
470   }
471 
472   return true;
473 }
474 
RecThreadProcess()475 bool FileAudioDevice::RecThreadProcess() {
476   if (!_recording) {
477     return false;
478   }
479 
480   int64_t currentTime = rtc::TimeMillis();
481   mutex_.Lock();
482 
483   if (_lastCallRecordMillis == 0 || currentTime - _lastCallRecordMillis >= 10) {
484     if (_inputFile.is_open()) {
485       if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
486         _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
487                                            _recordingFramesIn10MS);
488       } else {
489         _inputFile.Rewind();
490       }
491       _lastCallRecordMillis = currentTime;
492       mutex_.Unlock();
493       _ptrAudioBuffer->DeliverRecordedData();
494       mutex_.Lock();
495     }
496   }
497 
498   mutex_.Unlock();
499 
500   int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
501   if (deltaTimeMillis < 10) {
502     SleepMs(10 - deltaTimeMillis);
503   }
504 
505   return true;
506 }
507 
508 }  // namespace webrtc
509