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