• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <iostream>
11 #include "webrtc/modules/audio_device/dummy/file_audio_device.h"
12 #include "webrtc/system_wrappers/interface/sleep.h"
13 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
14 
15 namespace webrtc {
16 
17 int kRecordingFixedSampleRate = 48000;
18 int kRecordingNumChannels = 2;
19 int kPlayoutFixedSampleRate = 48000;
20 int kPlayoutNumChannels = 2;
21 int kPlayoutBufferSize = kPlayoutFixedSampleRate / 100
22                          * kPlayoutNumChannels * 2;
23 int kRecordingBufferSize = kRecordingFixedSampleRate / 100
24                            * kRecordingNumChannels * 2;
25 
FileAudioDevice(const int32_t id,const char * inputFilename,const char * outputFile)26 FileAudioDevice::FileAudioDevice(const int32_t id,
27                                  const char* inputFilename,
28                                  const char* outputFile):
29     _ptrAudioBuffer(NULL),
30     _recordingBuffer(NULL),
31     _playoutBuffer(NULL),
32     _recordingFramesLeft(0),
33     _playoutFramesLeft(0),
34     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
35     _recordingBufferSizeIn10MS(0),
36     _recordingFramesIn10MS(0),
37     _playoutFramesIn10MS(0),
38     _ptrThreadRec(NULL),
39     _ptrThreadPlay(NULL),
40     _recThreadID(0),
41     _playThreadID(0),
42     _playing(false),
43     _recording(false),
44     _lastCallPlayoutMillis(0),
45     _lastCallRecordMillis(0),
46     _outputFile(*FileWrapper::Create()),
47     _inputFile(*FileWrapper::Create()),
48     _outputFilename(outputFile),
49     _inputFilename(inputFilename),
50     _clock(Clock::GetRealTimeClock()) {
51 }
52 
~FileAudioDevice()53 FileAudioDevice::~FileAudioDevice() {
54   _outputFile.Flush();
55   _outputFile.CloseFile();
56   delete &_outputFile;
57   _inputFile.Flush();
58   _inputFile.CloseFile();
59   delete &_inputFile;
60 }
61 
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const62 int32_t FileAudioDevice::ActiveAudioLayer(
63     AudioDeviceModule::AudioLayer& audioLayer) const {
64   return -1;
65 }
66 
Init()67 int32_t FileAudioDevice::Init() { return 0; }
68 
Terminate()69 int32_t FileAudioDevice::Terminate() { return 0; }
70 
Initialized() const71 bool FileAudioDevice::Initialized() const { return true; }
72 
PlayoutDevices()73 int16_t FileAudioDevice::PlayoutDevices() {
74   return 1;
75 }
76 
RecordingDevices()77 int16_t FileAudioDevice::RecordingDevices() {
78   return 1;
79 }
80 
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])81 int32_t FileAudioDevice::PlayoutDeviceName(uint16_t index,
82                                             char name[kAdmMaxDeviceNameSize],
83                                             char guid[kAdmMaxGuidSize]) {
84   const char* kName = "dummy_device";
85   const char* kGuid = "dummy_device_unique_id";
86   if (index < 1) {
87     memset(name, 0, kAdmMaxDeviceNameSize);
88     memset(guid, 0, kAdmMaxGuidSize);
89     memcpy(name, kName, strlen(kName));
90     memcpy(guid, kGuid, strlen(guid));
91     return 0;
92   }
93   return -1;
94 }
95 
RecordingDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])96 int32_t FileAudioDevice::RecordingDeviceName(uint16_t index,
97                                               char name[kAdmMaxDeviceNameSize],
98                                               char guid[kAdmMaxGuidSize]) {
99   const char* kName = "dummy_device";
100   const char* kGuid = "dummy_device_unique_id";
101   if (index < 1) {
102     memset(name, 0, kAdmMaxDeviceNameSize);
103     memset(guid, 0, kAdmMaxGuidSize);
104     memcpy(name, kName, strlen(kName));
105     memcpy(guid, kGuid, strlen(guid));
106     return 0;
107   }
108   return -1;
109 }
110 
SetPlayoutDevice(uint16_t index)111 int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) {
112   if (index == 0) {
113     _playout_index = index;
114     return 0;
115   }
116   return -1;
117 }
118 
SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device)119 int32_t FileAudioDevice::SetPlayoutDevice(
120     AudioDeviceModule::WindowsDeviceType device) {
121   return -1;
122 }
123 
SetRecordingDevice(uint16_t index)124 int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) {
125   if (index == 0) {
126     _record_index = index;
127     return _record_index;
128   }
129   return -1;
130 }
131 
SetRecordingDevice(AudioDeviceModule::WindowsDeviceType device)132 int32_t FileAudioDevice::SetRecordingDevice(
133     AudioDeviceModule::WindowsDeviceType device) {
134   return -1;
135 }
136 
PlayoutIsAvailable(bool & available)137 int32_t FileAudioDevice::PlayoutIsAvailable(bool& available) {
138   if (_playout_index == 0) {
139     available = true;
140     return _playout_index;
141   }
142   available = false;
143   return -1;
144 }
145 
InitPlayout()146 int32_t FileAudioDevice::InitPlayout() {
147   if (_ptrAudioBuffer)
148   {
149       // Update webrtc audio buffer with the selected parameters
150       _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
151       _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
152   }
153   return 0;
154 }
155 
PlayoutIsInitialized() const156 bool FileAudioDevice::PlayoutIsInitialized() const {
157   return true;
158 }
159 
RecordingIsAvailable(bool & available)160 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
161   if (_record_index == 0) {
162     available = true;
163     return _record_index;
164   }
165   available = false;
166   return -1;
167 }
168 
InitRecording()169 int32_t FileAudioDevice::InitRecording() {
170   CriticalSectionScoped lock(&_critSect);
171 
172   if (_recording) {
173     return -1;
174   }
175 
176   _recordingFramesIn10MS = kRecordingFixedSampleRate/100;
177 
178   if (_ptrAudioBuffer) {
179     _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
180     _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
181   }
182   return 0;
183 }
184 
RecordingIsInitialized() const185 bool FileAudioDevice::RecordingIsInitialized() const {
186   return true;
187 }
188 
StartPlayout()189 int32_t FileAudioDevice::StartPlayout() {
190   if (_playing)
191   {
192       return 0;
193   }
194 
195   _playing = true;
196   _playoutFramesLeft = 0;
197 
198   if (!_playoutBuffer)
199       _playoutBuffer = new int8_t[2 *
200                                   kPlayoutNumChannels *
201                                   kPlayoutFixedSampleRate/100];
202   if (!_playoutBuffer)
203   {
204     _playing = false;
205     return -1;
206   }
207 
208   // PLAYOUT
209   const char* threadName = "webrtc_audio_module_play_thread";
210   _ptrThreadPlay =  ThreadWrapper::CreateThread(PlayThreadFunc,
211                                                 this,
212                                                 kRealtimePriority,
213                                                 threadName);
214   if (_ptrThreadPlay == NULL)
215   {
216       _playing = false;
217       delete [] _playoutBuffer;
218       _playoutBuffer = NULL;
219       return -1;
220   }
221 
222   if (_outputFile.OpenFile(_outputFilename.c_str(),
223                            false, false, false) == -1) {
224     printf("Failed to open playout file %s!", _outputFilename.c_str());
225     _playing = false;
226     delete [] _playoutBuffer;
227     _playoutBuffer = NULL;
228     return -1;
229   }
230 
231   unsigned int threadID(0);
232   if (!_ptrThreadPlay->Start(threadID))
233   {
234       _playing = false;
235       delete _ptrThreadPlay;
236       _ptrThreadPlay = NULL;
237       delete [] _playoutBuffer;
238       _playoutBuffer = NULL;
239       return -1;
240   }
241   _playThreadID = threadID;
242 
243   return 0;
244 }
245 
StopPlayout()246 int32_t FileAudioDevice::StopPlayout() {
247   {
248       CriticalSectionScoped lock(&_critSect);
249       _playing = false;
250   }
251 
252   // stop playout thread first
253   if (_ptrThreadPlay && !_ptrThreadPlay->Stop())
254   {
255       return -1;
256   }
257   else {
258       delete _ptrThreadPlay;
259       _ptrThreadPlay = NULL;
260   }
261 
262   CriticalSectionScoped lock(&_critSect);
263 
264   _playoutFramesLeft = 0;
265   delete [] _playoutBuffer;
266   _playoutBuffer = NULL;
267   _outputFile.Flush();
268   _outputFile.CloseFile();
269    return 0;
270 }
271 
Playing() const272 bool FileAudioDevice::Playing() const {
273   return true;
274 }
275 
StartRecording()276 int32_t FileAudioDevice::StartRecording() {
277   _recording = true;
278 
279   // Make sure we only create the buffer once.
280   _recordingBufferSizeIn10MS = _recordingFramesIn10MS *
281                                kRecordingNumChannels *
282                                2;
283   if (!_recordingBuffer) {
284       _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
285   }
286 
287   if (_inputFile.OpenFile(_inputFilename.c_str(), true,
288                               true, false) == -1) {
289     printf("Failed to open audio input file %s!\n",
290            _inputFilename.c_str());
291     _recording = false;
292     delete[] _recordingBuffer;
293     _recordingBuffer = NULL;
294     return -1;
295   }
296 
297   const char* threadName = "webrtc_audio_module_capture_thread";
298   _ptrThreadRec = ThreadWrapper::CreateThread(RecThreadFunc,
299                                               this,
300                                               kRealtimePriority,
301                                               threadName);
302   if (_ptrThreadRec == NULL)
303   {
304       _recording = false;
305       delete [] _recordingBuffer;
306       _recordingBuffer = NULL;
307       return -1;
308   }
309 
310   unsigned int threadID(0);
311   if (!_ptrThreadRec->Start(threadID))
312   {
313       _recording = false;
314       delete _ptrThreadRec;
315       _ptrThreadRec = NULL;
316       delete [] _recordingBuffer;
317       _recordingBuffer = NULL;
318       return -1;
319   }
320   _recThreadID = threadID;
321 
322   return 0;
323 }
324 
325 
StopRecording()326 int32_t FileAudioDevice::StopRecording() {
327   {
328     CriticalSectionScoped lock(&_critSect);
329     _recording = false;
330   }
331 
332   if (_ptrThreadRec && !_ptrThreadRec->Stop())
333   {
334       return -1;
335   }
336   else {
337       delete _ptrThreadRec;
338       _ptrThreadRec = NULL;
339   }
340 
341   CriticalSectionScoped lock(&_critSect);
342   _recordingFramesLeft = 0;
343   if (_recordingBuffer)
344   {
345       delete [] _recordingBuffer;
346       _recordingBuffer = NULL;
347   }
348   return 0;
349 }
350 
Recording() const351 bool FileAudioDevice::Recording() const {
352   return _recording;
353 }
354 
SetAGC(bool enable)355 int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
356 
AGC() const357 bool FileAudioDevice::AGC() const { return false; }
358 
SetWaveOutVolume(uint16_t volumeLeft,uint16_t volumeRight)359 int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
360                                            uint16_t volumeRight) {
361   return -1;
362 }
363 
WaveOutVolume(uint16_t & volumeLeft,uint16_t & volumeRight) const364 int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
365                                         uint16_t& volumeRight) const {
366   return -1;
367 }
368 
InitSpeaker()369 int32_t FileAudioDevice::InitSpeaker() { return -1; }
370 
SpeakerIsInitialized() const371 bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
372 
InitMicrophone()373 int32_t FileAudioDevice::InitMicrophone() { return 0; }
374 
MicrophoneIsInitialized() const375 bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
376 
SpeakerVolumeIsAvailable(bool & available)377 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
378   return -1;
379 }
380 
SetSpeakerVolume(uint32_t volume)381 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
382 
SpeakerVolume(uint32_t & volume) const383 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
384 
MaxSpeakerVolume(uint32_t & maxVolume) const385 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
386   return -1;
387 }
388 
MinSpeakerVolume(uint32_t & minVolume) const389 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
390   return -1;
391 }
392 
SpeakerVolumeStepSize(uint16_t & stepSize) const393 int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
394   return -1;
395 }
396 
MicrophoneVolumeIsAvailable(bool & available)397 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
398   return -1;
399 }
400 
SetMicrophoneVolume(uint32_t volume)401 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
402 
MicrophoneVolume(uint32_t & volume) const403 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
404   return -1;
405 }
406 
MaxMicrophoneVolume(uint32_t & maxVolume) const407 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
408   return -1;
409 }
410 
MinMicrophoneVolume(uint32_t & minVolume) const411 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
412   return -1;
413 }
414 
MicrophoneVolumeStepSize(uint16_t & stepSize) const415 int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
416   return -1;
417 }
418 
SpeakerMuteIsAvailable(bool & available)419 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
420 
SetSpeakerMute(bool enable)421 int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
422 
SpeakerMute(bool & enabled) const423 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
424 
MicrophoneMuteIsAvailable(bool & available)425 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
426   return -1;
427 }
428 
SetMicrophoneMute(bool enable)429 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
430 
MicrophoneMute(bool & enabled) const431 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
432 
MicrophoneBoostIsAvailable(bool & available)433 int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
434   return -1;
435 }
436 
SetMicrophoneBoost(bool enable)437 int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
438 
MicrophoneBoost(bool & enabled) const439 int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
440 
StereoPlayoutIsAvailable(bool & available)441 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
442   available = true;
443   return 0;
444 }
SetStereoPlayout(bool enable)445 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
446   return 0;
447 }
448 
StereoPlayout(bool & enabled) const449 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
450   enabled = true;
451   return 0;
452 }
453 
StereoRecordingIsAvailable(bool & available)454 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
455   available = true;
456   return 0;
457 }
458 
SetStereoRecording(bool enable)459 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
460   return 0;
461 }
462 
StereoRecording(bool & enabled) const463 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
464   enabled = true;
465   return 0;
466 }
467 
SetPlayoutBuffer(const AudioDeviceModule::BufferType type,uint16_t sizeMS)468 int32_t FileAudioDevice::SetPlayoutBuffer(
469     const AudioDeviceModule::BufferType type,
470     uint16_t sizeMS) {
471   return 0;
472 }
473 
PlayoutBuffer(AudioDeviceModule::BufferType & type,uint16_t & sizeMS) const474 int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
475                                         uint16_t& sizeMS) const {
476   type = _playBufType;
477   return 0;
478 }
479 
PlayoutDelay(uint16_t & delayMS) const480 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
481   return 0;
482 }
483 
RecordingDelay(uint16_t & delayMS) const484 int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
485 
CPULoad(uint16_t & load) const486 int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
487 
PlayoutWarning() const488 bool FileAudioDevice::PlayoutWarning() const { return false; }
489 
PlayoutError() const490 bool FileAudioDevice::PlayoutError() const { return false; }
491 
RecordingWarning() const492 bool FileAudioDevice::RecordingWarning() const { return false; }
493 
RecordingError() const494 bool FileAudioDevice::RecordingError() const { return false; }
495 
ClearPlayoutWarning()496 void FileAudioDevice::ClearPlayoutWarning() {}
497 
ClearPlayoutError()498 void FileAudioDevice::ClearPlayoutError() {}
499 
ClearRecordingWarning()500 void FileAudioDevice::ClearRecordingWarning() {}
501 
ClearRecordingError()502 void FileAudioDevice::ClearRecordingError() {}
503 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)504 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
505   CriticalSectionScoped lock(&_critSect);
506 
507   _ptrAudioBuffer = audioBuffer;
508 
509   // Inform the AudioBuffer about default settings for this implementation.
510   // Set all values to zero here since the actual settings will be done by
511   // InitPlayout and InitRecording later.
512   _ptrAudioBuffer->SetRecordingSampleRate(0);
513   _ptrAudioBuffer->SetPlayoutSampleRate(0);
514   _ptrAudioBuffer->SetRecordingChannels(0);
515   _ptrAudioBuffer->SetPlayoutChannels(0);
516 }
517 
PlayThreadFunc(void * pThis)518 bool FileAudioDevice::PlayThreadFunc(void* pThis)
519 {
520     return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
521 }
522 
RecThreadFunc(void * pThis)523 bool FileAudioDevice::RecThreadFunc(void* pThis)
524 {
525     return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
526 }
527 
PlayThreadProcess()528 bool FileAudioDevice::PlayThreadProcess()
529 {
530     if(!_playing)
531         return false;
532 
533     uint64_t currentTime = _clock->CurrentNtpInMilliseconds();
534     _critSect.Enter();
535 
536     if (_lastCallPlayoutMillis == 0 ||
537         currentTime - _lastCallPlayoutMillis >= 10)
538     {
539         _critSect.Leave();
540         _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
541         _critSect.Enter();
542 
543         _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
544         assert(_playoutFramesLeft == _playoutFramesIn10MS);
545         if (_outputFile.Open()) {
546           _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
547           _outputFile.Flush();
548         }
549         _lastCallPlayoutMillis = currentTime;
550     }
551     _playoutFramesLeft = 0;
552     _critSect.Leave();
553     SleepMs(10 - (_clock->CurrentNtpInMilliseconds() - currentTime));
554     return true;
555 }
556 
RecThreadProcess()557 bool FileAudioDevice::RecThreadProcess()
558 {
559     if (!_recording)
560         return false;
561 
562     uint64_t currentTime = _clock->CurrentNtpInMilliseconds();
563     _critSect.Enter();
564 
565     if (_lastCallRecordMillis == 0 ||
566         currentTime - _lastCallRecordMillis >= 10) {
567       if (_inputFile.Open()) {
568         if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
569           _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
570                                              _recordingFramesIn10MS);
571         } else {
572           _inputFile.Rewind();
573         }
574         _lastCallRecordMillis = currentTime;
575         _critSect.Leave();
576         _ptrAudioBuffer->DeliverRecordedData();
577         _critSect.Enter();
578       }
579     }
580 
581     _critSect.Leave();
582     SleepMs(10 - (_clock->CurrentNtpInMilliseconds() - currentTime));
583     return true;
584 }
585 
586 }  // namespace webrtc
587