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 #include "rtc_base/checks.h"
13 #include "rtc_base/logging.h"
14 #include "rtc_base/platform_thread.h"
15 #include "system_wrappers/include/sleep.h"
16 
17 namespace webrtc {
18 
19 const int kRecordingFixedSampleRate = 48000;
20 const size_t kRecordingNumChannels = 2;
21 const int kPlayoutFixedSampleRate = 48000;
22 const size_t kPlayoutNumChannels = 2;
23 const size_t kPlayoutBufferSize =
24     kPlayoutFixedSampleRate / 100 * kPlayoutNumChannels * 2;
25 const size_t kRecordingBufferSize =
26     kRecordingFixedSampleRate / 100 * kRecordingNumChannels * 2;
27 
FileAudioDevice(const char * inputFilename,const char * outputFilename)28 FileAudioDevice::FileAudioDevice(const char* inputFilename,
29                                  const char* outputFilename)
30     : _ptrAudioBuffer(NULL),
31       _recordingBuffer(NULL),
32       _playoutBuffer(NULL),
33       _recordingFramesLeft(0),
34       _playoutFramesLeft(0),
35       _recordingBufferSizeIn10MS(0),
36       _recordingFramesIn10MS(0),
37       _playoutFramesIn10MS(0),
38       _playing(false),
39       _recording(false),
40       _lastCallPlayoutMillis(0),
41       _lastCallRecordMillis(0),
42       _outputFile(*FileWrapper::Create()),
43       _inputFile(*FileWrapper::Create()),
44       _outputFilename(outputFilename),
45       _inputFilename(inputFilename) {}
46 
~FileAudioDevice()47 FileAudioDevice::~FileAudioDevice() {
48   delete &_outputFile;
49   delete &_inputFile;
50 }
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   if (_ptrAudioBuffer) {
144     // Update webrtc audio buffer with the selected parameters
145     _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
146     _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
147   }
148   return 0;
149 }
150 
PlayoutIsInitialized() const151 bool FileAudioDevice::PlayoutIsInitialized() const {
152   return true;
153 }
154 
RecordingIsAvailable(bool & available)155 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
156   if (_record_index == 0) {
157     available = true;
158     return _record_index;
159   }
160   available = false;
161   return -1;
162 }
163 
InitRecording()164 int32_t FileAudioDevice::InitRecording() {
165   rtc::CritScope lock(&_critSect);
166 
167   if (_recording) {
168     return -1;
169   }
170 
171   _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100);
172 
173   if (_ptrAudioBuffer) {
174     _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
175     _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
176   }
177   return 0;
178 }
179 
RecordingIsInitialized() const180 bool FileAudioDevice::RecordingIsInitialized() const {
181   return _recordingFramesIn10MS != 0;
182 }
183 
StartPlayout()184 int32_t FileAudioDevice::StartPlayout() {
185   if (_playing) {
186     return 0;
187   }
188 
189   _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100);
190   _playing = true;
191   _playoutFramesLeft = 0;
192 
193   if (!_playoutBuffer) {
194     _playoutBuffer = new int8_t[kPlayoutBufferSize];
195   }
196   if (!_playoutBuffer) {
197     _playing = false;
198     return -1;
199   }
200 
201   // PLAYOUT
202   if (!_outputFilename.empty() &&
203       !_outputFile.OpenFile(_outputFilename.c_str(), false)) {
204     RTC_LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename;
205     _playing = false;
206     delete[] _playoutBuffer;
207     _playoutBuffer = NULL;
208     return -1;
209   }
210 
211   _ptrThreadPlay.reset(new rtc::PlatformThread(
212       PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
213   _ptrThreadPlay->Start();
214   _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
215 
216   RTC_LOG(LS_INFO) << "Started playout capture to output file: "
217                    << _outputFilename;
218   return 0;
219 }
220 
StopPlayout()221 int32_t FileAudioDevice::StopPlayout() {
222   {
223     rtc::CritScope lock(&_critSect);
224     _playing = false;
225   }
226 
227   // stop playout thread first
228   if (_ptrThreadPlay) {
229     _ptrThreadPlay->Stop();
230     _ptrThreadPlay.reset();
231   }
232 
233   rtc::CritScope lock(&_critSect);
234 
235   _playoutFramesLeft = 0;
236   delete[] _playoutBuffer;
237   _playoutBuffer = NULL;
238   _outputFile.CloseFile();
239 
240   RTC_LOG(LS_INFO) << "Stopped playout capture to output file: "
241                    << _outputFilename;
242   return 0;
243 }
244 
Playing() const245 bool FileAudioDevice::Playing() const {
246   return true;
247 }
248 
StartRecording()249 int32_t FileAudioDevice::StartRecording() {
250   _recording = true;
251 
252   // Make sure we only create the buffer once.
253   _recordingBufferSizeIn10MS =
254       _recordingFramesIn10MS * kRecordingNumChannels * 2;
255   if (!_recordingBuffer) {
256     _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
257   }
258 
259   if (!_inputFilename.empty() &&
260       !_inputFile.OpenFile(_inputFilename.c_str(), true)) {
261     RTC_LOG(LS_ERROR) << "Failed to open audio input file: " << _inputFilename;
262     _recording = false;
263     delete[] _recordingBuffer;
264     _recordingBuffer = NULL;
265     return -1;
266   }
267 
268   _ptrThreadRec.reset(new rtc::PlatformThread(
269       RecThreadFunc, this, "webrtc_audio_module_capture_thread"));
270 
271   _ptrThreadRec->Start();
272   _ptrThreadRec->SetPriority(rtc::kRealtimePriority);
273 
274   RTC_LOG(LS_INFO) << "Started recording from input file: " << _inputFilename;
275 
276   return 0;
277 }
278 
StopRecording()279 int32_t FileAudioDevice::StopRecording() {
280   {
281     rtc::CritScope lock(&_critSect);
282     _recording = false;
283   }
284 
285   if (_ptrThreadRec) {
286     _ptrThreadRec->Stop();
287     _ptrThreadRec.reset();
288   }
289 
290   rtc::CritScope lock(&_critSect);
291   _recordingFramesLeft = 0;
292   if (_recordingBuffer) {
293     delete[] _recordingBuffer;
294     _recordingBuffer = NULL;
295   }
296   _inputFile.CloseFile();
297 
298   RTC_LOG(LS_INFO) << "Stopped recording from input file: " << _inputFilename;
299   return 0;
300 }
301 
Recording() const302 bool FileAudioDevice::Recording() const {
303   return _recording;
304 }
305 
SetAGC(bool enable)306 int32_t FileAudioDevice::SetAGC(bool enable) {
307   return -1;
308 }
309 
AGC() const310 bool FileAudioDevice::AGC() const {
311   return false;
312 }
313 
InitSpeaker()314 int32_t FileAudioDevice::InitSpeaker() {
315   return -1;
316 }
317 
SpeakerIsInitialized() const318 bool FileAudioDevice::SpeakerIsInitialized() const {
319   return false;
320 }
321 
InitMicrophone()322 int32_t FileAudioDevice::InitMicrophone() {
323   return 0;
324 }
325 
MicrophoneIsInitialized() const326 bool FileAudioDevice::MicrophoneIsInitialized() const {
327   return true;
328 }
329 
SpeakerVolumeIsAvailable(bool & available)330 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
331   return -1;
332 }
333 
SetSpeakerVolume(uint32_t volume)334 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) {
335   return -1;
336 }
337 
SpeakerVolume(uint32_t & volume) const338 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const {
339   return -1;
340 }
341 
MaxSpeakerVolume(uint32_t & maxVolume) const342 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
343   return -1;
344 }
345 
MinSpeakerVolume(uint32_t & minVolume) const346 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
347   return -1;
348 }
349 
MicrophoneVolumeIsAvailable(bool & available)350 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
351   return -1;
352 }
353 
SetMicrophoneVolume(uint32_t volume)354 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) {
355   return -1;
356 }
357 
MicrophoneVolume(uint32_t & volume) const358 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
359   return -1;
360 }
361 
MaxMicrophoneVolume(uint32_t & maxVolume) const362 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
363   return -1;
364 }
365 
MinMicrophoneVolume(uint32_t & minVolume) const366 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
367   return -1;
368 }
369 
SpeakerMuteIsAvailable(bool & available)370 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) {
371   return -1;
372 }
373 
SetSpeakerMute(bool enable)374 int32_t FileAudioDevice::SetSpeakerMute(bool enable) {
375   return -1;
376 }
377 
SpeakerMute(bool & enabled) const378 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const {
379   return -1;
380 }
381 
MicrophoneMuteIsAvailable(bool & available)382 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
383   return -1;
384 }
385 
SetMicrophoneMute(bool enable)386 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) {
387   return -1;
388 }
389 
MicrophoneMute(bool & enabled) const390 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const {
391   return -1;
392 }
393 
StereoPlayoutIsAvailable(bool & available)394 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
395   available = true;
396   return 0;
397 }
SetStereoPlayout(bool enable)398 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
399   return 0;
400 }
401 
StereoPlayout(bool & enabled) const402 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
403   enabled = true;
404   return 0;
405 }
406 
StereoRecordingIsAvailable(bool & available)407 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
408   available = true;
409   return 0;
410 }
411 
SetStereoRecording(bool enable)412 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
413   return 0;
414 }
415 
StereoRecording(bool & enabled) const416 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
417   enabled = true;
418   return 0;
419 }
420 
PlayoutDelay(uint16_t & delayMS) const421 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
422   return 0;
423 }
424 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)425 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
426   rtc::CritScope lock(&_critSect);
427 
428   _ptrAudioBuffer = audioBuffer;
429 
430   // Inform the AudioBuffer about default settings for this implementation.
431   // Set all values to zero here since the actual settings will be done by
432   // InitPlayout and InitRecording later.
433   _ptrAudioBuffer->SetRecordingSampleRate(0);
434   _ptrAudioBuffer->SetPlayoutSampleRate(0);
435   _ptrAudioBuffer->SetRecordingChannels(0);
436   _ptrAudioBuffer->SetPlayoutChannels(0);
437 }
438 
PlayThreadFunc(void * pThis)439 bool FileAudioDevice::PlayThreadFunc(void* pThis) {
440   return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
441 }
442 
RecThreadFunc(void * pThis)443 bool FileAudioDevice::RecThreadFunc(void* pThis) {
444   return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
445 }
446 
PlayThreadProcess()447 bool FileAudioDevice::PlayThreadProcess() {
448   if (!_playing) {
449     return false;
450   }
451   int64_t currentTime = rtc::TimeMillis();
452   _critSect.Enter();
453 
454   if (_lastCallPlayoutMillis == 0 ||
455       currentTime - _lastCallPlayoutMillis >= 10) {
456     _critSect.Leave();
457     _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
458     _critSect.Enter();
459 
460     _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
461     RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft);
462     if (_outputFile.is_open()) {
463       _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
464     }
465     _lastCallPlayoutMillis = currentTime;
466   }
467   _playoutFramesLeft = 0;
468   _critSect.Leave();
469 
470   int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
471   if (deltaTimeMillis < 10) {
472     SleepMs(10 - deltaTimeMillis);
473   }
474 
475   return true;
476 }
477 
RecThreadProcess()478 bool FileAudioDevice::RecThreadProcess() {
479   if (!_recording) {
480     return false;
481   }
482 
483   int64_t currentTime = rtc::TimeMillis();
484   _critSect.Enter();
485 
486   if (_lastCallRecordMillis == 0 || currentTime - _lastCallRecordMillis >= 10) {
487     if (_inputFile.is_open()) {
488       if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
489         _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
490                                            _recordingFramesIn10MS);
491       } else {
492         _inputFile.Rewind();
493       }
494       _lastCallRecordMillis = currentTime;
495       _critSect.Leave();
496       _ptrAudioBuffer->DeliverRecordedData();
497       _critSect.Enter();
498     }
499   }
500 
501   _critSect.Leave();
502 
503   int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
504   if (deltaTimeMillis < 10) {
505     SleepMs(10 - deltaTimeMillis);
506   }
507 
508   return true;
509 }
510 
511 }  // namespace webrtc
512