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 "webrtc/base/checks.h"
12 #include "webrtc/base/logging.h"
13 #include "webrtc/base/platform_thread.h"
14 #include "webrtc/modules/audio_device/dummy/file_audio_device.h"
15 #include "webrtc/system_wrappers/include/sleep.h"
16
17 namespace webrtc {
18
19 const int kRecordingFixedSampleRate = 48000;
20 const size_t kRecordingNumChannels = 2;
21 const int kPlayoutFixedSampleRate = 48000;
22 const size_t kPlayoutNumChannels = 2;
23 const size_t kPlayoutBufferSize =
24 kPlayoutFixedSampleRate / 100 * kPlayoutNumChannels * 2;
25 const size_t kRecordingBufferSize =
26 kRecordingFixedSampleRate / 100 * kRecordingNumChannels * 2;
27
FileAudioDevice(const int32_t id,const char * inputFilename,const char * outputFilename)28 FileAudioDevice::FileAudioDevice(const int32_t id,
29 const char* inputFilename,
30 const char* outputFilename):
31 _ptrAudioBuffer(NULL),
32 _recordingBuffer(NULL),
33 _playoutBuffer(NULL),
34 _recordingFramesLeft(0),
35 _playoutFramesLeft(0),
36 _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
37 _recordingBufferSizeIn10MS(0),
38 _recordingFramesIn10MS(0),
39 _playoutFramesIn10MS(0),
40 _playing(false),
41 _recording(false),
42 _lastCallPlayoutMillis(0),
43 _lastCallRecordMillis(0),
44 _outputFile(*FileWrapper::Create()),
45 _inputFile(*FileWrapper::Create()),
46 _outputFilename(outputFilename),
47 _inputFilename(inputFilename) {
48 }
49
~FileAudioDevice()50 FileAudioDevice::~FileAudioDevice() {
51 delete &_outputFile;
52 delete &_inputFile;
53 }
54
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const55 int32_t FileAudioDevice::ActiveAudioLayer(
56 AudioDeviceModule::AudioLayer& audioLayer) const {
57 return -1;
58 }
59
Init()60 AudioDeviceGeneric::InitStatus FileAudioDevice::Init() {
61 return InitStatus::OK;
62 }
63
Terminate()64 int32_t FileAudioDevice::Terminate() { return 0; }
65
Initialized() const66 bool FileAudioDevice::Initialized() const { return true; }
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 if (_ptrAudioBuffer) {
143 // Update webrtc audio buffer with the selected parameters
144 _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
145 _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
146 }
147 return 0;
148 }
149
PlayoutIsInitialized() const150 bool FileAudioDevice::PlayoutIsInitialized() const {
151 return true;
152 }
153
RecordingIsAvailable(bool & available)154 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
155 if (_record_index == 0) {
156 available = true;
157 return _record_index;
158 }
159 available = false;
160 return -1;
161 }
162
InitRecording()163 int32_t FileAudioDevice::InitRecording() {
164 CriticalSectionScoped lock(&_critSect);
165
166 if (_recording) {
167 return -1;
168 }
169
170 _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100);
171
172 if (_ptrAudioBuffer) {
173 _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
174 _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
175 }
176 return 0;
177 }
178
RecordingIsInitialized() const179 bool FileAudioDevice::RecordingIsInitialized() const {
180 return _recordingFramesIn10MS != 0;
181 }
182
StartPlayout()183 int32_t FileAudioDevice::StartPlayout() {
184 if (_playing) {
185 return 0;
186 }
187
188 _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100);
189 _playing = true;
190 _playoutFramesLeft = 0;
191
192 if (!_playoutBuffer) {
193 _playoutBuffer = new int8_t[kPlayoutBufferSize];
194 }
195 if (!_playoutBuffer) {
196 _playing = false;
197 return -1;
198 }
199
200 // PLAYOUT
201 if (!_outputFilename.empty() &&
202 !_outputFile.OpenFile(_outputFilename.c_str(), false)) {
203 LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename;
204 _playing = false;
205 delete [] _playoutBuffer;
206 _playoutBuffer = NULL;
207 return -1;
208 }
209
210 _ptrThreadPlay.reset(new rtc::PlatformThread(
211 PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
212 _ptrThreadPlay->Start();
213 _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
214
215 LOG(LS_INFO) << "Started playout capture to output file: "
216 << _outputFilename;
217 return 0;
218 }
219
StopPlayout()220 int32_t FileAudioDevice::StopPlayout() {
221 {
222 CriticalSectionScoped lock(&_critSect);
223 _playing = false;
224 }
225
226 // stop playout thread first
227 if (_ptrThreadPlay) {
228 _ptrThreadPlay->Stop();
229 _ptrThreadPlay.reset();
230 }
231
232 CriticalSectionScoped lock(&_critSect);
233
234 _playoutFramesLeft = 0;
235 delete [] _playoutBuffer;
236 _playoutBuffer = NULL;
237 _outputFile.CloseFile();
238
239 LOG(LS_INFO) << "Stopped playout capture to output file: "
240 << _outputFilename;
241 return 0;
242 }
243
Playing() const244 bool FileAudioDevice::Playing() const {
245 return true;
246 }
247
StartRecording()248 int32_t FileAudioDevice::StartRecording() {
249 _recording = true;
250
251 // Make sure we only create the buffer once.
252 _recordingBufferSizeIn10MS = _recordingFramesIn10MS *
253 kRecordingNumChannels *
254 2;
255 if (!_recordingBuffer) {
256 _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
257 }
258
259 if (!_inputFilename.empty() &&
260 !_inputFile.OpenFile(_inputFilename.c_str(), true)) {
261 LOG(LS_ERROR) << "Failed to open audio input file: " << _inputFilename;
262 _recording = false;
263 delete[] _recordingBuffer;
264 _recordingBuffer = NULL;
265 return -1;
266 }
267
268 _ptrThreadRec.reset(new rtc::PlatformThread(
269 RecThreadFunc, this, "webrtc_audio_module_capture_thread"));
270
271 _ptrThreadRec->Start();
272 _ptrThreadRec->SetPriority(rtc::kRealtimePriority);
273
274 LOG(LS_INFO) << "Started recording from input file: "
275 << _inputFilename;
276
277 return 0;
278 }
279
280
StopRecording()281 int32_t FileAudioDevice::StopRecording() {
282 {
283 CriticalSectionScoped lock(&_critSect);
284 _recording = false;
285 }
286
287 if (_ptrThreadRec) {
288 _ptrThreadRec->Stop();
289 _ptrThreadRec.reset();
290 }
291
292 CriticalSectionScoped lock(&_critSect);
293 _recordingFramesLeft = 0;
294 if (_recordingBuffer) {
295 delete [] _recordingBuffer;
296 _recordingBuffer = NULL;
297 }
298 _inputFile.CloseFile();
299
300 LOG(LS_INFO) << "Stopped recording from input file: "
301 << _inputFilename;
302 return 0;
303 }
304
Recording() const305 bool FileAudioDevice::Recording() const {
306 return _recording;
307 }
308
SetAGC(bool enable)309 int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
310
AGC() const311 bool FileAudioDevice::AGC() const { return false; }
312
SetWaveOutVolume(uint16_t volumeLeft,uint16_t volumeRight)313 int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
314 uint16_t volumeRight) {
315 return -1;
316 }
317
WaveOutVolume(uint16_t & volumeLeft,uint16_t & volumeRight) const318 int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
319 uint16_t& volumeRight) const {
320 return -1;
321 }
322
InitSpeaker()323 int32_t FileAudioDevice::InitSpeaker() { return -1; }
324
SpeakerIsInitialized() const325 bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
326
InitMicrophone()327 int32_t FileAudioDevice::InitMicrophone() { return 0; }
328
MicrophoneIsInitialized() const329 bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
330
SpeakerVolumeIsAvailable(bool & available)331 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
332 return -1;
333 }
334
SetSpeakerVolume(uint32_t volume)335 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
336
SpeakerVolume(uint32_t & volume) const337 int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
338
MaxSpeakerVolume(uint32_t & maxVolume) const339 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
340 return -1;
341 }
342
MinSpeakerVolume(uint32_t & minVolume) const343 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
344 return -1;
345 }
346
SpeakerVolumeStepSize(uint16_t & stepSize) const347 int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
348 return -1;
349 }
350
MicrophoneVolumeIsAvailable(bool & available)351 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
352 return -1;
353 }
354
SetMicrophoneVolume(uint32_t volume)355 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
356
MicrophoneVolume(uint32_t & volume) const357 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
358 return -1;
359 }
360
MaxMicrophoneVolume(uint32_t & maxVolume) const361 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
362 return -1;
363 }
364
MinMicrophoneVolume(uint32_t & minVolume) const365 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
366 return -1;
367 }
368
MicrophoneVolumeStepSize(uint16_t & stepSize) const369 int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
370 return -1;
371 }
372
SpeakerMuteIsAvailable(bool & available)373 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
374
SetSpeakerMute(bool enable)375 int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
376
SpeakerMute(bool & enabled) const377 int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
378
MicrophoneMuteIsAvailable(bool & available)379 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
380 return -1;
381 }
382
SetMicrophoneMute(bool enable)383 int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
384
MicrophoneMute(bool & enabled) const385 int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
386
MicrophoneBoostIsAvailable(bool & available)387 int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
388 return -1;
389 }
390
SetMicrophoneBoost(bool enable)391 int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
392
MicrophoneBoost(bool & enabled) const393 int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
394
StereoPlayoutIsAvailable(bool & available)395 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
396 available = true;
397 return 0;
398 }
SetStereoPlayout(bool enable)399 int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
400 return 0;
401 }
402
StereoPlayout(bool & enabled) const403 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
404 enabled = true;
405 return 0;
406 }
407
StereoRecordingIsAvailable(bool & available)408 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
409 available = true;
410 return 0;
411 }
412
SetStereoRecording(bool enable)413 int32_t FileAudioDevice::SetStereoRecording(bool enable) {
414 return 0;
415 }
416
StereoRecording(bool & enabled) const417 int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
418 enabled = true;
419 return 0;
420 }
421
SetPlayoutBuffer(const AudioDeviceModule::BufferType type,uint16_t sizeMS)422 int32_t FileAudioDevice::SetPlayoutBuffer(
423 const AudioDeviceModule::BufferType type,
424 uint16_t sizeMS) {
425 return 0;
426 }
427
PlayoutBuffer(AudioDeviceModule::BufferType & type,uint16_t & sizeMS) const428 int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
429 uint16_t& sizeMS) const {
430 type = _playBufType;
431 return 0;
432 }
433
PlayoutDelay(uint16_t & delayMS) const434 int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
435 return 0;
436 }
437
RecordingDelay(uint16_t & delayMS) const438 int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
439
CPULoad(uint16_t & load) const440 int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
441
PlayoutWarning() const442 bool FileAudioDevice::PlayoutWarning() const { return false; }
443
PlayoutError() const444 bool FileAudioDevice::PlayoutError() const { return false; }
445
RecordingWarning() const446 bool FileAudioDevice::RecordingWarning() const { return false; }
447
RecordingError() const448 bool FileAudioDevice::RecordingError() const { return false; }
449
ClearPlayoutWarning()450 void FileAudioDevice::ClearPlayoutWarning() {}
451
ClearPlayoutError()452 void FileAudioDevice::ClearPlayoutError() {}
453
ClearRecordingWarning()454 void FileAudioDevice::ClearRecordingWarning() {}
455
ClearRecordingError()456 void FileAudioDevice::ClearRecordingError() {}
457
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)458 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
459 CriticalSectionScoped lock(&_critSect);
460
461 _ptrAudioBuffer = audioBuffer;
462
463 // Inform the AudioBuffer about default settings for this implementation.
464 // Set all values to zero here since the actual settings will be done by
465 // InitPlayout and InitRecording later.
466 _ptrAudioBuffer->SetRecordingSampleRate(0);
467 _ptrAudioBuffer->SetPlayoutSampleRate(0);
468 _ptrAudioBuffer->SetRecordingChannels(0);
469 _ptrAudioBuffer->SetPlayoutChannels(0);
470 }
471
PlayThreadFunc(void * pThis)472 bool FileAudioDevice::PlayThreadFunc(void* pThis)
473 {
474 return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
475 }
476
RecThreadFunc(void * pThis)477 bool FileAudioDevice::RecThreadFunc(void* pThis)
478 {
479 return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
480 }
481
PlayThreadProcess()482 bool FileAudioDevice::PlayThreadProcess()
483 {
484 if (!_playing) {
485 return false;
486 }
487 int64_t currentTime = rtc::TimeMillis();
488 _critSect.Enter();
489
490 if (_lastCallPlayoutMillis == 0 ||
491 currentTime - _lastCallPlayoutMillis >= 10) {
492 _critSect.Leave();
493 _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
494 _critSect.Enter();
495
496 _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
497 RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft);
498 if (_outputFile.is_open()) {
499 _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
500 }
501 _lastCallPlayoutMillis = currentTime;
502 }
503 _playoutFramesLeft = 0;
504 _critSect.Leave();
505
506 int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
507 if (deltaTimeMillis < 10) {
508 SleepMs(10 - deltaTimeMillis);
509 }
510
511 return true;
512 }
513
RecThreadProcess()514 bool FileAudioDevice::RecThreadProcess()
515 {
516 if (!_recording) {
517 return false;
518 }
519
520 int64_t currentTime = rtc::TimeMillis();
521 _critSect.Enter();
522
523 if (_lastCallRecordMillis == 0 ||
524 currentTime - _lastCallRecordMillis >= 10) {
525 if (_inputFile.is_open()) {
526 if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
527 _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
528 _recordingFramesIn10MS);
529 } else {
530 _inputFile.Rewind();
531 }
532 _lastCallRecordMillis = currentTime;
533 _critSect.Leave();
534 _ptrAudioBuffer->DeliverRecordedData();
535 _critSect.Enter();
536 }
537 }
538
539 _critSect.Leave();
540
541 int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
542 if (deltaTimeMillis < 10) {
543 SleepMs(10 - deltaTimeMillis);
544 }
545
546 return true;
547 }
548
549 } // namespace webrtc
550