blob: 182c43d9d54b5eabbabca04285dac3515787e0b4 [file] [log] [blame]
phoglund@webrtc.org3acaa1f2014-06-11 14:12:04 +00001/*
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
15namespace webrtc {
16
17int kRecordingFixedSampleRate = 48000;
18int kRecordingNumChannels = 2;
19int kPlayoutFixedSampleRate = 48000;
20int kPlayoutNumChannels = 2;
21int kPlayoutBufferSize = kPlayoutFixedSampleRate / 100
22 * kPlayoutNumChannels * 2;
23int kRecordingBufferSize = kRecordingFixedSampleRate / 100
24 * kRecordingNumChannels * 2;
25
26FileAudioDevice::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
53FileAudioDevice::~FileAudioDevice() {
54 _outputFile.Flush();
55 _outputFile.CloseFile();
56 delete &_outputFile;
57 _inputFile.Flush();
58 _inputFile.CloseFile();
59 delete &_inputFile;
60}
61
62int32_t FileAudioDevice::ActiveAudioLayer(
63 AudioDeviceModule::AudioLayer& audioLayer) const {
64 return -1;
65}
66
67int32_t FileAudioDevice::Init() { return 0; }
68
69int32_t FileAudioDevice::Terminate() { return 0; }
70
71bool FileAudioDevice::Initialized() const { return true; }
72
73int16_t FileAudioDevice::PlayoutDevices() {
74 return 1;
75}
76
77int16_t FileAudioDevice::RecordingDevices() {
78 return 1;
79}
80
81int32_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
96int32_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
111int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) {
112 if (index == 0) {
113 _playout_index = index;
114 return 0;
115 }
116 return -1;
117}
118
119int32_t FileAudioDevice::SetPlayoutDevice(
120 AudioDeviceModule::WindowsDeviceType device) {
121 return -1;
122}
123
124int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) {
125 if (index == 0) {
126 _record_index = index;
127 return _record_index;
128 }
129 return -1;
130}
131
132int32_t FileAudioDevice::SetRecordingDevice(
133 AudioDeviceModule::WindowsDeviceType device) {
134 return -1;
135}
136
137int32_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
146int32_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
156bool FileAudioDevice::PlayoutIsInitialized() const {
157 return true;
158}
159
160int32_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
169int32_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
185bool FileAudioDevice::RecordingIsInitialized() const {
186 return true;
187}
188
189int32_t FileAudioDevice::StartPlayout() {
190 if (_playing)
191 {
192 return 0;
193 }
194
195 _playing = true;
196 _playoutFramesLeft = 0;
phoglund@webrtc.orgea0a7d82014-08-12 11:09:12 +0000197 _playoutFramesIn10MS = kPlayoutFixedSampleRate/100;
phoglund@webrtc.org3acaa1f2014-06-11 14:12:04 +0000198
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
247int32_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
273bool FileAudioDevice::Playing() const {
274 return true;
275}
276
277int32_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
327int32_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
352bool FileAudioDevice::Recording() const {
353 return _recording;
354}
355
356int32_t FileAudioDevice::SetAGC(bool enable) { return -1; }
357
358bool FileAudioDevice::AGC() const { return false; }
359
360int32_t FileAudioDevice::SetWaveOutVolume(uint16_t volumeLeft,
361 uint16_t volumeRight) {
362 return -1;
363}
364
365int32_t FileAudioDevice::WaveOutVolume(uint16_t& volumeLeft,
366 uint16_t& volumeRight) const {
367 return -1;
368}
369
370int32_t FileAudioDevice::InitSpeaker() { return -1; }
371
372bool FileAudioDevice::SpeakerIsInitialized() const { return false; }
373
374int32_t FileAudioDevice::InitMicrophone() { return 0; }
375
376bool FileAudioDevice::MicrophoneIsInitialized() const { return true; }
377
378int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& available) {
379 return -1;
380}
381
382int32_t FileAudioDevice::SetSpeakerVolume(uint32_t volume) { return -1; }
383
384int32_t FileAudioDevice::SpeakerVolume(uint32_t& volume) const { return -1; }
385
386int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& maxVolume) const {
387 return -1;
388}
389
390int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& minVolume) const {
391 return -1;
392}
393
394int32_t FileAudioDevice::SpeakerVolumeStepSize(uint16_t& stepSize) const {
395 return -1;
396}
397
398int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& available) {
399 return -1;
400}
401
402int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t volume) { return -1; }
403
404int32_t FileAudioDevice::MicrophoneVolume(uint32_t& volume) const {
405 return -1;
406}
407
408int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& maxVolume) const {
409 return -1;
410}
411
412int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& minVolume) const {
413 return -1;
414}
415
416int32_t FileAudioDevice::MicrophoneVolumeStepSize(uint16_t& stepSize) const {
417 return -1;
418}
419
420int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& available) { return -1; }
421
422int32_t FileAudioDevice::SetSpeakerMute(bool enable) { return -1; }
423
424int32_t FileAudioDevice::SpeakerMute(bool& enabled) const { return -1; }
425
426int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& available) {
427 return -1;
428}
429
430int32_t FileAudioDevice::SetMicrophoneMute(bool enable) { return -1; }
431
432int32_t FileAudioDevice::MicrophoneMute(bool& enabled) const { return -1; }
433
434int32_t FileAudioDevice::MicrophoneBoostIsAvailable(bool& available) {
435 return -1;
436}
437
438int32_t FileAudioDevice::SetMicrophoneBoost(bool enable) { return -1; }
439
440int32_t FileAudioDevice::MicrophoneBoost(bool& enabled) const { return -1; }
441
442int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) {
443 available = true;
444 return 0;
445}
446int32_t FileAudioDevice::SetStereoPlayout(bool enable) {
447 return 0;
448}
449
450int32_t FileAudioDevice::StereoPlayout(bool& enabled) const {
451 enabled = true;
452 return 0;
453}
454
455int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) {
456 available = true;
457 return 0;
458}
459
460int32_t FileAudioDevice::SetStereoRecording(bool enable) {
461 return 0;
462}
463
464int32_t FileAudioDevice::StereoRecording(bool& enabled) const {
465 enabled = true;
466 return 0;
467}
468
469int32_t FileAudioDevice::SetPlayoutBuffer(
470 const AudioDeviceModule::BufferType type,
471 uint16_t sizeMS) {
472 return 0;
473}
474
475int32_t FileAudioDevice::PlayoutBuffer(AudioDeviceModule::BufferType& type,
476 uint16_t& sizeMS) const {
477 type = _playBufType;
478 return 0;
479}
480
481int32_t FileAudioDevice::PlayoutDelay(uint16_t& delayMS) const {
482 return 0;
483}
484
485int32_t FileAudioDevice::RecordingDelay(uint16_t& delayMS) const { return -1; }
486
487int32_t FileAudioDevice::CPULoad(uint16_t& load) const { return -1; }
488
489bool FileAudioDevice::PlayoutWarning() const { return false; }
490
491bool FileAudioDevice::PlayoutError() const { return false; }
492
493bool FileAudioDevice::RecordingWarning() const { return false; }
494
495bool FileAudioDevice::RecordingError() const { return false; }
496
497void FileAudioDevice::ClearPlayoutWarning() {}
498
499void FileAudioDevice::ClearPlayoutError() {}
500
501void FileAudioDevice::ClearRecordingWarning() {}
502
503void FileAudioDevice::ClearRecordingError() {}
504
505void 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
519bool FileAudioDevice::PlayThreadFunc(void* pThis)
520{
521 return (static_cast<FileAudioDevice*>(pThis)->PlayThreadProcess());
522}
523
524bool FileAudioDevice::RecThreadFunc(void* pThis)
525{
526 return (static_cast<FileAudioDevice*>(pThis)->RecThreadProcess());
527}
528
529bool 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
558bool 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