• Home
  • History
  • Annotate
  • 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   _playoutFramesIn10MS = kPlayoutFixedSampleRate/100;
198 
199   if (!_playoutBuffer)
200       _playoutBuffer = new int8_t[2 *
201                                   kPlayoutNumChannels *
202                                   kPlayoutFixedSampleRate/100];
203   if (!_playoutBuffer)
204   {
205     _playing = false;
206     return -1;
207   }
208 
209   // PLAYOUT
210   const char* threadName = "webrtc_audio_module_play_thread";
211   _ptrThreadPlay =  ThreadWrapper::CreateThread(PlayThreadFunc,
212                                                 this,
213                                                 kRealtimePriority,
214                                                 threadName);
215   if (_ptrThreadPlay == NULL)
216   {
217       _playing = false;
218       delete [] _playoutBuffer;
219       _playoutBuffer = NULL;
220       return -1;
221   }
222 
223   if (_outputFile.OpenFile(_outputFilename.c_str(),
224                            false, false, false) == -1) {
225     printf("Failed to open playout file %s!", _outputFilename.c_str());
226     _playing = false;
227     delete [] _playoutBuffer;
228     _playoutBuffer = NULL;
229     return -1;
230   }
231 
232   unsigned int threadID(0);
233   if (!_ptrThreadPlay->Start(threadID))
234   {
235       _playing = false;
236       delete _ptrThreadPlay;
237       _ptrThreadPlay = NULL;
238       delete [] _playoutBuffer;
239       _playoutBuffer = NULL;
240       return -1;
241   }
242   _playThreadID = threadID;
243 
244   return 0;
245 }
246 
StopPlayout()247 int32_t FileAudioDevice::StopPlayout() {
248   {
249       CriticalSectionScoped lock(&_critSect);
250       _playing = false;
251   }
252 
253   // stop playout thread first
254   if (_ptrThreadPlay && !_ptrThreadPlay->Stop())
255   {
256       return -1;
257   }
258   else {
259       delete _ptrThreadPlay;
260       _ptrThreadPlay = NULL;
261   }
262 
263   CriticalSectionScoped lock(&_critSect);
264 
265   _playoutFramesLeft = 0;
266   delete [] _playoutBuffer;
267   _playoutBuffer = NULL;
268   _outputFile.Flush();
269   _outputFile.CloseFile();
270    return 0;
271 }
272 
Playing() const273 bool FileAudioDevice::Playing() const {
274   return true;
275 }
276 
StartRecording()277 int32_t FileAudioDevice::StartRecording() {
278   _recording = true;
279 
280   // Make sure we only create the buffer once.
281   _recordingBufferSizeIn10MS = _recordingFramesIn10MS *
282                                kRecordingNumChannels *
283                                2;
284   if (!_recordingBuffer) {
285       _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
286   }
287 
288   if (_inputFile.OpenFile(_inputFilename.c_str(), true,
289                               true, false) == -1) {
290     printf("Failed to open audio input file %s!\n",
291            _inputFilename.c_str());
292     _recording = false;
293     delete[] _recordingBuffer;
294     _recordingBuffer = NULL;
295     return -1;
296   }
297 
298   const char* threadName = "webrtc_audio_module_capture_thread";
299   _ptrThreadRec = ThreadWrapper::CreateThread(RecThreadFunc,
300                                               this,
301                                               kRealtimePriority,
302                                               threadName);
303   if (_ptrThreadRec == NULL)
304   {
305       _recording = false;
306       delete [] _recordingBuffer;
307       _recordingBuffer = NULL;
308       return -1;
309   }
310 
311   unsigned int threadID(0);
312   if (!_ptrThreadRec->Start(threadID))
313   {
314       _recording = false;
315       delete _ptrThreadRec;
316       _ptrThreadRec = NULL;
317       delete [] _recordingBuffer;
318       _recordingBuffer = NULL;
319       return -1;
320   }
321   _recThreadID = threadID;
322 
323   return 0;
324 }
325 
326 
StopRecording()327 int32_t FileAudioDevice::StopRecording() {
328   {
329     CriticalSectionScoped lock(&_critSect);
330     _recording = false;
331   }
332 
333   if (_ptrThreadRec && !_ptrThreadRec->Stop())
334   {
335       return -1;
336   }
337   else {
338       delete _ptrThreadRec;
339       _ptrThreadRec = NULL;
340   }
341 
342   CriticalSectionScoped lock(&_critSect);
343   _recordingFramesLeft = 0;
344   if (_recordingBuffer)
345   {
346       delete [] _recordingBuffer;
347       _recordingBuffer = NULL;
348   }
349   return 0;
350 }
351 
Recording() const352 bool FileAudioDevice::Recording() const {
353   return _recording;
354 }
355 
SetAGC(bool enable)356 int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
357 
AGC() const358 bool FileAudioDevice::AGC() const { return false; }
359 
SetWaveOutVolume(uint16_t volumeLeft,uint16_t volumeRight)360 int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
361                                            uint16_t volumeRight) {
362   return -1;
363 }
364 
WaveOutVolume(uint16_t & volumeLeft,uint16_t & volumeRight) const365 int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
366                                         uint16_t& volumeRight) const {
367   return -1;
368 }
369 
InitSpeaker()370 int32_t FileAudioDevice::InitSpeaker() { return -1; }
371 
SpeakerIsInitialized() const372 bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
373 
InitMicrophone()374 int32_t FileAudioDevice::InitMicrophone() { return 0; }
375 
MicrophoneIsInitialized() const376 bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
377 
SpeakerVolumeIsAvailable(bool & available)378 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
379   return -1;
380 }
381 
SetSpeakerVolume(uint32_t volume)382 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
383 
SpeakerVolume(uint32_t & volume) const384 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
385 
MaxSpeakerVolume(uint32_t & maxVolume) const386 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
387   return -1;
388 }
389 
MinSpeakerVolume(uint32_t & minVolume) const390 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
391   return -1;
392 }
393 
SpeakerVolumeStepSize(uint16_t & stepSize) const394 int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
395   return -1;
396 }
397 
MicrophoneVolumeIsAvailable(bool & available)398 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
399   return -1;
400 }
401 
SetMicrophoneVolume(uint32_t volume)402 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
403 
MicrophoneVolume(uint32_t & volume) const404 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
405   return -1;
406 }
407 
MaxMicrophoneVolume(uint32_t & maxVolume) const408 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
409   return -1;
410 }
411 
MinMicrophoneVolume(uint32_t & minVolume) const412 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
413   return -1;
414 }
415 
MicrophoneVolumeStepSize(uint16_t & stepSize) const416 int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
417   return -1;
418 }
419 
SpeakerMuteIsAvailable(bool & available)420 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
421 
SetSpeakerMute(bool enable)422 int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
423 
SpeakerMute(bool & enabled) const424 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
425 
MicrophoneMuteIsAvailable(bool & available)426 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
427   return -1;
428 }
429 
SetMicrophoneMute(bool enable)430 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
431 
MicrophoneMute(bool & enabled) const432 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
433 
MicrophoneBoostIsAvailable(bool & available)434 int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
435   return -1;
436 }
437 
SetMicrophoneBoost(bool enable)438 int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
439 
MicrophoneBoost(bool & enabled) const440 int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
441 
StereoPlayoutIsAvailable(bool & available)442 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
443   available = true;
444   return 0;
445 }
SetStereoPlayout(bool enable)446 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
447   return 0;
448 }
449 
StereoPlayout(bool & enabled) const450 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
451   enabled = true;
452   return 0;
453 }
454 
StereoRecordingIsAvailable(bool & available)455 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
456   available = true;
457   return 0;
458 }
459 
SetStereoRecording(bool enable)460 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
461   return 0;
462 }
463 
StereoRecording(bool & enabled) const464 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
465   enabled = true;
466   return 0;
467 }
468 
SetPlayoutBuffer(const AudioDeviceModule::BufferType type,uint16_t sizeMS)469 int32_t FileAudioDevice::SetPlayoutBuffer(
470     const AudioDeviceModule::BufferType type,
471     uint16_t sizeMS) {
472   return 0;
473 }
474 
PlayoutBuffer(AudioDeviceModule::BufferType & type,uint16_t & sizeMS) const475 int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
476                                         uint16_t& sizeMS) const {
477   type = _playBufType;
478   return 0;
479 }
480 
PlayoutDelay(uint16_t & delayMS) const481 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
482   return 0;
483 }
484 
RecordingDelay(uint16_t & delayMS) const485 int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
486 
CPULoad(uint16_t & load) const487 int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
488 
PlayoutWarning() const489 bool FileAudioDevice::PlayoutWarning() const { return false; }
490 
PlayoutError() const491 bool FileAudioDevice::PlayoutError() const { return false; }
492 
RecordingWarning() const493 bool FileAudioDevice::RecordingWarning() const { return false; }
494 
RecordingError() const495 bool FileAudioDevice::RecordingError() const { return false; }
496 
ClearPlayoutWarning()497 void FileAudioDevice::ClearPlayoutWarning() {}
498 
ClearPlayoutError()499 void FileAudioDevice::ClearPlayoutError() {}
500 
ClearRecordingWarning()501 void FileAudioDevice::ClearRecordingWarning() {}
502 
ClearRecordingError()503 void FileAudioDevice::ClearRecordingError() {}
504 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)505 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
506   CriticalSectionScoped lock(&_critSect);
507 
508   _ptrAudioBuffer = audioBuffer;
509 
510   // Inform the AudioBuffer about default settings for this implementation.
511   // Set all values to zero here since the actual settings will be done by
512   // InitPlayout and InitRecording later.
513   _ptrAudioBuffer->SetRecordingSampleRate(0);
514   _ptrAudioBuffer->SetPlayoutSampleRate(0);
515   _ptrAudioBuffer->SetRecordingChannels(0);
516   _ptrAudioBuffer->SetPlayoutChannels(0);
517 }
518 
PlayThreadFunc(void * pThis)519 bool FileAudioDevice::PlayThreadFunc(void* pThis)
520 {
521     return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
522 }
523 
RecThreadFunc(void * pThis)524 bool FileAudioDevice::RecThreadFunc(void* pThis)
525 {
526     return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
527 }
528 
PlayThreadProcess()529 bool FileAudioDevice::PlayThreadProcess()
530 {
531     if(!_playing)
532         return false;
533 
534     uint64_t currentTime = _clock->CurrentNtpInMilliseconds();
535     _critSect.Enter();
536 
537     if (_lastCallPlayoutMillis == 0 ||
538         currentTime - _lastCallPlayoutMillis >= 10)
539     {
540         _critSect.Leave();
541         _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
542         _critSect.Enter();
543 
544         _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
545         assert(_playoutFramesLeft == _playoutFramesIn10MS);
546         if (_outputFile.Open()) {
547           _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
548           _outputFile.Flush();
549         }
550         _lastCallPlayoutMillis = currentTime;
551     }
552     _playoutFramesLeft = 0;
553     _critSect.Leave();
554     SleepMs(10 - (_clock->CurrentNtpInMilliseconds() - currentTime));
555     return true;
556 }
557 
RecThreadProcess()558 bool FileAudioDevice::RecThreadProcess()
559 {
560     if (!_recording)
561         return false;
562 
563     uint64_t currentTime = _clock->CurrentNtpInMilliseconds();
564     _critSect.Enter();
565 
566     if (_lastCallRecordMillis == 0 ||
567         currentTime - _lastCallRecordMillis >= 10) {
568       if (_inputFile.Open()) {
569         if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
570           _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
571                                              _recordingFramesIn10MS);
572         } else {
573           _inputFile.Rewind();
574         }
575         _lastCallRecordMillis = currentTime;
576         _critSect.Leave();
577         _ptrAudioBuffer->DeliverRecordedData();
578         _critSect.Enter();
579       }
580     }
581 
582     _critSect.Leave();
583     SleepMs(10 - (_clock->CurrentNtpInMilliseconds() - currentTime));
584     return true;
585 }
586 
587 }  // namespace webrtc
588