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