file_audio_device.cc (12788B)
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 "modules/audio_device/dummy/file_audio_device.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <cstring> 16 17 #include "absl/strings/string_view.h" 18 #include "api/audio/audio_device.h" 19 #include "api/audio/audio_device_defines.h" 20 #include "modules/audio_device/audio_device_buffer.h" 21 #include "modules/audio_device/audio_device_generic.h" 22 #include "rtc_base/checks.h" 23 #include "rtc_base/logging.h" 24 #include "rtc_base/platform_thread.h" 25 #include "rtc_base/synchronization/mutex.h" 26 #include "rtc_base/system/file_wrapper.h" 27 #include "rtc_base/thread.h" 28 #include "rtc_base/time_utils.h" 29 30 namespace webrtc { 31 32 const int kRecordingFixedSampleRate = 48000; 33 const size_t kRecordingNumChannels = 2; 34 const int kPlayoutFixedSampleRate = 48000; 35 const size_t kPlayoutNumChannels = 2; 36 const size_t kPlayoutBufferSize = 37 kPlayoutFixedSampleRate / 100 * kPlayoutNumChannels * 2; 38 const size_t kRecordingBufferSize = 39 kRecordingFixedSampleRate / 100 * kRecordingNumChannels * 2; 40 41 FileAudioDevice::FileAudioDevice(absl::string_view inputFilename, 42 absl::string_view outputFilename) 43 : _ptrAudioBuffer(nullptr), 44 _recordingBuffer(nullptr), 45 _playoutBuffer(nullptr), 46 _recordingFramesLeft(0), 47 _playoutFramesLeft(0), 48 _recordingBufferSizeIn10MS(0), 49 _recordingFramesIn10MS(0), 50 _playoutFramesIn10MS(0), 51 _playing(false), 52 _recording(false), 53 _lastCallPlayoutMillis(0), 54 _lastCallRecordMillis(0), 55 _outputFilename(outputFilename), 56 _inputFilename(inputFilename) {} 57 58 FileAudioDevice::~FileAudioDevice() {} 59 60 int32_t FileAudioDevice::ActiveAudioLayer( 61 AudioDeviceModule::AudioLayer& /* audioLayer */) const { 62 return -1; 63 } 64 65 AudioDeviceGeneric::InitStatus FileAudioDevice::Init() { 66 return InitStatus::OK; 67 } 68 69 int32_t FileAudioDevice::Terminate() { 70 return 0; 71 } 72 73 bool FileAudioDevice::Initialized() const { 74 return true; 75 } 76 77 int16_t FileAudioDevice::PlayoutDevices() { 78 return 1; 79 } 80 81 int16_t FileAudioDevice::RecordingDevices() { 82 return 1; 83 } 84 85 int32_t FileAudioDevice::PlayoutDeviceName(uint16_t index, 86 char name[kAdmMaxDeviceNameSize], 87 char guid[kAdmMaxGuidSize]) { 88 const char* kName = "dummy_device"; 89 const char* kGuid = "dummy_device_unique_id"; 90 if (index < 1) { 91 memset(name, 0, kAdmMaxDeviceNameSize); 92 memset(guid, 0, kAdmMaxGuidSize); 93 memcpy(name, kName, strlen(kName)); 94 memcpy(guid, kGuid, strlen(guid)); 95 return 0; 96 } 97 return -1; 98 } 99 100 int32_t FileAudioDevice::RecordingDeviceName(uint16_t index, 101 char name[kAdmMaxDeviceNameSize], 102 char guid[kAdmMaxGuidSize]) { 103 const char* kName = "dummy_device"; 104 const char* kGuid = "dummy_device_unique_id"; 105 if (index < 1) { 106 memset(name, 0, kAdmMaxDeviceNameSize); 107 memset(guid, 0, kAdmMaxGuidSize); 108 memcpy(name, kName, strlen(kName)); 109 memcpy(guid, kGuid, strlen(guid)); 110 return 0; 111 } 112 return -1; 113 } 114 115 int32_t FileAudioDevice::SetPlayoutDevice(uint16_t index) { 116 if (index == 0) { 117 _playout_index = index; 118 return 0; 119 } 120 return -1; 121 } 122 123 int32_t FileAudioDevice::SetPlayoutDevice( 124 AudioDeviceModule::WindowsDeviceType /* device */) { 125 return -1; 126 } 127 128 int32_t FileAudioDevice::SetRecordingDevice(uint16_t index) { 129 if (index == 0) { 130 _record_index = index; 131 return _record_index; 132 } 133 return -1; 134 } 135 136 int32_t FileAudioDevice::SetRecordingDevice( 137 AudioDeviceModule::WindowsDeviceType /* device */) { 138 return -1; 139 } 140 141 int32_t FileAudioDevice::PlayoutIsAvailable(bool& available) { 142 if (_playout_index == 0) { 143 available = true; 144 return _playout_index; 145 } 146 available = false; 147 return -1; 148 } 149 150 int32_t FileAudioDevice::InitPlayout() { 151 MutexLock lock(&mutex_); 152 153 if (_playing) { 154 return -1; 155 } 156 157 _playoutFramesIn10MS = static_cast<size_t>(kPlayoutFixedSampleRate / 100); 158 159 if (_ptrAudioBuffer) { 160 // Update webrtc audio buffer with the selected parameters 161 _ptrAudioBuffer->SetPlayoutSampleRate(kPlayoutFixedSampleRate); 162 _ptrAudioBuffer->SetPlayoutChannels(kPlayoutNumChannels); 163 } 164 return 0; 165 } 166 167 bool FileAudioDevice::PlayoutIsInitialized() const { 168 return _playoutFramesIn10MS != 0; 169 } 170 171 int32_t FileAudioDevice::RecordingIsAvailable(bool& available) { 172 if (_record_index == 0) { 173 available = true; 174 return _record_index; 175 } 176 available = false; 177 return -1; 178 } 179 180 int32_t FileAudioDevice::InitRecording() { 181 MutexLock lock(&mutex_); 182 183 if (_recording) { 184 return -1; 185 } 186 187 _recordingFramesIn10MS = static_cast<size_t>(kRecordingFixedSampleRate / 100); 188 189 if (_ptrAudioBuffer) { 190 _ptrAudioBuffer->SetRecordingSampleRate(kRecordingFixedSampleRate); 191 _ptrAudioBuffer->SetRecordingChannels(kRecordingNumChannels); 192 } 193 return 0; 194 } 195 196 bool FileAudioDevice::RecordingIsInitialized() const { 197 return _recordingFramesIn10MS != 0; 198 } 199 200 int32_t FileAudioDevice::StartPlayout() { 201 if (_playing) { 202 return 0; 203 } 204 205 _playing = true; 206 _playoutFramesLeft = 0; 207 208 if (!_playoutBuffer) { 209 _playoutBuffer = new int8_t[kPlayoutBufferSize]; 210 } 211 if (!_playoutBuffer) { 212 _playing = false; 213 return -1; 214 } 215 216 // PLAYOUT 217 if (!_outputFilename.empty()) { 218 _outputFile = FileWrapper::OpenWriteOnly(_outputFilename); 219 if (!_outputFile.is_open()) { 220 RTC_LOG(LS_ERROR) << "Failed to open playout file: " << _outputFilename; 221 _playing = false; 222 delete[] _playoutBuffer; 223 _playoutBuffer = nullptr; 224 return -1; 225 } 226 } 227 228 _ptrThreadPlay = PlatformThread::SpawnJoinable( 229 [this] { 230 while (PlayThreadProcess()) { 231 } 232 }, 233 "webrtc_audio_module_play_thread", 234 ThreadAttributes().SetPriority(ThreadPriority::kRealtime)); 235 236 RTC_LOG(LS_INFO) << "Started playout capture to output file: " 237 << _outputFilename; 238 return 0; 239 } 240 241 int32_t FileAudioDevice::StopPlayout() { 242 { 243 MutexLock lock(&mutex_); 244 _playing = false; 245 } 246 247 // stop playout thread first 248 if (!_ptrThreadPlay.empty()) 249 _ptrThreadPlay.Finalize(); 250 251 MutexLock lock(&mutex_); 252 253 _playoutFramesLeft = 0; 254 delete[] _playoutBuffer; 255 _playoutBuffer = nullptr; 256 _outputFile.Close(); 257 258 RTC_LOG(LS_INFO) << "Stopped playout capture to output file: " 259 << _outputFilename; 260 return 0; 261 } 262 263 bool FileAudioDevice::Playing() const { 264 return _playing; 265 } 266 267 int32_t FileAudioDevice::StartRecording() { 268 _recording = true; 269 270 // Make sure we only create the buffer once. 271 _recordingBufferSizeIn10MS = 272 _recordingFramesIn10MS * kRecordingNumChannels * 2; 273 if (!_recordingBuffer) { 274 _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS]; 275 } 276 277 if (!_inputFilename.empty()) { 278 _inputFile = FileWrapper::OpenReadOnly(_inputFilename); 279 if (!_inputFile.is_open()) { 280 RTC_LOG(LS_ERROR) << "Failed to open audio input file: " 281 << _inputFilename; 282 _recording = false; 283 delete[] _recordingBuffer; 284 _recordingBuffer = nullptr; 285 return -1; 286 } 287 } 288 289 _ptrThreadRec = PlatformThread::SpawnJoinable( 290 [this] { 291 while (RecThreadProcess()) { 292 } 293 }, 294 "webrtc_audio_module_capture_thread", 295 ThreadAttributes().SetPriority(ThreadPriority::kRealtime)); 296 297 RTC_LOG(LS_INFO) << "Started recording from input file: " << _inputFilename; 298 299 return 0; 300 } 301 302 int32_t FileAudioDevice::StopRecording() { 303 { 304 MutexLock lock(&mutex_); 305 _recording = false; 306 } 307 308 if (!_ptrThreadRec.empty()) 309 _ptrThreadRec.Finalize(); 310 311 MutexLock lock(&mutex_); 312 _recordingFramesLeft = 0; 313 if (_recordingBuffer) { 314 delete[] _recordingBuffer; 315 _recordingBuffer = nullptr; 316 } 317 _inputFile.Close(); 318 319 RTC_LOG(LS_INFO) << "Stopped recording from input file: " << _inputFilename; 320 return 0; 321 } 322 323 bool FileAudioDevice::Recording() const { 324 return _recording; 325 } 326 327 int32_t FileAudioDevice::InitSpeaker() { 328 return -1; 329 } 330 331 bool FileAudioDevice::SpeakerIsInitialized() const { 332 return false; 333 } 334 335 int32_t FileAudioDevice::InitMicrophone() { 336 return 0; 337 } 338 339 bool FileAudioDevice::MicrophoneIsInitialized() const { 340 return true; 341 } 342 343 int32_t FileAudioDevice::SpeakerVolumeIsAvailable(bool& /* available */) { 344 return -1; 345 } 346 347 int32_t FileAudioDevice::SetSpeakerVolume(uint32_t /* volume */) { 348 return -1; 349 } 350 351 int32_t FileAudioDevice::SpeakerVolume(uint32_t& /* volume */) const { 352 return -1; 353 } 354 355 int32_t FileAudioDevice::MaxSpeakerVolume(uint32_t& /* maxVolume */) const { 356 return -1; 357 } 358 359 int32_t FileAudioDevice::MinSpeakerVolume(uint32_t& /* minVolume */) const { 360 return -1; 361 } 362 363 int32_t FileAudioDevice::MicrophoneVolumeIsAvailable(bool& /* available */) { 364 return -1; 365 } 366 367 int32_t FileAudioDevice::SetMicrophoneVolume(uint32_t /* volume */) { 368 return -1; 369 } 370 371 int32_t FileAudioDevice::MicrophoneVolume(uint32_t& /* volume */) const { 372 return -1; 373 } 374 375 int32_t FileAudioDevice::MaxMicrophoneVolume(uint32_t& /* maxVolume */) const { 376 return -1; 377 } 378 379 int32_t FileAudioDevice::MinMicrophoneVolume(uint32_t& /* minVolume */) const { 380 return -1; 381 } 382 383 int32_t FileAudioDevice::SpeakerMuteIsAvailable(bool& /* available */) { 384 return -1; 385 } 386 387 int32_t FileAudioDevice::SetSpeakerMute(bool /* enable */) { 388 return -1; 389 } 390 391 int32_t FileAudioDevice::SpeakerMute(bool& /* enabled */) const { 392 return -1; 393 } 394 395 int32_t FileAudioDevice::MicrophoneMuteIsAvailable(bool& /* available */) { 396 return -1; 397 } 398 399 int32_t FileAudioDevice::SetMicrophoneMute(bool /* enable */) { 400 return -1; 401 } 402 403 int32_t FileAudioDevice::MicrophoneMute(bool& /* enabled */) const { 404 return -1; 405 } 406 407 int32_t FileAudioDevice::StereoPlayoutIsAvailable(bool& available) { 408 available = true; 409 return 0; 410 } 411 int32_t FileAudioDevice::SetStereoPlayout(bool /* enable */) { 412 return 0; 413 } 414 415 int32_t FileAudioDevice::StereoPlayout(bool& enabled) const { 416 enabled = true; 417 return 0; 418 } 419 420 int32_t FileAudioDevice::StereoRecordingIsAvailable(bool& available) { 421 available = true; 422 return 0; 423 } 424 425 int32_t FileAudioDevice::SetStereoRecording(bool /* enable */) { 426 return 0; 427 } 428 429 int32_t FileAudioDevice::StereoRecording(bool& enabled) const { 430 enabled = true; 431 return 0; 432 } 433 434 int32_t FileAudioDevice::PlayoutDelay(uint16_t& /* delayMS */) const { 435 return 0; 436 } 437 438 void FileAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { 439 MutexLock lock(&mutex_); 440 441 _ptrAudioBuffer = audioBuffer; 442 443 // Inform the AudioBuffer about default settings for this implementation. 444 // Set all values to zero here since the actual settings will be done by 445 // InitPlayout and InitRecording later. 446 _ptrAudioBuffer->SetRecordingSampleRate(0); 447 _ptrAudioBuffer->SetPlayoutSampleRate(0); 448 _ptrAudioBuffer->SetRecordingChannels(0); 449 _ptrAudioBuffer->SetPlayoutChannels(0); 450 } 451 452 bool FileAudioDevice::PlayThreadProcess() { 453 if (!_playing) { 454 return false; 455 } 456 int64_t currentTime = TimeMillis(); 457 mutex_.Lock(); 458 459 if (_lastCallPlayoutMillis == 0 || 460 currentTime - _lastCallPlayoutMillis >= 10) { 461 mutex_.Unlock(); 462 _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS); 463 mutex_.Lock(); 464 465 _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer); 466 RTC_DCHECK_EQ(_playoutFramesIn10MS, _playoutFramesLeft); 467 if (_outputFile.is_open()) { 468 _outputFile.Write(_playoutBuffer, kPlayoutBufferSize); 469 } 470 _lastCallPlayoutMillis = currentTime; 471 } 472 _playoutFramesLeft = 0; 473 mutex_.Unlock(); 474 475 int64_t deltaTimeMillis = TimeMillis() - currentTime; 476 if (deltaTimeMillis < 10) { 477 Thread::SleepMs(10 - deltaTimeMillis); 478 } 479 480 return true; 481 } 482 483 bool FileAudioDevice::RecThreadProcess() { 484 if (!_recording) { 485 return false; 486 } 487 488 int64_t currentTime = TimeMillis(); 489 mutex_.Lock(); 490 491 if (_lastCallRecordMillis == 0 || currentTime - _lastCallRecordMillis >= 10) { 492 if (_inputFile.is_open()) { 493 if (_inputFile.Read(_recordingBuffer, kRecordingBufferSize) > 0) { 494 _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer, 495 _recordingFramesIn10MS); 496 } else { 497 _inputFile.Rewind(); 498 } 499 _lastCallRecordMillis = currentTime; 500 mutex_.Unlock(); 501 _ptrAudioBuffer->DeliverRecordedData(); 502 mutex_.Lock(); 503 } 504 } 505 506 mutex_.Unlock(); 507 508 int64_t deltaTimeMillis = TimeMillis() - currentTime; 509 if (deltaTimeMillis < 10) { 510 Thread::SleepMs(10 - deltaTimeMillis); 511 } 512 513 return true; 514 } 515 516 } // namespace webrtc