audio_device_alsa_linux.cc (47286B)
1 /* 2 * Copyright (c) 2012 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/linux/audio_device_alsa_linux.h" 12 13 #include <asm-generic/errno.h> 14 15 #include <cerrno> 16 #include <cstdint> 17 #include <cstdlib> 18 #include <cstring> 19 #include <vector> 20 21 #include "api/audio/audio_device.h" 22 #include "api/audio/audio_device_defines.h" 23 #include "modules/audio_device/audio_device_buffer.h" 24 #include "modules/audio_device/audio_device_generic.h" 25 #include "modules/audio_device/linux/latebindingsymboltable_linux.h" 26 #include "rtc_base/checks.h" 27 #include "rtc_base/logging.h" 28 #include "rtc_base/platform_thread.h" 29 #include "rtc_base/synchronization/mutex.h" 30 #include "rtc_base/thread.h" 31 32 #if defined(WEBRTC_USE_X11) 33 #include <X11/Xlib.h> 34 #endif 35 36 WebRTCAlsaSymbolTable* GetAlsaSymbolTable() { 37 static WebRTCAlsaSymbolTable* alsa_symbol_table = new WebRTCAlsaSymbolTable(); 38 return alsa_symbol_table; 39 } 40 41 // Accesses ALSA functions through our late-binding symbol table instead of 42 // directly. This way we don't have to link to libasound, which means our binary 43 // will work on systems that don't have it. 44 #define LATE(sym) \ 45 LATESYM_GET(webrtc::adm_linux_alsa::AlsaSymbolTable, GetAlsaSymbolTable(), \ 46 sym) 47 48 // Redefine these here to be able to do late-binding 49 #undef snd_ctl_card_info_alloca 50 #define snd_ctl_card_info_alloca(ptr) \ 51 do { \ 52 *ptr = (snd_ctl_card_info_t*)__builtin_alloca( \ 53 LATE(snd_ctl_card_info_sizeof)()); \ 54 memset(*ptr, 0, LATE(snd_ctl_card_info_sizeof)()); \ 55 } while (0) 56 57 #undef snd_pcm_info_alloca 58 #define snd_pcm_info_alloca(pInfo) \ 59 do { \ 60 *pInfo = (snd_pcm_info_t*)__builtin_alloca(LATE(snd_pcm_info_sizeof)()); \ 61 memset(*pInfo, 0, LATE(snd_pcm_info_sizeof)()); \ 62 } while (0) 63 64 // snd_lib_error_handler_t 65 void WebrtcAlsaErrorHandler(const char* file, 66 int line, 67 const char* function, 68 int err, 69 const char* fmt, 70 ...) {} 71 72 namespace webrtc { 73 static const unsigned int ALSA_PLAYOUT_FREQ = 48000; 74 static const unsigned int ALSA_PLAYOUT_CH = 2; 75 static const unsigned int ALSA_PLAYOUT_LATENCY = 40 * 1000; // in us 76 static const unsigned int ALSA_CAPTURE_FREQ = 48000; 77 static const unsigned int ALSA_CAPTURE_CH = 2; 78 static const unsigned int ALSA_CAPTURE_LATENCY = 40 * 1000; // in us 79 static const unsigned int ALSA_CAPTURE_WAIT_TIMEOUT = 5; // in ms 80 81 #define FUNC_GET_NUM_OF_DEVICE 0 82 #define FUNC_GET_DEVICE_NAME 1 83 #define FUNC_GET_DEVICE_NAME_FOR_AN_ENUM 2 84 85 AudioDeviceLinuxALSA::AudioDeviceLinuxALSA() 86 : _ptrAudioBuffer(nullptr), 87 _inputDeviceIndex(0), 88 _outputDeviceIndex(0), 89 _inputDeviceIsSpecified(false), 90 _outputDeviceIsSpecified(false), 91 _handleRecord(nullptr), 92 _handlePlayout(nullptr), 93 _recordingBuffersizeInFrame(0), 94 _recordingPeriodSizeInFrame(0), 95 _playoutBufferSizeInFrame(0), 96 _playoutPeriodSizeInFrame(0), 97 _recordingBufferSizeIn10MS(0), 98 _playoutBufferSizeIn10MS(0), 99 _recordingFramesIn10MS(0), 100 _playoutFramesIn10MS(0), 101 _recordingFreq(ALSA_CAPTURE_FREQ), 102 _playoutFreq(ALSA_PLAYOUT_FREQ), 103 _recChannels(ALSA_CAPTURE_CH), 104 _playChannels(ALSA_PLAYOUT_CH), 105 _recordingBuffer(nullptr), 106 _playoutBuffer(nullptr), 107 _recordingFramesLeft(0), 108 _playoutFramesLeft(0), 109 _initialized(false), 110 _recording(false), 111 _playing(false), 112 _recIsInitialized(false), 113 _playIsInitialized(false), 114 _recordingDelay(0), 115 _playoutDelay(0) { 116 memset(_oldKeyState, 0, sizeof(_oldKeyState)); 117 RTC_DLOG(LS_INFO) << __FUNCTION__ << " created"; 118 } 119 120 // ---------------------------------------------------------------------------- 121 // AudioDeviceLinuxALSA - dtor 122 // ---------------------------------------------------------------------------- 123 124 AudioDeviceLinuxALSA::~AudioDeviceLinuxALSA() { 125 RTC_DLOG(LS_INFO) << __FUNCTION__ << " destroyed"; 126 127 Terminate(); 128 129 // Clean up the recording buffer and playout buffer. 130 if (_recordingBuffer) { 131 delete[] _recordingBuffer; 132 _recordingBuffer = nullptr; 133 } 134 if (_playoutBuffer) { 135 delete[] _playoutBuffer; 136 _playoutBuffer = nullptr; 137 } 138 } 139 140 void AudioDeviceLinuxALSA::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { 141 MutexLock lock(&mutex_); 142 143 _ptrAudioBuffer = audioBuffer; 144 145 // Inform the AudioBuffer about default settings for this implementation. 146 // Set all values to zero here since the actual settings will be done by 147 // InitPlayout and InitRecording later. 148 _ptrAudioBuffer->SetRecordingSampleRate(0); 149 _ptrAudioBuffer->SetPlayoutSampleRate(0); 150 _ptrAudioBuffer->SetRecordingChannels(0); 151 _ptrAudioBuffer->SetPlayoutChannels(0); 152 } 153 154 int32_t AudioDeviceLinuxALSA::ActiveAudioLayer( 155 AudioDeviceModule::AudioLayer& audioLayer) const { 156 audioLayer = AudioDeviceModule::kLinuxAlsaAudio; 157 return 0; 158 } 159 160 AudioDeviceGeneric::InitStatus AudioDeviceLinuxALSA::Init() { 161 MutexLock lock(&mutex_); 162 163 // Load libasound 164 if (!GetAlsaSymbolTable()->Load()) { 165 // Alsa is not installed on this system 166 RTC_LOG(LS_ERROR) << "failed to load symbol table"; 167 return InitStatus::OTHER_ERROR; 168 } 169 170 if (_initialized) { 171 return InitStatus::OK; 172 } 173 #if defined(WEBRTC_USE_X11) 174 // Get X display handle for typing detection 175 _XDisplay = XOpenDisplay(nullptr); 176 if (!_XDisplay) { 177 RTC_LOG(LS_WARNING) 178 << "failed to open X display, typing detection will not work"; 179 } 180 #endif 181 182 _initialized = true; 183 184 return InitStatus::OK; 185 } 186 187 int32_t AudioDeviceLinuxALSA::Terminate() { 188 if (!_initialized) { 189 return 0; 190 } 191 192 MutexLock lock(&mutex_); 193 194 _mixerManager.Close(); 195 196 // RECORDING 197 mutex_.Unlock(); 198 _ptrThreadRec.Finalize(); 199 200 // PLAYOUT 201 _ptrThreadPlay.Finalize(); 202 mutex_.Lock(); 203 204 #if defined(WEBRTC_USE_X11) 205 if (_XDisplay) { 206 XCloseDisplay(_XDisplay); 207 _XDisplay = nullptr; 208 } 209 #endif 210 _initialized = false; 211 _outputDeviceIsSpecified = false; 212 _inputDeviceIsSpecified = false; 213 214 return 0; 215 } 216 217 bool AudioDeviceLinuxALSA::Initialized() const { 218 return (_initialized); 219 } 220 221 int32_t AudioDeviceLinuxALSA::InitSpeaker() { 222 MutexLock lock(&mutex_); 223 return InitSpeakerLocked(); 224 } 225 226 int32_t AudioDeviceLinuxALSA::InitSpeakerLocked() { 227 if (_playing) { 228 return -1; 229 } 230 231 char devName[kAdmMaxDeviceNameSize] = {0}; 232 GetDevicesInfo(2, true, _outputDeviceIndex, devName, kAdmMaxDeviceNameSize); 233 return _mixerManager.OpenSpeaker(devName); 234 } 235 236 int32_t AudioDeviceLinuxALSA::InitMicrophone() { 237 MutexLock lock(&mutex_); 238 return InitMicrophoneLocked(); 239 } 240 241 int32_t AudioDeviceLinuxALSA::InitMicrophoneLocked() { 242 if (_recording) { 243 return -1; 244 } 245 246 char devName[kAdmMaxDeviceNameSize] = {0}; 247 GetDevicesInfo(2, false, _inputDeviceIndex, devName, kAdmMaxDeviceNameSize); 248 return _mixerManager.OpenMicrophone(devName); 249 } 250 251 bool AudioDeviceLinuxALSA::SpeakerIsInitialized() const { 252 return (_mixerManager.SpeakerIsInitialized()); 253 } 254 255 bool AudioDeviceLinuxALSA::MicrophoneIsInitialized() const { 256 return (_mixerManager.MicrophoneIsInitialized()); 257 } 258 259 int32_t AudioDeviceLinuxALSA::SpeakerVolumeIsAvailable(bool& available) { 260 bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 261 262 // Make an attempt to open up the 263 // output mixer corresponding to the currently selected output device. 264 if (!wasInitialized && InitSpeaker() == -1) { 265 // If we end up here it means that the selected speaker has no volume 266 // control. 267 available = false; 268 return 0; 269 } 270 271 // Given that InitSpeaker was successful, we know that a volume control 272 // exists 273 available = true; 274 275 // Close the initialized output mixer 276 if (!wasInitialized) { 277 _mixerManager.CloseSpeaker(); 278 } 279 280 return 0; 281 } 282 283 int32_t AudioDeviceLinuxALSA::SetSpeakerVolume(uint32_t volume) { 284 return (_mixerManager.SetSpeakerVolume(volume)); 285 } 286 287 int32_t AudioDeviceLinuxALSA::SpeakerVolume(uint32_t& volume) const { 288 uint32_t level(0); 289 290 if (_mixerManager.SpeakerVolume(level) == -1) { 291 return -1; 292 } 293 294 volume = level; 295 296 return 0; 297 } 298 299 int32_t AudioDeviceLinuxALSA::MaxSpeakerVolume(uint32_t& maxVolume) const { 300 uint32_t maxVol(0); 301 302 if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) { 303 return -1; 304 } 305 306 maxVolume = maxVol; 307 308 return 0; 309 } 310 311 int32_t AudioDeviceLinuxALSA::MinSpeakerVolume(uint32_t& minVolume) const { 312 uint32_t minVol(0); 313 314 if (_mixerManager.MinSpeakerVolume(minVol) == -1) { 315 return -1; 316 } 317 318 minVolume = minVol; 319 320 return 0; 321 } 322 323 int32_t AudioDeviceLinuxALSA::SpeakerMuteIsAvailable(bool& available) { 324 bool isAvailable(false); 325 bool wasInitialized = _mixerManager.SpeakerIsInitialized(); 326 327 // Make an attempt to open up the 328 // output mixer corresponding to the currently selected output device. 329 // 330 if (!wasInitialized && InitSpeaker() == -1) { 331 // If we end up here it means that the selected speaker has no volume 332 // control, hence it is safe to state that there is no mute control 333 // already at this stage. 334 available = false; 335 return 0; 336 } 337 338 // Check if the selected speaker has a mute control 339 _mixerManager.SpeakerMuteIsAvailable(isAvailable); 340 341 available = isAvailable; 342 343 // Close the initialized output mixer 344 if (!wasInitialized) { 345 _mixerManager.CloseSpeaker(); 346 } 347 348 return 0; 349 } 350 351 int32_t AudioDeviceLinuxALSA::SetSpeakerMute(bool enable) { 352 return (_mixerManager.SetSpeakerMute(enable)); 353 } 354 355 int32_t AudioDeviceLinuxALSA::SpeakerMute(bool& enabled) const { 356 bool muted(0); 357 358 if (_mixerManager.SpeakerMute(muted) == -1) { 359 return -1; 360 } 361 362 enabled = muted; 363 364 return 0; 365 } 366 367 int32_t AudioDeviceLinuxALSA::MicrophoneMuteIsAvailable(bool& available) { 368 bool isAvailable(false); 369 bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 370 371 // Make an attempt to open up the 372 // input mixer corresponding to the currently selected input device. 373 // 374 if (!wasInitialized && InitMicrophone() == -1) { 375 // If we end up here it means that the selected microphone has no volume 376 // control, hence it is safe to state that there is no mute control 377 // already at this stage. 378 available = false; 379 return 0; 380 } 381 382 // Check if the selected microphone has a mute control 383 // 384 _mixerManager.MicrophoneMuteIsAvailable(isAvailable); 385 available = isAvailable; 386 387 // Close the initialized input mixer 388 // 389 if (!wasInitialized) { 390 _mixerManager.CloseMicrophone(); 391 } 392 393 return 0; 394 } 395 396 int32_t AudioDeviceLinuxALSA::SetMicrophoneMute(bool enable) { 397 return (_mixerManager.SetMicrophoneMute(enable)); 398 } 399 400 // ---------------------------------------------------------------------------- 401 // MicrophoneMute 402 // ---------------------------------------------------------------------------- 403 404 int32_t AudioDeviceLinuxALSA::MicrophoneMute(bool& enabled) const { 405 bool muted(0); 406 407 if (_mixerManager.MicrophoneMute(muted) == -1) { 408 return -1; 409 } 410 411 enabled = muted; 412 return 0; 413 } 414 415 int32_t AudioDeviceLinuxALSA::StereoRecordingIsAvailable(bool& available) { 416 MutexLock lock(&mutex_); 417 418 // If we already have initialized in stereo it's obviously available 419 if (_recIsInitialized && (2 == _recChannels)) { 420 available = true; 421 return 0; 422 } 423 424 // Save rec states and the number of rec channels 425 bool recIsInitialized = _recIsInitialized; 426 bool recording = _recording; 427 int recChannels = _recChannels; 428 429 available = false; 430 431 // Stop/uninitialize recording if initialized (and possibly started) 432 if (_recIsInitialized) { 433 StopRecordingLocked(); 434 } 435 436 // Try init in stereo; 437 _recChannels = 2; 438 if (InitRecordingLocked() == 0) { 439 available = true; 440 } 441 442 // Stop/uninitialize recording 443 StopRecordingLocked(); 444 445 // Recover previous states 446 _recChannels = recChannels; 447 if (recIsInitialized) { 448 InitRecordingLocked(); 449 } 450 if (recording) { 451 StartRecording(); 452 } 453 454 return 0; 455 } 456 457 int32_t AudioDeviceLinuxALSA::SetStereoRecording(bool enable) { 458 if (enable) 459 _recChannels = 2; 460 else 461 _recChannels = 1; 462 463 return 0; 464 } 465 466 int32_t AudioDeviceLinuxALSA::StereoRecording(bool& enabled) const { 467 if (_recChannels == 2) 468 enabled = true; 469 else 470 enabled = false; 471 472 return 0; 473 } 474 475 int32_t AudioDeviceLinuxALSA::StereoPlayoutIsAvailable(bool& available) { 476 MutexLock lock(&mutex_); 477 478 // If we already have initialized in stereo it's obviously available 479 if (_playIsInitialized && (2 == _playChannels)) { 480 available = true; 481 return 0; 482 } 483 484 // Save rec states and the number of rec channels 485 bool playIsInitialized = _playIsInitialized; 486 bool playing = _playing; 487 int playChannels = _playChannels; 488 489 available = false; 490 491 // Stop/uninitialize recording if initialized (and possibly started) 492 if (_playIsInitialized) { 493 StopPlayoutLocked(); 494 } 495 496 // Try init in stereo; 497 _playChannels = 2; 498 if (InitPlayoutLocked() == 0) { 499 available = true; 500 } 501 502 // Stop/uninitialize recording 503 StopPlayoutLocked(); 504 505 // Recover previous states 506 _playChannels = playChannels; 507 if (playIsInitialized) { 508 InitPlayoutLocked(); 509 } 510 if (playing) { 511 StartPlayout(); 512 } 513 514 return 0; 515 } 516 517 int32_t AudioDeviceLinuxALSA::SetStereoPlayout(bool enable) { 518 if (enable) 519 _playChannels = 2; 520 else 521 _playChannels = 1; 522 523 return 0; 524 } 525 526 int32_t AudioDeviceLinuxALSA::StereoPlayout(bool& enabled) const { 527 if (_playChannels == 2) 528 enabled = true; 529 else 530 enabled = false; 531 532 return 0; 533 } 534 535 int32_t AudioDeviceLinuxALSA::MicrophoneVolumeIsAvailable(bool& available) { 536 bool wasInitialized = _mixerManager.MicrophoneIsInitialized(); 537 538 // Make an attempt to open up the 539 // input mixer corresponding to the currently selected output device. 540 if (!wasInitialized && InitMicrophone() == -1) { 541 // If we end up here it means that the selected microphone has no volume 542 // control. 543 available = false; 544 return 0; 545 } 546 547 // Given that InitMicrophone was successful, we know that a volume control 548 // exists 549 available = true; 550 551 // Close the initialized input mixer 552 if (!wasInitialized) { 553 _mixerManager.CloseMicrophone(); 554 } 555 556 return 0; 557 } 558 559 int32_t AudioDeviceLinuxALSA::SetMicrophoneVolume(uint32_t volume) { 560 return (_mixerManager.SetMicrophoneVolume(volume)); 561 } 562 563 int32_t AudioDeviceLinuxALSA::MicrophoneVolume(uint32_t& volume) const { 564 uint32_t level(0); 565 566 if (_mixerManager.MicrophoneVolume(level) == -1) { 567 RTC_LOG(LS_WARNING) << "failed to retrive current microphone level"; 568 return -1; 569 } 570 571 volume = level; 572 573 return 0; 574 } 575 576 int32_t AudioDeviceLinuxALSA::MaxMicrophoneVolume(uint32_t& maxVolume) const { 577 uint32_t maxVol(0); 578 579 if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) { 580 return -1; 581 } 582 583 maxVolume = maxVol; 584 585 return 0; 586 } 587 588 int32_t AudioDeviceLinuxALSA::MinMicrophoneVolume(uint32_t& minVolume) const { 589 uint32_t minVol(0); 590 591 if (_mixerManager.MinMicrophoneVolume(minVol) == -1) { 592 return -1; 593 } 594 595 minVolume = minVol; 596 597 return 0; 598 } 599 600 int16_t AudioDeviceLinuxALSA::PlayoutDevices() { 601 return (int16_t)GetDevicesInfo(0, true); 602 } 603 604 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(uint16_t index) { 605 if (_playIsInitialized) { 606 return -1; 607 } 608 609 int32_t nDevices = GetDevicesInfo(0, true); 610 RTC_LOG(LS_VERBOSE) << "number of available audio output devices is " 611 << nDevices; 612 613 if (index > (nDevices - 1)) { 614 RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1) 615 << "]"; 616 return -1; 617 } 618 619 _outputDeviceIndex = index; 620 _outputDeviceIsSpecified = true; 621 622 return 0; 623 } 624 625 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice( 626 AudioDeviceModule::WindowsDeviceType /*device*/) { 627 RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported"; 628 return -1; 629 } 630 631 int32_t AudioDeviceLinuxALSA::PlayoutDeviceName( 632 uint16_t index, 633 char name[kAdmMaxDeviceNameSize], 634 char guid[kAdmMaxGuidSize]) { 635 const uint16_t nDevices(PlayoutDevices()); 636 637 if ((index > (nDevices - 1)) || (name == nullptr)) { 638 return -1; 639 } 640 641 memset(name, 0, kAdmMaxDeviceNameSize); 642 643 if (guid != nullptr) { 644 memset(guid, 0, kAdmMaxGuidSize); 645 } 646 647 return GetDevicesInfo(1, true, index, name, kAdmMaxDeviceNameSize); 648 } 649 650 int32_t AudioDeviceLinuxALSA::RecordingDeviceName( 651 uint16_t index, 652 char name[kAdmMaxDeviceNameSize], 653 char guid[kAdmMaxGuidSize]) { 654 const uint16_t nDevices(RecordingDevices()); 655 656 if ((index > (nDevices - 1)) || (name == nullptr)) { 657 return -1; 658 } 659 660 memset(name, 0, kAdmMaxDeviceNameSize); 661 662 if (guid != nullptr) { 663 memset(guid, 0, kAdmMaxGuidSize); 664 } 665 666 return GetDevicesInfo(1, false, index, name, kAdmMaxDeviceNameSize); 667 } 668 669 int16_t AudioDeviceLinuxALSA::RecordingDevices() { 670 return (int16_t)GetDevicesInfo(0, false); 671 } 672 673 int32_t AudioDeviceLinuxALSA::SetRecordingDevice(uint16_t index) { 674 if (_recIsInitialized) { 675 return -1; 676 } 677 678 int32_t nDevices = GetDevicesInfo(0, false); 679 RTC_LOG(LS_VERBOSE) << "number of availiable audio input devices is " 680 << nDevices; 681 682 if (index > (nDevices - 1)) { 683 RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1) 684 << "]"; 685 return -1; 686 } 687 688 _inputDeviceIndex = index; 689 _inputDeviceIsSpecified = true; 690 691 return 0; 692 } 693 694 // ---------------------------------------------------------------------------- 695 // SetRecordingDevice II (II) 696 // ---------------------------------------------------------------------------- 697 698 int32_t AudioDeviceLinuxALSA::SetRecordingDevice( 699 AudioDeviceModule::WindowsDeviceType /*device*/) { 700 RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported"; 701 return -1; 702 } 703 704 int32_t AudioDeviceLinuxALSA::PlayoutIsAvailable(bool& available) { 705 available = false; 706 707 // Try to initialize the playout side with mono 708 // Assumes that user set num channels after calling this function 709 _playChannels = 1; 710 int32_t res = InitPlayout(); 711 712 // Cancel effect of initialization 713 StopPlayout(); 714 715 if (res != -1) { 716 available = true; 717 } else { 718 // It may be possible to play out in stereo 719 res = StereoPlayoutIsAvailable(available); 720 if (available) { 721 // Then set channels to 2 so InitPlayout doesn't fail 722 _playChannels = 2; 723 } 724 } 725 726 return res; 727 } 728 729 int32_t AudioDeviceLinuxALSA::RecordingIsAvailable(bool& available) { 730 available = false; 731 732 // Try to initialize the recording side with mono 733 // Assumes that user set num channels after calling this function 734 _recChannels = 1; 735 int32_t res = InitRecording(); 736 737 // Cancel effect of initialization 738 StopRecording(); 739 740 if (res != -1) { 741 available = true; 742 } else { 743 // It may be possible to record in stereo 744 res = StereoRecordingIsAvailable(available); 745 if (available) { 746 // Then set channels to 2 so InitPlayout doesn't fail 747 _recChannels = 2; 748 } 749 } 750 751 return res; 752 } 753 754 int32_t AudioDeviceLinuxALSA::InitPlayout() { 755 MutexLock lock(&mutex_); 756 return InitPlayoutLocked(); 757 } 758 759 int32_t AudioDeviceLinuxALSA::InitPlayoutLocked() { 760 int errVal = 0; 761 762 if (_playing) { 763 return -1; 764 } 765 766 if (!_outputDeviceIsSpecified) { 767 return -1; 768 } 769 770 if (_playIsInitialized) { 771 return 0; 772 } 773 // Initialize the speaker (devices might have been added or removed) 774 if (InitSpeakerLocked() == -1) { 775 RTC_LOG(LS_WARNING) << "InitSpeaker() failed"; 776 } 777 778 // Start by closing any existing wave-output devices 779 // 780 if (_handlePlayout != nullptr) { 781 LATE(snd_pcm_close)(_handlePlayout); 782 _handlePlayout = nullptr; 783 _playIsInitialized = false; 784 if (errVal < 0) { 785 RTC_LOG(LS_ERROR) << "Error closing current playout sound device, error: " 786 << LATE(snd_strerror)(errVal); 787 } 788 } 789 790 // Open PCM device for playout 791 char deviceName[kAdmMaxDeviceNameSize] = {0}; 792 GetDevicesInfo(2, true, _outputDeviceIndex, deviceName, 793 kAdmMaxDeviceNameSize); 794 795 RTC_LOG(LS_VERBOSE) << "InitPlayout open (" << deviceName << ")"; 796 797 errVal = LATE(snd_pcm_open)(&_handlePlayout, deviceName, 798 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 799 800 if (errVal == -EBUSY) // Device busy - try some more! 801 { 802 for (int i = 0; i < 5; i++) { 803 Thread::SleepMs(1000); 804 errVal = LATE(snd_pcm_open)(&_handlePlayout, deviceName, 805 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 806 if (errVal == 0) { 807 break; 808 } 809 } 810 } 811 if (errVal < 0) { 812 RTC_LOG(LS_ERROR) << "unable to open playback device: " 813 << LATE(snd_strerror)(errVal) << " (" << errVal << ")"; 814 _handlePlayout = nullptr; 815 return -1; 816 } 817 818 _playoutFramesIn10MS = _playoutFreq / 100; 819 if ((errVal = LATE(snd_pcm_set_params)( 820 _handlePlayout, 821 #if defined(WEBRTC_ARCH_BIG_ENDIAN) 822 SND_PCM_FORMAT_S16_BE, 823 #else 824 SND_PCM_FORMAT_S16_LE, // format 825 #endif 826 SND_PCM_ACCESS_RW_INTERLEAVED, // access 827 _playChannels, // channels 828 _playoutFreq, // rate 829 1, // soft_resample 830 ALSA_PLAYOUT_LATENCY // 40*1000 //latency required overall latency 831 // in us 832 )) < 0) { /* 0.5sec */ 833 _playoutFramesIn10MS = 0; 834 RTC_LOG(LS_ERROR) << "unable to set playback device: " 835 << LATE(snd_strerror)(errVal) << " (" << errVal << ")"; 836 ErrorRecovery(errVal, _handlePlayout); 837 errVal = LATE(snd_pcm_close)(_handlePlayout); 838 _handlePlayout = nullptr; 839 return -1; 840 } 841 842 errVal = LATE(snd_pcm_get_params)(_handlePlayout, &_playoutBufferSizeInFrame, 843 &_playoutPeriodSizeInFrame); 844 if (errVal < 0) { 845 RTC_LOG(LS_ERROR) << "snd_pcm_get_params: " << LATE(snd_strerror)(errVal) 846 << " (" << errVal << ")"; 847 _playoutBufferSizeInFrame = 0; 848 _playoutPeriodSizeInFrame = 0; 849 } else { 850 RTC_LOG(LS_VERBOSE) << "playout snd_pcm_get_params buffer_size:" 851 << _playoutBufferSizeInFrame 852 << " period_size :" << _playoutPeriodSizeInFrame; 853 } 854 855 if (_ptrAudioBuffer) { 856 // Update webrtc audio buffer with the selected parameters 857 _ptrAudioBuffer->SetPlayoutSampleRate(_playoutFreq); 858 _ptrAudioBuffer->SetPlayoutChannels(_playChannels); 859 } 860 861 // Set play buffer size 862 _playoutBufferSizeIn10MS = 863 LATE(snd_pcm_frames_to_bytes)(_handlePlayout, _playoutFramesIn10MS); 864 865 // Init varaibles used for play 866 867 if (_handlePlayout != nullptr) { 868 _playIsInitialized = true; 869 return 0; 870 } else { 871 return -1; 872 } 873 } 874 875 int32_t AudioDeviceLinuxALSA::InitRecording() { 876 MutexLock lock(&mutex_); 877 return InitRecordingLocked(); 878 } 879 880 int32_t AudioDeviceLinuxALSA::InitRecordingLocked() { 881 int errVal = 0; 882 883 if (_recording) { 884 return -1; 885 } 886 887 if (!_inputDeviceIsSpecified) { 888 return -1; 889 } 890 891 if (_recIsInitialized) { 892 return 0; 893 } 894 895 // Initialize the microphone (devices might have been added or removed) 896 if (InitMicrophoneLocked() == -1) { 897 RTC_LOG(LS_WARNING) << "InitMicrophone() failed"; 898 } 899 900 // Start by closing any existing pcm-input devices 901 // 902 if (_handleRecord != nullptr) { 903 errVal = LATE(snd_pcm_close)(_handleRecord); 904 _handleRecord = nullptr; 905 _recIsInitialized = false; 906 if (errVal < 0) { 907 RTC_LOG(LS_ERROR) 908 << "Error closing current recording sound device, error: " 909 << LATE(snd_strerror)(errVal); 910 } 911 } 912 913 // Open PCM device for recording 914 // The corresponding settings for playout are made after the record settings 915 char deviceName[kAdmMaxDeviceNameSize] = {0}; 916 GetDevicesInfo(2, false, _inputDeviceIndex, deviceName, 917 kAdmMaxDeviceNameSize); 918 919 RTC_LOG(LS_VERBOSE) << "InitRecording open (" << deviceName << ")"; 920 errVal = LATE(snd_pcm_open)(&_handleRecord, deviceName, 921 SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); 922 923 // Available modes: 0 = blocking, SND_PCM_NONBLOCK, SND_PCM_ASYNC 924 if (errVal == -EBUSY) // Device busy - try some more! 925 { 926 for (int i = 0; i < 5; i++) { 927 Thread::SleepMs(1000); 928 errVal = LATE(snd_pcm_open)(&_handleRecord, deviceName, 929 SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); 930 if (errVal == 0) { 931 break; 932 } 933 } 934 } 935 if (errVal < 0) { 936 RTC_LOG(LS_ERROR) << "unable to open record device: " 937 << LATE(snd_strerror)(errVal); 938 _handleRecord = nullptr; 939 return -1; 940 } 941 942 _recordingFramesIn10MS = _recordingFreq / 100; 943 if ((errVal = 944 LATE(snd_pcm_set_params)(_handleRecord, 945 #if defined(WEBRTC_ARCH_BIG_ENDIAN) 946 SND_PCM_FORMAT_S16_BE, // format 947 #else 948 SND_PCM_FORMAT_S16_LE, // format 949 #endif 950 SND_PCM_ACCESS_RW_INTERLEAVED, // access 951 _recChannels, // channels 952 _recordingFreq, // rate 953 1, // soft_resample 954 ALSA_CAPTURE_LATENCY // latency in us 955 )) < 0) { 956 // Fall back to another mode then. 957 if (_recChannels == 1) 958 _recChannels = 2; 959 else 960 _recChannels = 1; 961 962 if ((errVal = 963 LATE(snd_pcm_set_params)(_handleRecord, 964 #if defined(WEBRTC_ARCH_BIG_ENDIAN) 965 SND_PCM_FORMAT_S16_BE, // format 966 #else 967 SND_PCM_FORMAT_S16_LE, // format 968 #endif 969 SND_PCM_ACCESS_RW_INTERLEAVED, // access 970 _recChannels, // channels 971 _recordingFreq, // rate 972 1, // soft_resample 973 ALSA_CAPTURE_LATENCY // latency in us 974 )) < 0) { 975 _recordingFramesIn10MS = 0; 976 RTC_LOG(LS_ERROR) << "unable to set record settings: " 977 << LATE(snd_strerror)(errVal) << " (" << errVal << ")"; 978 ErrorRecovery(errVal, _handleRecord); 979 errVal = LATE(snd_pcm_close)(_handleRecord); 980 _handleRecord = nullptr; 981 return -1; 982 } 983 } 984 985 errVal = LATE(snd_pcm_get_params)(_handleRecord, &_recordingBuffersizeInFrame, 986 &_recordingPeriodSizeInFrame); 987 if (errVal < 0) { 988 RTC_LOG(LS_ERROR) << "snd_pcm_get_params " << LATE(snd_strerror)(errVal) 989 << " (" << errVal << ")"; 990 _recordingBuffersizeInFrame = 0; 991 _recordingPeriodSizeInFrame = 0; 992 } else { 993 RTC_LOG(LS_VERBOSE) << "capture snd_pcm_get_params, buffer_size:" 994 << _recordingBuffersizeInFrame 995 << ", period_size:" << _recordingPeriodSizeInFrame; 996 } 997 998 if (_ptrAudioBuffer) { 999 // Update webrtc audio buffer with the selected parameters 1000 _ptrAudioBuffer->SetRecordingSampleRate(_recordingFreq); 1001 _ptrAudioBuffer->SetRecordingChannels(_recChannels); 1002 } 1003 1004 // Set rec buffer size and create buffer 1005 _recordingBufferSizeIn10MS = 1006 LATE(snd_pcm_frames_to_bytes)(_handleRecord, _recordingFramesIn10MS); 1007 1008 if (_handleRecord != nullptr) { 1009 // Mark recording side as initialized 1010 _recIsInitialized = true; 1011 return 0; 1012 } else { 1013 return -1; 1014 } 1015 } 1016 1017 int32_t AudioDeviceLinuxALSA::StartRecording() { 1018 if (!_recIsInitialized) { 1019 return -1; 1020 } 1021 1022 if (_recording) { 1023 return 0; 1024 } 1025 1026 _recording = true; 1027 1028 int errVal = 0; 1029 _recordingFramesLeft = _recordingFramesIn10MS; 1030 1031 // Make sure we only create the buffer once. 1032 if (!_recordingBuffer) 1033 _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS]; 1034 if (!_recordingBuffer) { 1035 RTC_LOG(LS_ERROR) << "failed to alloc recording buffer"; 1036 _recording = false; 1037 return -1; 1038 } 1039 // RECORDING 1040 _ptrThreadRec = PlatformThread::SpawnJoinable( 1041 [this] { 1042 while (RecThreadProcess()) { 1043 } 1044 }, 1045 "webrtc_audio_module_capture_thread", 1046 ThreadAttributes().SetPriority(ThreadPriority::kRealtime)); 1047 1048 errVal = LATE(snd_pcm_prepare)(_handleRecord); 1049 if (errVal < 0) { 1050 RTC_LOG(LS_ERROR) << "capture snd_pcm_prepare failed (" 1051 << LATE(snd_strerror)(errVal) << ")\n"; 1052 // just log error 1053 // if snd_pcm_open fails will return -1 1054 } 1055 1056 errVal = LATE(snd_pcm_start)(_handleRecord); 1057 if (errVal < 0) { 1058 RTC_LOG(LS_ERROR) << "capture snd_pcm_start err: " 1059 << LATE(snd_strerror)(errVal); 1060 errVal = LATE(snd_pcm_start)(_handleRecord); 1061 if (errVal < 0) { 1062 RTC_LOG(LS_ERROR) << "capture snd_pcm_start 2nd try err: " 1063 << LATE(snd_strerror)(errVal); 1064 StopRecording(); 1065 return -1; 1066 } 1067 } 1068 1069 return 0; 1070 } 1071 1072 int32_t AudioDeviceLinuxALSA::StopRecording() { 1073 MutexLock lock(&mutex_); 1074 return StopRecordingLocked(); 1075 } 1076 1077 int32_t AudioDeviceLinuxALSA::StopRecordingLocked() { 1078 if (!_recIsInitialized) { 1079 return 0; 1080 } 1081 1082 if (_handleRecord == nullptr) { 1083 return -1; 1084 } 1085 1086 // Make sure we don't start recording (it's asynchronous). 1087 _recIsInitialized = false; 1088 _recording = false; 1089 1090 _ptrThreadRec.Finalize(); 1091 1092 _recordingFramesLeft = 0; 1093 if (_recordingBuffer) { 1094 delete[] _recordingBuffer; 1095 _recordingBuffer = nullptr; 1096 } 1097 1098 // Stop and close pcm recording device. 1099 int errVal = LATE(snd_pcm_drop)(_handleRecord); 1100 if (errVal < 0) { 1101 RTC_LOG(LS_ERROR) << "Error stop recording: " << LATE(snd_strerror)(errVal); 1102 return -1; 1103 } 1104 1105 errVal = LATE(snd_pcm_close)(_handleRecord); 1106 if (errVal < 0) { 1107 RTC_LOG(LS_ERROR) << "Error closing record sound device, error: " 1108 << LATE(snd_strerror)(errVal); 1109 return -1; 1110 } 1111 1112 // Check if we have muted and unmute if so. 1113 bool muteEnabled = false; 1114 MicrophoneMute(muteEnabled); 1115 if (muteEnabled) { 1116 SetMicrophoneMute(false); 1117 } 1118 1119 // set the pcm input handle to NULL 1120 _handleRecord = nullptr; 1121 return 0; 1122 } 1123 1124 bool AudioDeviceLinuxALSA::RecordingIsInitialized() const { 1125 return (_recIsInitialized); 1126 } 1127 1128 bool AudioDeviceLinuxALSA::Recording() const { 1129 return (_recording); 1130 } 1131 1132 bool AudioDeviceLinuxALSA::PlayoutIsInitialized() const { 1133 return (_playIsInitialized); 1134 } 1135 1136 int32_t AudioDeviceLinuxALSA::StartPlayout() { 1137 if (!_playIsInitialized) { 1138 return -1; 1139 } 1140 1141 if (_playing) { 1142 return 0; 1143 } 1144 1145 _playing = true; 1146 1147 _playoutFramesLeft = 0; 1148 if (!_playoutBuffer) 1149 _playoutBuffer = new int8_t[_playoutBufferSizeIn10MS]; 1150 if (!_playoutBuffer) { 1151 RTC_LOG(LS_ERROR) << "failed to alloc playout buf"; 1152 _playing = false; 1153 return -1; 1154 } 1155 1156 // PLAYOUT 1157 _ptrThreadPlay = PlatformThread::SpawnJoinable( 1158 [this] { 1159 while (PlayThreadProcess()) { 1160 } 1161 }, 1162 "webrtc_audio_module_play_thread", 1163 ThreadAttributes().SetPriority(ThreadPriority::kRealtime)); 1164 1165 int errVal = LATE(snd_pcm_prepare)(_handlePlayout); 1166 if (errVal < 0) { 1167 RTC_LOG(LS_ERROR) << "playout snd_pcm_prepare failed (" 1168 << LATE(snd_strerror)(errVal) << ")\n"; 1169 // just log error 1170 // if snd_pcm_open fails will return -1 1171 } 1172 1173 return 0; 1174 } 1175 1176 int32_t AudioDeviceLinuxALSA::StopPlayout() { 1177 MutexLock lock(&mutex_); 1178 return StopPlayoutLocked(); 1179 } 1180 1181 int32_t AudioDeviceLinuxALSA::StopPlayoutLocked() { 1182 if (!_playIsInitialized) { 1183 return 0; 1184 } 1185 1186 if (_handlePlayout == nullptr) { 1187 return -1; 1188 } 1189 1190 _playing = false; 1191 1192 // stop playout thread first 1193 _ptrThreadPlay.Finalize(); 1194 1195 _playoutFramesLeft = 0; 1196 delete[] _playoutBuffer; 1197 _playoutBuffer = nullptr; 1198 1199 // stop and close pcm playout device 1200 int errVal = LATE(snd_pcm_drop)(_handlePlayout); 1201 if (errVal < 0) { 1202 RTC_LOG(LS_ERROR) << "Error stop playing: " << LATE(snd_strerror)(errVal); 1203 } 1204 1205 errVal = LATE(snd_pcm_close)(_handlePlayout); 1206 if (errVal < 0) 1207 RTC_LOG(LS_ERROR) << "Error closing playout sound device, error: " 1208 << LATE(snd_strerror)(errVal); 1209 1210 // set the pcm input handle to NULL 1211 _playIsInitialized = false; 1212 _handlePlayout = nullptr; 1213 RTC_LOG(LS_VERBOSE) << "handle_playout is now set to NULL"; 1214 1215 return 0; 1216 } 1217 1218 int32_t AudioDeviceLinuxALSA::PlayoutDelay(uint16_t& delayMS) const { 1219 delayMS = (uint16_t)_playoutDelay * 1000 / _playoutFreq; 1220 return 0; 1221 } 1222 1223 bool AudioDeviceLinuxALSA::Playing() const { 1224 return (_playing); 1225 } 1226 1227 // ============================================================================ 1228 // Private Methods 1229 // ============================================================================ 1230 1231 int32_t AudioDeviceLinuxALSA::GetDevicesInfo(const int32_t function, 1232 const bool playback, 1233 const int32_t enumDeviceNo, 1234 char* enumDeviceName, 1235 const int32_t ednLen) const { 1236 // Device enumeration based on libjingle implementation 1237 // by Tristan Schmelcher at Google Inc. 1238 1239 const char* type = playback ? "Output" : "Input"; 1240 // dmix and dsnoop are only for playback and capture, respectively, but ALSA 1241 // stupidly includes them in both lists. 1242 const char* ignorePrefix = playback ? "dsnoop:" : "dmix:"; 1243 // (ALSA lists many more "devices" of questionable interest, but we show them 1244 // just in case the weird devices may actually be desirable for some 1245 // users/systems.) 1246 1247 int err; 1248 int enumCount(0); 1249 bool keepSearching(true); 1250 1251 // From Chromium issue 95797 1252 // Loop through the sound cards to get Alsa device hints. 1253 // Don't use snd_device_name_hint(-1,..) since there is a access violation 1254 // inside this ALSA API with libasound.so.2.0.0. 1255 int card = -1; 1256 while (!(LATE(snd_card_next)(&card)) && (card >= 0) && keepSearching) { 1257 void** hints; 1258 err = LATE(snd_device_name_hint)(card, "pcm", &hints); 1259 if (err != 0) { 1260 RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name hint error: " 1261 << LATE(snd_strerror)(err); 1262 return -1; 1263 } 1264 1265 enumCount++; // default is 0 1266 if ((function == FUNC_GET_DEVICE_NAME || 1267 function == FUNC_GET_DEVICE_NAME_FOR_AN_ENUM) && 1268 enumDeviceNo == 0) { 1269 strcpy(enumDeviceName, "default"); 1270 1271 err = LATE(snd_device_name_free_hint)(hints); 1272 if (err != 0) { 1273 RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name free hint error: " 1274 << LATE(snd_strerror)(err); 1275 } 1276 1277 return 0; 1278 } 1279 1280 for (void** list = hints; *list != nullptr; ++list) { 1281 char* actualType = LATE(snd_device_name_get_hint)(*list, "IOID"); 1282 if (actualType) { // NULL means it's both. 1283 bool wrongType = (strcmp(actualType, type) != 0); 1284 free(actualType); 1285 if (wrongType) { 1286 // Wrong type of device (i.e., input vs. output). 1287 continue; 1288 } 1289 } 1290 1291 char* name = LATE(snd_device_name_get_hint)(*list, "NAME"); 1292 if (!name) { 1293 RTC_LOG(LS_ERROR) << "Device has no name"; 1294 // Skip it. 1295 continue; 1296 } 1297 1298 // Now check if we actually want to show this device. 1299 if (strcmp(name, "default") != 0 && strcmp(name, "null") != 0 && 1300 strcmp(name, "pulse") != 0 && 1301 strncmp(name, ignorePrefix, strlen(ignorePrefix)) != 0) { 1302 // Yes, we do. 1303 char* desc = LATE(snd_device_name_get_hint)(*list, "DESC"); 1304 if (!desc) { 1305 // Virtual devices don't necessarily have descriptions. 1306 // Use their names instead. 1307 desc = name; 1308 } 1309 1310 if (FUNC_GET_NUM_OF_DEVICE == function) { 1311 RTC_LOG(LS_VERBOSE) << "Enum device " << enumCount << " - " << name; 1312 } 1313 if ((FUNC_GET_DEVICE_NAME == function) && (enumDeviceNo == enumCount)) { 1314 // We have found the enum device, copy the name to buffer. 1315 strncpy(enumDeviceName, desc, ednLen); 1316 enumDeviceName[ednLen - 1] = '\0'; 1317 keepSearching = false; 1318 // Replace '\n' with '-'. 1319 char* pret = strchr(enumDeviceName, '\n' /*0xa*/); // LF 1320 if (pret) 1321 *pret = '-'; 1322 } 1323 if ((FUNC_GET_DEVICE_NAME_FOR_AN_ENUM == function) && 1324 (enumDeviceNo == enumCount)) { 1325 // We have found the enum device, copy the name to buffer. 1326 strncpy(enumDeviceName, name, ednLen); 1327 enumDeviceName[ednLen - 1] = '\0'; 1328 keepSearching = false; 1329 } 1330 1331 if (keepSearching) 1332 ++enumCount; 1333 1334 if (desc != name) 1335 free(desc); 1336 } 1337 1338 free(name); 1339 1340 if (!keepSearching) 1341 break; 1342 } 1343 1344 err = LATE(snd_device_name_free_hint)(hints); 1345 if (err != 0) { 1346 RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name free hint error: " 1347 << LATE(snd_strerror)(err); 1348 // Continue and return true anyway, since we did get the whole list. 1349 } 1350 } 1351 1352 if (FUNC_GET_NUM_OF_DEVICE == function) { 1353 if (enumCount == 1) // only default? 1354 enumCount = 0; 1355 return enumCount; // Normal return point for function 0 1356 } 1357 1358 if (keepSearching) { 1359 // If we get here for function 1 and 2, we didn't find the specified 1360 // enum device. 1361 RTC_LOG(LS_ERROR) 1362 << "GetDevicesInfo - Could not find device name or numbers"; 1363 return -1; 1364 } 1365 1366 return 0; 1367 } 1368 1369 int32_t AudioDeviceLinuxALSA::InputSanityCheckAfterUnlockedPeriod() const { 1370 if (_handleRecord == nullptr) { 1371 RTC_LOG(LS_ERROR) << "input state has been modified during unlocked period"; 1372 return -1; 1373 } 1374 return 0; 1375 } 1376 1377 int32_t AudioDeviceLinuxALSA::OutputSanityCheckAfterUnlockedPeriod() const { 1378 if (_handlePlayout == nullptr) { 1379 RTC_LOG(LS_ERROR) 1380 << "output state has been modified during unlocked period"; 1381 return -1; 1382 } 1383 return 0; 1384 } 1385 1386 int32_t AudioDeviceLinuxALSA::ErrorRecovery(int32_t error, 1387 snd_pcm_t* deviceHandle) { 1388 int st = LATE(snd_pcm_state)(deviceHandle); 1389 RTC_LOG(LS_VERBOSE) << "Trying to recover from " 1390 << ((LATE(snd_pcm_stream)(deviceHandle) == 1391 SND_PCM_STREAM_CAPTURE) 1392 ? "capture" 1393 : "playout") 1394 << " error: " << LATE(snd_strerror)(error) << " (" 1395 << error << ") (state " << st << ")"; 1396 1397 // It is recommended to use snd_pcm_recover for all errors. If that function 1398 // cannot handle the error, the input error code will be returned, otherwise 1399 // 0 is returned. From snd_pcm_recover API doc: "This functions handles 1400 // -EINTR (4) (interrupted system call), -EPIPE (32) (playout overrun or 1401 // capture underrun) and -ESTRPIPE (86) (stream is suspended) error codes 1402 // trying to prepare given stream for next I/O." 1403 1404 /** Open */ 1405 // SND_PCM_STATE_OPEN = 0, 1406 /** Setup installed */ 1407 // SND_PCM_STATE_SETUP, 1408 /** Ready to start */ 1409 // SND_PCM_STATE_PREPARED, 1410 /** Running */ 1411 // SND_PCM_STATE_RUNNING, 1412 /** Stopped: underrun (playback) or overrun (capture) detected */ 1413 // SND_PCM_STATE_XRUN,= 4 1414 /** Draining: running (playback) or stopped (capture) */ 1415 // SND_PCM_STATE_DRAINING, 1416 /** Paused */ 1417 // SND_PCM_STATE_PAUSED, 1418 /** Hardware is suspended */ 1419 // SND_PCM_STATE_SUSPENDED, 1420 // ** Hardware is disconnected */ 1421 // SND_PCM_STATE_DISCONNECTED, 1422 // SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED 1423 1424 // snd_pcm_recover isn't available in older alsa, e.g. on the FC4 machine 1425 // in Sthlm lab. 1426 1427 int res = LATE(snd_pcm_recover)(deviceHandle, error, 1); 1428 if (0 == res) { 1429 RTC_LOG(LS_VERBOSE) << "Recovery - snd_pcm_recover OK"; 1430 1431 if ((error == -EPIPE || error == -ESTRPIPE) && // Buf underrun/overrun. 1432 _recording && 1433 LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE) { 1434 // For capture streams we also have to repeat the explicit start() 1435 // to get data flowing again. 1436 int err = LATE(snd_pcm_start)(deviceHandle); 1437 if (err != 0) { 1438 RTC_LOG(LS_ERROR) << "Recovery - snd_pcm_start error: " << err; 1439 return -1; 1440 } 1441 } 1442 1443 if ((error == -EPIPE || error == -ESTRPIPE) && // Buf underrun/overrun. 1444 _playing && 1445 LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_PLAYBACK) { 1446 // For capture streams we also have to repeat the explicit start() to get 1447 // data flowing again. 1448 int err = LATE(snd_pcm_start)(deviceHandle); 1449 if (err != 0) { 1450 RTC_LOG(LS_ERROR) << "Recovery - snd_pcm_start error: " 1451 << LATE(snd_strerror)(err); 1452 return -1; 1453 } 1454 } 1455 1456 return -EPIPE == error ? 1 : 0; 1457 } else { 1458 RTC_LOG(LS_ERROR) << "Unrecoverable alsa stream error: " << res; 1459 } 1460 1461 return res; 1462 } 1463 1464 // ============================================================================ 1465 // Thread Methods 1466 // ============================================================================ 1467 1468 bool AudioDeviceLinuxALSA::PlayThreadProcess() { 1469 if (!_playing) 1470 return false; 1471 1472 int err; 1473 snd_pcm_sframes_t frames; 1474 snd_pcm_sframes_t avail_frames; 1475 1476 Lock(); 1477 // return a positive number of frames ready otherwise a negative error code 1478 avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout); 1479 if (avail_frames < 0) { 1480 RTC_LOG(LS_ERROR) << "playout snd_pcm_avail_update error: " 1481 << LATE(snd_strerror)(avail_frames); 1482 ErrorRecovery(avail_frames, _handlePlayout); 1483 UnLock(); 1484 return true; 1485 } else if (avail_frames == 0) { 1486 UnLock(); 1487 1488 // maximum tixe in milliseconds to wait, a negative value means infinity 1489 err = LATE(snd_pcm_wait)(_handlePlayout, 2); 1490 if (err == 0) { // timeout occured 1491 RTC_LOG(LS_VERBOSE) << "playout snd_pcm_wait timeout"; 1492 } 1493 1494 return true; 1495 } 1496 1497 if (_playoutFramesLeft <= 0) { 1498 UnLock(); 1499 _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS); 1500 Lock(); 1501 1502 _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer); 1503 RTC_DCHECK_EQ(_playoutFramesLeft, _playoutFramesIn10MS); 1504 } 1505 1506 if (static_cast<uint32_t>(avail_frames) > _playoutFramesLeft) 1507 avail_frames = _playoutFramesLeft; 1508 1509 int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout, _playoutFramesLeft); 1510 frames = LATE(snd_pcm_writei)( 1511 _handlePlayout, &_playoutBuffer[_playoutBufferSizeIn10MS - size], 1512 avail_frames); 1513 1514 if (frames < 0) { 1515 RTC_LOG(LS_VERBOSE) << "playout snd_pcm_writei error: " 1516 << LATE(snd_strerror)(frames); 1517 _playoutFramesLeft = 0; 1518 ErrorRecovery(frames, _handlePlayout); 1519 UnLock(); 1520 return true; 1521 } else { 1522 RTC_DCHECK_EQ(frames, avail_frames); 1523 _playoutFramesLeft -= frames; 1524 } 1525 1526 UnLock(); 1527 return true; 1528 } 1529 1530 bool AudioDeviceLinuxALSA::RecThreadProcess() { 1531 if (!_recording) 1532 return false; 1533 1534 int err; 1535 snd_pcm_sframes_t frames; 1536 snd_pcm_sframes_t avail_frames; 1537 std::vector<int8_t> buffer(_recordingBufferSizeIn10MS); 1538 1539 Lock(); 1540 1541 // return a positive number of frames ready otherwise a negative error code 1542 avail_frames = LATE(snd_pcm_avail_update)(_handleRecord); 1543 if (avail_frames < 0) { 1544 RTC_LOG(LS_ERROR) << "capture snd_pcm_avail_update error: " 1545 << LATE(snd_strerror)(avail_frames); 1546 ErrorRecovery(avail_frames, _handleRecord); 1547 UnLock(); 1548 return true; 1549 } else if (avail_frames == 0) { // no frame is available now 1550 UnLock(); 1551 1552 // maximum time in milliseconds to wait, a negative value means infinity 1553 err = LATE(snd_pcm_wait)(_handleRecord, ALSA_CAPTURE_WAIT_TIMEOUT); 1554 if (err == 0) // timeout occured 1555 RTC_LOG(LS_VERBOSE) << "capture snd_pcm_wait timeout"; 1556 1557 return true; 1558 } 1559 1560 if (static_cast<uint32_t>(avail_frames) > _recordingFramesLeft) 1561 avail_frames = _recordingFramesLeft; 1562 1563 frames = LATE(snd_pcm_readi)(_handleRecord, buffer.data(), 1564 avail_frames); // frames to be written 1565 if (frames < 0) { 1566 RTC_LOG(LS_ERROR) << "capture snd_pcm_readi error: " 1567 << LATE(snd_strerror)(frames); 1568 ErrorRecovery(frames, _handleRecord); 1569 UnLock(); 1570 return true; 1571 } else if (frames > 0) { 1572 RTC_DCHECK_EQ(frames, avail_frames); 1573 1574 int left_size = 1575 LATE(snd_pcm_frames_to_bytes)(_handleRecord, _recordingFramesLeft); 1576 int size = LATE(snd_pcm_frames_to_bytes)(_handleRecord, frames); 1577 1578 memcpy(&_recordingBuffer[_recordingBufferSizeIn10MS - left_size], 1579 buffer.data(), size); 1580 _recordingFramesLeft -= frames; 1581 1582 if (!_recordingFramesLeft) { // buf is full 1583 _recordingFramesLeft = _recordingFramesIn10MS; 1584 1585 // store the recorded buffer (no action will be taken if the 1586 // #recorded samples is not a full buffer) 1587 _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer, 1588 _recordingFramesIn10MS); 1589 1590 // calculate delay 1591 _playoutDelay = 0; 1592 _recordingDelay = 0; 1593 if (_handlePlayout) { 1594 err = LATE(snd_pcm_delay)(_handlePlayout, 1595 &_playoutDelay); // returned delay in frames 1596 if (err < 0) { 1597 // TODO(xians): Shall we call ErrorRecovery() here? 1598 _playoutDelay = 0; 1599 RTC_LOG(LS_ERROR) 1600 << "playout snd_pcm_delay: " << LATE(snd_strerror)(err); 1601 } 1602 } 1603 1604 err = LATE(snd_pcm_delay)(_handleRecord, 1605 &_recordingDelay); // returned delay in frames 1606 if (err < 0) { 1607 // TODO(xians): Shall we call ErrorRecovery() here? 1608 _recordingDelay = 0; 1609 RTC_LOG(LS_ERROR) << "capture snd_pcm_delay: " 1610 << LATE(snd_strerror)(err); 1611 } 1612 1613 // TODO(xians): Shall we add 10ms buffer delay to the record delay? 1614 _ptrAudioBuffer->SetVQEData(_playoutDelay * 1000 / _playoutFreq, 1615 _recordingDelay * 1000 / _recordingFreq); 1616 1617 _ptrAudioBuffer->SetTypingStatus(KeyPressed()); 1618 1619 // Deliver recorded samples at specified sample rate, mic level etc. 1620 // to the observer using callback. 1621 UnLock(); 1622 _ptrAudioBuffer->DeliverRecordedData(); 1623 Lock(); 1624 } 1625 } 1626 1627 UnLock(); 1628 return true; 1629 } 1630 1631 bool AudioDeviceLinuxALSA::KeyPressed() const { 1632 #if defined(WEBRTC_USE_X11) 1633 char szKey[32]; 1634 unsigned int i = 0; 1635 char state = 0; 1636 1637 if (!_XDisplay) 1638 return false; 1639 1640 // Check key map status 1641 XQueryKeymap(_XDisplay, szKey); 1642 1643 // A bit change in keymap means a key is pressed 1644 for (i = 0; i < sizeof(szKey); i++) 1645 state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i]; 1646 1647 // Save old state 1648 memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState)); 1649 return (state != 0); 1650 #else 1651 return false; 1652 #endif 1653 } 1654 } // namespace webrtc