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