1d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant/*
2d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant *
4d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant *  Use of this source code is governed by a BSD-style license
5b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant *  that can be found in the LICENSE file in the root of the source
6b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant *  tree. An additional intellectual property rights grant can be found
7d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant *  in the file PATENTS.  All contributing project authors may
8d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant *  be found in the AUTHORS file in the root of the source tree.
9d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant */
10d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant#include <iostream>
11d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant#include "webrtc/modules/audio_device/dummy/file_audio_device.h"
12d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant#include "webrtc/system_wrappers/interface/sleep.h"
13d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant#include "webrtc/system_wrappers/interface/thread_wrapper.h"
14d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant
15d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantnamespace webrtc {
16d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant
17d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kRecordingFixedSampleRate = 48000;
18d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kRecordingNumChannels = 2;
19d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kPlayoutFixedSampleRate = 48000;
20d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kPlayoutNumChannels = 2;
21d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kPlayoutBufferSize = kPlayoutFixedSampleRate / 100
22d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant                         * kPlayoutNumChannels * 2;
23d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnantint kRecordingBufferSize = kRecordingFixedSampleRate / 100
24d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant                           * kRecordingNumChannels * 2;
25d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant
26d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward HinnantFileAudioDevice::FileAudioDevice(const int32_t id,
27d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant                                 const char* inputFilename,
28d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant                                 const char* outputFile):
29d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant    _ptrAudioBuffer(NULL),
30d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant    _recordingBuffer(NULL),
31d1176e29b01bebab9ca1b35bc9d457a4730cf84bHoward Hinnant    _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;
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
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
588