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