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 "webrtc/base/checks.h"
12 #include "webrtc/base/logging.h"
13 #include "webrtc/base/platform_thread.h"
14 #include "webrtc/modules/audio_device/dummy/file_audio_device.h"
15 #include "webrtc/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 int32_t id,const char * inputFilename,const char * outputFilename)28 FileAudioDevice::FileAudioDevice(const int32_t id,
29                                  const char* inputFilename,
30                                  const char* outputFilename):
31     _ptrAudioBuffer(NULL),
32     _recordingBuffer(NULL),
33     _playoutBuffer(NULL),
34     _recordingFramesLeft(0),
35     _playoutFramesLeft(0),
36     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
37     _recordingBufferSizeIn10MS(0),
38     _recordingFramesIn10MS(0),
39     _playoutFramesIn10MS(0),
40     _playing(false),
41     _recording(false),
42     _lastCallPlayoutMillis(0),
43     _lastCallRecordMillis(0),
44     _outputFile(*FileWrapper::Create()),
45     _inputFile(*FileWrapper::Create()),
46     _outputFilename(outputFilename),
47     _inputFilename(inputFilename) {
48 }
49 
~FileAudioDevice()50 FileAudioDevice::~FileAudioDevice() {
51   delete &_outputFile;
52   delete &_inputFile;
53 }
54 
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const55 int32_t FileAudioDevice::ActiveAudioLayer(
56     AudioDeviceModule::AudioLayer& audioLayer) const {
57   return -1;
58 }
59 
Init()60 AudioDeviceGeneric::InitStatus FileAudioDevice::Init() {
61   return InitStatus::OK;
62 }
63 
Terminate()64 int32_t FileAudioDevice::Terminate() { return 0; }
65 
Initialized() const66 bool FileAudioDevice::Initialized() const { return true; }
67 
PlayoutDevices()68 int16_t FileAudioDevice::PlayoutDevices() {
69   return 1;
70 }
71 
RecordingDevices()72 int16_t FileAudioDevice::RecordingDevices() {
73   return 1;
74 }
75 
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])76 int32_t FileAudioDevice::PlayoutDeviceName(uint16_t index,
77                                             char name[kAdmMaxDeviceNameSize],
78                                             char guid[kAdmMaxGuidSize]) {
79   const char* kName = "dummy_device";
80   const char* kGuid = "dummy_device_unique_id";
81   if (index < 1) {
82     memset(name, 0, kAdmMaxDeviceNameSize);
83     memset(guid, 0, kAdmMaxGuidSize);
84     memcpy(name, kName, strlen(kName));
85     memcpy(guid, kGuid, strlen(guid));
86     return 0;
87   }
88   return -1;
89 }
90 
RecordingDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])91 int32_t FileAudioDevice::RecordingDeviceName(uint16_t index,
92                                               char name[kAdmMaxDeviceNameSize],
93                                               char guid[kAdmMaxGuidSize]) {
94   const char* kName = "dummy_device";
95   const char* kGuid = "dummy_device_unique_id";
96   if (index < 1) {
97     memset(name, 0, kAdmMaxDeviceNameSize);
98     memset(guid, 0, kAdmMaxGuidSize);
99     memcpy(name, kName, strlen(kName));
100     memcpy(guid, kGuid, strlen(guid));
101     return 0;
102   }
103   return -1;
104 }
105 
SetPlayoutDevice(uint16_t index)106 int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) {
107   if (index == 0) {
108     _playout_index = index;
109     return 0;
110   }
111   return -1;
112 }
113 
SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device)114 int32_t FileAudioDevice::SetPlayoutDevice(
115     AudioDeviceModule::WindowsDeviceType device) {
116   return -1;
117 }
118 
SetRecordingDevice(uint16_t index)119 int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) {
120   if (index == 0) {
121     _record_index = index;
122     return _record_index;
123   }
124   return -1;
125 }
126 
SetRecordingDevice(AudioDeviceModule::WindowsDeviceType device)127 int32_t FileAudioDevice::SetRecordingDevice(
128     AudioDeviceModule::WindowsDeviceType device) {
129   return -1;
130 }
131 
PlayoutIsAvailable(bool & available)132 int32_t FileAudioDevice::PlayoutIsAvailable(bool& available) {
133   if (_playout_index == 0) {
134     available = true;
135     return _playout_index;
136   }
137   available = false;
138   return -1;
139 }
140 
InitPlayout()141 int32_t FileAudioDevice::InitPlayout() {
142   if (_ptrAudioBuffer) {
143       // Update webrtc audio buffer with the selected parameters
144       _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
145       _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
146   }
147   return 0;
148 }
149 
PlayoutIsInitialized() const150 bool FileAudioDevice::PlayoutIsInitialized() const {
151   return true;
152 }
153 
RecordingIsAvailable(bool & available)154 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
155   if (_record_index == 0) {
156     available = true;
157     return _record_index;
158   }
159   available = false;
160   return -1;
161 }
162 
InitRecording()163 int32_t FileAudioDevice::InitRecording() {
164   CriticalSectionScoped lock(&_critSect);
165 
166   if (_recording) {
167     return -1;
168   }
169 
170   _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100);
171 
172   if (_ptrAudioBuffer) {
173     _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
174     _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
175   }
176   return 0;
177 }
178 
RecordingIsInitialized() const179 bool FileAudioDevice::RecordingIsInitialized() const {
180   return _recordingFramesIn10MS != 0;
181 }
182 
StartPlayout()183 int32_t FileAudioDevice::StartPlayout() {
184   if (_playing) {
185       return 0;
186   }
187 
188   _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100);
189   _playing = true;
190   _playoutFramesLeft = 0;
191 
192   if (!_playoutBuffer) {
193       _playoutBuffer = new int8_t[kPlayoutBufferSize];
194   }
195   if (!_playoutBuffer) {
196     _playing = false;
197     return -1;
198   }
199 
200   // PLAYOUT
201   if (!_outputFilename.empty() &&
202       !_outputFile.OpenFile(_outputFilename.c_str(), false)) {
203     LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename;
204     _playing = false;
205     delete [] _playoutBuffer;
206     _playoutBuffer = NULL;
207     return -1;
208   }
209 
210   _ptrThreadPlay.reset(new rtc::PlatformThread(
211       PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
212   _ptrThreadPlay->Start();
213   _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
214 
215   LOG(LS_INFO) << "Started playout capture to output file: "
216                << _outputFilename;
217   return 0;
218 }
219 
StopPlayout()220 int32_t FileAudioDevice::StopPlayout() {
221   {
222       CriticalSectionScoped lock(&_critSect);
223       _playing = false;
224   }
225 
226   // stop playout thread first
227   if (_ptrThreadPlay) {
228       _ptrThreadPlay->Stop();
229       _ptrThreadPlay.reset();
230   }
231 
232   CriticalSectionScoped lock(&_critSect);
233 
234   _playoutFramesLeft = 0;
235   delete [] _playoutBuffer;
236   _playoutBuffer = NULL;
237   _outputFile.CloseFile();
238 
239   LOG(LS_INFO) << "Stopped playout capture to output file: "
240                << _outputFilename;
241   return 0;
242 }
243 
Playing() const244 bool FileAudioDevice::Playing() const {
245   return true;
246 }
247 
StartRecording()248 int32_t FileAudioDevice::StartRecording() {
249   _recording = true;
250 
251   // Make sure we only create the buffer once.
252   _recordingBufferSizeIn10MS = _recordingFramesIn10MS *
253                                kRecordingNumChannels *
254                                2;
255   if (!_recordingBuffer) {
256       _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
257   }
258 
259   if (!_inputFilename.empty() &&
260       !_inputFile.OpenFile(_inputFilename.c_str(), true)) {
261     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   LOG(LS_INFO) << "Started recording from input file: "
275                << _inputFilename;
276 
277   return 0;
278 }
279 
280 
StopRecording()281 int32_t FileAudioDevice::StopRecording() {
282   {
283     CriticalSectionScoped lock(&_critSect);
284     _recording = false;
285   }
286 
287   if (_ptrThreadRec) {
288       _ptrThreadRec->Stop();
289       _ptrThreadRec.reset();
290   }
291 
292   CriticalSectionScoped lock(&_critSect);
293   _recordingFramesLeft = 0;
294   if (_recordingBuffer) {
295       delete [] _recordingBuffer;
296       _recordingBuffer = NULL;
297   }
298   _inputFile.CloseFile();
299 
300   LOG(LS_INFO) << "Stopped recording from input file: "
301                << _inputFilename;
302   return 0;
303 }
304 
Recording() const305 bool FileAudioDevice::Recording() const {
306   return _recording;
307 }
308 
SetAGC(bool enable)309 int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
310 
AGC() const311 bool FileAudioDevice::AGC() const { return false; }
312 
SetWaveOutVolume(uint16_t volumeLeft,uint16_t volumeRight)313 int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
314                                            uint16_t volumeRight) {
315   return -1;
316 }
317 
WaveOutVolume(uint16_t & volumeLeft,uint16_t & volumeRight) const318 int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
319                                         uint16_t& volumeRight) const {
320   return -1;
321 }
322 
InitSpeaker()323 int32_t FileAudioDevice::InitSpeaker() { return -1; }
324 
SpeakerIsInitialized() const325 bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
326 
InitMicrophone()327 int32_t FileAudioDevice::InitMicrophone() { return 0; }
328 
MicrophoneIsInitialized() const329 bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
330 
SpeakerVolumeIsAvailable(bool & available)331 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
332   return -1;
333 }
334 
SetSpeakerVolume(uint32_t volume)335 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
336 
SpeakerVolume(uint32_t & volume) const337 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
338 
MaxSpeakerVolume(uint32_t & maxVolume) const339 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
340   return -1;
341 }
342 
MinSpeakerVolume(uint32_t & minVolume) const343 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
344   return -1;
345 }
346 
SpeakerVolumeStepSize(uint16_t & stepSize) const347 int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
348   return -1;
349 }
350 
MicrophoneVolumeIsAvailable(bool & available)351 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
352   return -1;
353 }
354 
SetMicrophoneVolume(uint32_t volume)355 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
356 
MicrophoneVolume(uint32_t & volume) const357 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
358   return -1;
359 }
360 
MaxMicrophoneVolume(uint32_t & maxVolume) const361 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
362   return -1;
363 }
364 
MinMicrophoneVolume(uint32_t & minVolume) const365 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
366   return -1;
367 }
368 
MicrophoneVolumeStepSize(uint16_t & stepSize) const369 int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
370   return -1;
371 }
372 
SpeakerMuteIsAvailable(bool & available)373 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
374 
SetSpeakerMute(bool enable)375 int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
376 
SpeakerMute(bool & enabled) const377 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
378 
MicrophoneMuteIsAvailable(bool & available)379 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
380   return -1;
381 }
382 
SetMicrophoneMute(bool enable)383 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
384 
MicrophoneMute(bool & enabled) const385 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
386 
MicrophoneBoostIsAvailable(bool & available)387 int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
388   return -1;
389 }
390 
SetMicrophoneBoost(bool enable)391 int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
392 
MicrophoneBoost(bool & enabled) const393 int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
394 
StereoPlayoutIsAvailable(bool & available)395 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
396   available = true;
397   return 0;
398 }
SetStereoPlayout(bool enable)399 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
400   return 0;
401 }
402 
StereoPlayout(bool & enabled) const403 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
404   enabled = true;
405   return 0;
406 }
407 
StereoRecordingIsAvailable(bool & available)408 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
409   available = true;
410   return 0;
411 }
412 
SetStereoRecording(bool enable)413 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
414   return 0;
415 }
416 
StereoRecording(bool & enabled) const417 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
418   enabled = true;
419   return 0;
420 }
421 
SetPlayoutBuffer(const AudioDeviceModule::BufferType type,uint16_t sizeMS)422 int32_t FileAudioDevice::SetPlayoutBuffer(
423     const AudioDeviceModule::BufferType type,
424     uint16_t sizeMS) {
425   return 0;
426 }
427 
PlayoutBuffer(AudioDeviceModule::BufferType & type,uint16_t & sizeMS) const428 int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
429                                         uint16_t& sizeMS) const {
430   type = _playBufType;
431   return 0;
432 }
433 
PlayoutDelay(uint16_t & delayMS) const434 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
435   return 0;
436 }
437 
RecordingDelay(uint16_t & delayMS) const438 int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
439 
CPULoad(uint16_t & load) const440 int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
441 
PlayoutWarning() const442 bool FileAudioDevice::PlayoutWarning() const { return false; }
443 
PlayoutError() const444 bool FileAudioDevice::PlayoutError() const { return false; }
445 
RecordingWarning() const446 bool FileAudioDevice::RecordingWarning() const { return false; }
447 
RecordingError() const448 bool FileAudioDevice::RecordingError() const { return false; }
449 
ClearPlayoutWarning()450 void FileAudioDevice::ClearPlayoutWarning() {}
451 
ClearPlayoutError()452 void FileAudioDevice::ClearPlayoutError() {}
453 
ClearRecordingWarning()454 void FileAudioDevice::ClearRecordingWarning() {}
455 
ClearRecordingError()456 void FileAudioDevice::ClearRecordingError() {}
457 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)458 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
459   CriticalSectionScoped lock(&_critSect);
460 
461   _ptrAudioBuffer = audioBuffer;
462 
463   // Inform the AudioBuffer about default settings for this implementation.
464   // Set all values to zero here since the actual settings will be done by
465   // InitPlayout and InitRecording later.
466   _ptrAudioBuffer->SetRecordingSampleRate(0);
467   _ptrAudioBuffer->SetPlayoutSampleRate(0);
468   _ptrAudioBuffer->SetRecordingChannels(0);
469   _ptrAudioBuffer->SetPlayoutChannels(0);
470 }
471 
PlayThreadFunc(void * pThis)472 bool FileAudioDevice::PlayThreadFunc(void* pThis)
473 {
474     return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
475 }
476 
RecThreadFunc(void * pThis)477 bool FileAudioDevice::RecThreadFunc(void* pThis)
478 {
479     return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
480 }
481 
PlayThreadProcess()482 bool FileAudioDevice::PlayThreadProcess()
483 {
484     if (!_playing) {
485         return false;
486     }
487     int64_t currentTime = rtc::TimeMillis();
488     _critSect.Enter();
489 
490     if (_lastCallPlayoutMillis == 0 ||
491         currentTime - _lastCallPlayoutMillis >= 10) {
492         _critSect.Leave();
493         _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
494         _critSect.Enter();
495 
496         _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
497         RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft);
498         if (_outputFile.is_open()) {
499           _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
500         }
501         _lastCallPlayoutMillis = currentTime;
502     }
503     _playoutFramesLeft = 0;
504     _critSect.Leave();
505 
506     int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
507     if (deltaTimeMillis < 10) {
508       SleepMs(10 - deltaTimeMillis);
509     }
510 
511     return true;
512 }
513 
RecThreadProcess()514 bool FileAudioDevice::RecThreadProcess()
515 {
516     if (!_recording) {
517         return false;
518     }
519 
520     int64_t currentTime = rtc::TimeMillis();
521     _critSect.Enter();
522 
523     if (_lastCallRecordMillis == 0 ||
524         currentTime - _lastCallRecordMillis >= 10) {
525       if (_inputFile.is_open()) {
526         if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
527           _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
528                                              _recordingFramesIn10MS);
529         } else {
530           _inputFile.Rewind();
531         }
532         _lastCallRecordMillis = currentTime;
533         _critSect.Leave();
534         _ptrAudioBuffer->DeliverRecordedData();
535         _critSect.Enter();
536       }
537     }
538 
539     _critSect.Leave();
540 
541     int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
542     if (deltaTimeMillis < 10) {
543       SleepMs(10 - deltaTimeMillis);
544     }
545 
546     return true;
547 }
548 
549 }  // namespace webrtc
550