Line data Source code
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 :
28 0 : FileAudioDevice::FileAudioDevice(const int32_t id,
29 : const char* inputFilename,
30 0 : const char* outputFilename):
31 : _ptrAudioBuffer(NULL),
32 : _recordingBuffer(NULL),
33 : _playoutBuffer(NULL),
34 : _recordingFramesLeft(0),
35 : _playoutFramesLeft(0),
36 0 : _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 0 : _outputFile(*FileWrapper::Create()),
45 0 : _inputFile(*FileWrapper::Create()),
46 : _outputFilename(outputFilename),
47 0 : _inputFilename(inputFilename) {
48 0 : }
49 :
50 0 : FileAudioDevice::~FileAudioDevice() {
51 0 : delete &_outputFile;
52 0 : delete &_inputFile;
53 0 : }
54 :
55 0 : int32_t FileAudioDevice::ActiveAudioLayer(
56 : AudioDeviceModule::AudioLayer& audioLayer) const {
57 0 : return -1;
58 : }
59 :
60 0 : AudioDeviceGeneric::InitStatus FileAudioDevice::Init() {
61 0 : return InitStatus::OK;
62 : }
63 :
64 0 : int32_t FileAudioDevice::Terminate() { return 0; }
65 :
66 0 : bool FileAudioDevice::Initialized() const { return true; }
67 :
68 0 : int16_t FileAudioDevice::PlayoutDevices() {
69 0 : return 1;
70 : }
71 :
72 0 : int16_t FileAudioDevice::RecordingDevices() {
73 0 : return 1;
74 : }
75 :
76 0 : int32_t FileAudioDevice::PlayoutDeviceName(uint16_t index,
77 : char name[kAdmMaxDeviceNameSize],
78 : char guid[kAdmMaxGuidSize]) {
79 0 : const char* kName = "dummy_device";
80 0 : const char* kGuid = "dummy_device_unique_id";
81 0 : if (index < 1) {
82 0 : memset(name, 0, kAdmMaxDeviceNameSize);
83 0 : memset(guid, 0, kAdmMaxGuidSize);
84 0 : memcpy(name, kName, strlen(kName));
85 0 : memcpy(guid, kGuid, strlen(guid));
86 0 : return 0;
87 : }
88 0 : return -1;
89 : }
90 :
91 0 : int32_t FileAudioDevice::RecordingDeviceName(uint16_t index,
92 : char name[kAdmMaxDeviceNameSize],
93 : char guid[kAdmMaxGuidSize]) {
94 0 : const char* kName = "dummy_device";
95 0 : const char* kGuid = "dummy_device_unique_id";
96 0 : if (index < 1) {
97 0 : memset(name, 0, kAdmMaxDeviceNameSize);
98 0 : memset(guid, 0, kAdmMaxGuidSize);
99 0 : memcpy(name, kName, strlen(kName));
100 0 : memcpy(guid, kGuid, strlen(guid));
101 0 : return 0;
102 : }
103 0 : return -1;
104 : }
105 :
106 0 : int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) {
107 0 : if (index == 0) {
108 0 : _playout_index = index;
109 0 : return 0;
110 : }
111 0 : return -1;
112 : }
113 :
114 0 : int32_t FileAudioDevice::SetPlayoutDevice(
115 : AudioDeviceModule::WindowsDeviceType device) {
116 0 : return -1;
117 : }
118 :
119 0 : int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) {
120 0 : if (index == 0) {
121 0 : _record_index = index;
122 0 : return _record_index;
123 : }
124 0 : return -1;
125 : }
126 :
127 0 : int32_t FileAudioDevice::SetRecordingDevice(
128 : AudioDeviceModule::WindowsDeviceType device) {
129 0 : return -1;
130 : }
131 :
132 0 : int32_t FileAudioDevice::PlayoutIsAvailable(bool& available) {
133 0 : if (_playout_index == 0) {
134 0 : available = true;
135 0 : return _playout_index;
136 : }
137 0 : available = false;
138 0 : return -1;
139 : }
140 :
141 0 : int32_t FileAudioDevice::InitPlayout() {
142 0 : if (_ptrAudioBuffer) {
143 : // Update webrtc audio buffer with the selected parameters
144 0 : _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate);
145 0 : _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels);
146 : }
147 0 : return 0;
148 : }
149 :
150 0 : bool FileAudioDevice::PlayoutIsInitialized() const {
151 0 : return true;
152 : }
153 :
154 0 : int32_t FileAudioDevice::RecordingIsAvailable(bool& available) {
155 0 : if (_record_index == 0) {
156 0 : available = true;
157 0 : return _record_index;
158 : }
159 0 : available = false;
160 0 : return -1;
161 : }
162 :
163 0 : int32_t FileAudioDevice::InitRecording() {
164 0 : CriticalSectionScoped lock(&_critSect);
165 :
166 0 : if (_recording) {
167 0 : return -1;
168 : }
169 :
170 0 : _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100);
171 :
172 0 : if (_ptrAudioBuffer) {
173 0 : _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate);
174 0 : _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels);
175 : }
176 0 : return 0;
177 : }
178 :
179 0 : bool FileAudioDevice::RecordingIsInitialized() const {
180 0 : return _recordingFramesIn10MS != 0;
181 : }
182 :
183 0 : int32_t FileAudioDevice::StartPlayout() {
184 0 : if (_playing) {
185 0 : return 0;
186 : }
187 :
188 0 : _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100);
189 0 : _playing = true;
190 0 : _playoutFramesLeft = 0;
191 :
192 0 : if (!_playoutBuffer) {
193 0 : _playoutBuffer = new int8_t[kPlayoutBufferSize];
194 : }
195 0 : if (!_playoutBuffer) {
196 0 : _playing = false;
197 0 : return -1;
198 : }
199 :
200 : // PLAYOUT
201 0 : if (!_outputFilename.empty() &&
202 0 : !_outputFile.OpenFile(_outputFilename.c_str(), false)) {
203 0 : LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename;
204 0 : _playing = false;
205 0 : delete [] _playoutBuffer;
206 0 : _playoutBuffer = NULL;
207 0 : return -1;
208 : }
209 :
210 0 : _ptrThreadPlay.reset(new rtc::PlatformThread(
211 0 : PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
212 0 : _ptrThreadPlay->Start();
213 0 : _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
214 :
215 0 : LOG(LS_INFO) << "Started playout capture to output file: "
216 0 : << _outputFilename;
217 0 : return 0;
218 : }
219 :
220 0 : int32_t FileAudioDevice::StopPlayout() {
221 : {
222 0 : CriticalSectionScoped lock(&_critSect);
223 0 : _playing = false;
224 : }
225 :
226 : // stop playout thread first
227 0 : if (_ptrThreadPlay) {
228 0 : _ptrThreadPlay->Stop();
229 0 : _ptrThreadPlay.reset();
230 : }
231 :
232 0 : CriticalSectionScoped lock(&_critSect);
233 :
234 0 : _playoutFramesLeft = 0;
235 0 : delete [] _playoutBuffer;
236 0 : _playoutBuffer = NULL;
237 0 : _outputFile.CloseFile();
238 :
239 0 : LOG(LS_INFO) << "Stopped playout capture to output file: "
240 0 : << _outputFilename;
241 0 : return 0;
242 : }
243 :
244 0 : bool FileAudioDevice::Playing() const {
245 0 : return true;
246 : }
247 :
248 0 : int32_t FileAudioDevice::StartRecording() {
249 0 : _recording = true;
250 :
251 : // Make sure we only create the buffer once.
252 0 : _recordingBufferSizeIn10MS = _recordingFramesIn10MS *
253 : kRecordingNumChannels *
254 0 : 2;
255 0 : if (!_recordingBuffer) {
256 0 : _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
257 : }
258 :
259 0 : if (!_inputFilename.empty() &&
260 0 : !_inputFile.OpenFile(_inputFilename.c_str(), true)) {
261 0 : LOG(LS_ERROR) << "Failed to open audio input file: " << _inputFilename;
262 0 : _recording = false;
263 0 : delete[] _recordingBuffer;
264 0 : _recordingBuffer = NULL;
265 0 : return -1;
266 : }
267 :
268 0 : _ptrThreadRec.reset(new rtc::PlatformThread(
269 0 : RecThreadFunc, this, "webrtc_audio_module_capture_thread"));
270 :
271 0 : _ptrThreadRec->Start();
272 0 : _ptrThreadRec->SetPriority(rtc::kRealtimePriority);
273 :
274 0 : LOG(LS_INFO) << "Started recording from input file: "
275 0 : << _inputFilename;
276 :
277 0 : return 0;
278 : }
279 :
280 :
281 0 : int32_t FileAudioDevice::StopRecording() {
282 : {
283 0 : CriticalSectionScoped lock(&_critSect);
284 0 : _recording = false;
285 : }
286 :
287 0 : if (_ptrThreadRec) {
288 0 : _ptrThreadRec->Stop();
289 0 : _ptrThreadRec.reset();
290 : }
291 :
292 0 : CriticalSectionScoped lock(&_critSect);
293 0 : _recordingFramesLeft = 0;
294 0 : if (_recordingBuffer) {
295 0 : delete [] _recordingBuffer;
296 0 : _recordingBuffer = NULL;
297 : }
298 0 : _inputFile.CloseFile();
299 :
300 0 : LOG(LS_INFO) << "Stopped recording from input file: "
301 0 : << _inputFilename;
302 0 : return 0;
303 : }
304 :
305 0 : bool FileAudioDevice::Recording() const {
306 0 : return _recording;
307 : }
308 :
309 0 : int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
310 :
311 0 : bool FileAudioDevice::AGC() const { return false; }
312 :
313 0 : int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
314 : uint16_t volumeRight) {
315 0 : return -1;
316 : }
317 :
318 0 : int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
319 : uint16_t& volumeRight) const {
320 0 : return -1;
321 : }
322 :
323 0 : int32_t FileAudioDevice::InitSpeaker() { return -1; }
324 :
325 0 : bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
326 :
327 0 : int32_t FileAudioDevice::InitMicrophone() { return 0; }
328 :
329 0 : bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
330 :
331 0 : int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
332 0 : return -1;
333 : }
334 :
335 0 : int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
336 :
337 0 : int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
338 :
339 0 : int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
340 0 : return -1;
341 : }
342 :
343 0 : int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
344 0 : return -1;
345 : }
346 :
347 0 : int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
348 0 : return -1;
349 : }
350 :
351 0 : int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
352 0 : return -1;
353 : }
354 :
355 0 : int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
356 :
357 0 : int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
358 0 : return -1;
359 : }
360 :
361 0 : int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
362 0 : return -1;
363 : }
364 :
365 0 : int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
366 0 : return -1;
367 : }
368 :
369 0 : int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
370 0 : return -1;
371 : }
372 :
373 0 : int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
374 :
375 0 : int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
376 :
377 0 : int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
378 :
379 0 : int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
380 0 : return -1;
381 : }
382 :
383 0 : int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
384 :
385 0 : int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
386 :
387 0 : int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
388 0 : return -1;
389 : }
390 :
391 0 : int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
392 :
393 0 : int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
394 :
395 0 : int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
396 0 : available = true;
397 0 : return 0;
398 : }
399 0 : int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
400 0 : return 0;
401 : }
402 :
403 0 : int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
404 0 : enabled = true;
405 0 : return 0;
406 : }
407 :
408 0 : int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
409 0 : available = true;
410 0 : return 0;
411 : }
412 :
413 0 : int32_t FileAudioDevice::SetStereoRecording(bool enable) {
414 0 : return 0;
415 : }
416 :
417 0 : int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
418 0 : enabled = true;
419 0 : return 0;
420 : }
421 :
422 0 : int32_t FileAudioDevice::SetPlayoutBuffer(
423 : const AudioDeviceModule::BufferType type,
424 : uint16_t sizeMS) {
425 0 : return 0;
426 : }
427 :
428 0 : int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
429 : uint16_t& sizeMS) const {
430 0 : type = _playBufType;
431 0 : return 0;
432 : }
433 :
434 0 : int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
435 0 : return 0;
436 : }
437 :
438 0 : int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
439 :
440 0 : int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
441 :
442 0 : bool FileAudioDevice::PlayoutWarning() const { return false; }
443 :
444 0 : bool FileAudioDevice::PlayoutError() const { return false; }
445 :
446 0 : bool FileAudioDevice::RecordingWarning() const { return false; }
447 :
448 0 : bool FileAudioDevice::RecordingError() const { return false; }
449 :
450 0 : void FileAudioDevice::ClearPlayoutWarning() {}
451 :
452 0 : void FileAudioDevice::ClearPlayoutError() {}
453 :
454 0 : void FileAudioDevice::ClearRecordingWarning() {}
455 :
456 0 : void FileAudioDevice::ClearRecordingError() {}
457 :
458 0 : void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
459 0 : CriticalSectionScoped lock(&_critSect);
460 :
461 0 : _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 0 : _ptrAudioBuffer->SetRecordingSampleRate(0);
467 0 : _ptrAudioBuffer->SetPlayoutSampleRate(0);
468 0 : _ptrAudioBuffer->SetRecordingChannels(0);
469 0 : _ptrAudioBuffer->SetPlayoutChannels(0);
470 0 : }
471 :
472 0 : bool FileAudioDevice::PlayThreadFunc(void* pThis)
473 : {
474 0 : return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
475 : }
476 :
477 0 : bool FileAudioDevice::RecThreadFunc(void* pThis)
478 : {
479 0 : return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
480 : }
481 :
482 0 : bool FileAudioDevice::PlayThreadProcess()
483 : {
484 0 : if (!_playing) {
485 0 : return false;
486 : }
487 0 : int64_t currentTime = rtc::TimeMillis();
488 0 : _critSect.Enter();
489 :
490 0 : if (_lastCallPlayoutMillis == 0 ||
491 0 : currentTime - _lastCallPlayoutMillis >= 10) {
492 0 : _critSect.Leave();
493 0 : _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
494 0 : _critSect.Enter();
495 :
496 0 : _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
497 0 : RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft);
498 0 : if (_outputFile.is_open()) {
499 0 : _outputFile.Write(_playoutBuffer, kPlayoutBufferSize);
500 : }
501 0 : _lastCallPlayoutMillis = currentTime;
502 : }
503 0 : _playoutFramesLeft = 0;
504 0 : _critSect.Leave();
505 :
506 0 : int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
507 0 : if (deltaTimeMillis < 10) {
508 0 : SleepMs(10 - deltaTimeMillis);
509 : }
510 :
511 0 : return true;
512 : }
513 :
514 0 : bool FileAudioDevice::RecThreadProcess()
515 : {
516 0 : if (!_recording) {
517 0 : return false;
518 : }
519 :
520 0 : int64_t currentTime = rtc::TimeMillis();
521 0 : _critSect.Enter();
522 :
523 0 : if (_lastCallRecordMillis == 0 ||
524 0 : currentTime - _lastCallRecordMillis >= 10) {
525 0 : if (_inputFile.is_open()) {
526 0 : if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) {
527 0 : _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
528 0 : _recordingFramesIn10MS);
529 : } else {
530 0 : _inputFile.Rewind();
531 : }
532 0 : _lastCallRecordMillis = currentTime;
533 0 : _critSect.Leave();
534 0 : _ptrAudioBuffer->DeliverRecordedData();
535 0 : _critSect.Enter();
536 : }
537 : }
538 :
539 0 : _critSect.Leave();
540 :
541 0 : int64_t deltaTimeMillis = rtc::TimeMillis() - currentTime;
542 0 : if (deltaTimeMillis < 10) {
543 0 : SleepMs(10 - deltaTimeMillis);
544 : }
545 :
546 0 : return true;
547 : }
548 :
549 : } // namespace webrtc
|