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 <assert.h> 12 13 #include "webrtc/modules/audio_device/linux/audio_mixer_manager_alsa_linux.h" 14 #include "webrtc/system_wrappers/include/trace.h" 15 16 extern webrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable; 17 18 // Accesses ALSA functions through our late-binding symbol table instead of 19 // directly. This way we don't have to link to libalsa, which means our binary 20 // will work on systems that don't have it. 21 #define LATE(sym) \ 22 LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym) 23 24 namespace webrtc 25 { 26 27 AudioMixerManagerLinuxALSA::AudioMixerManagerLinuxALSA(const int32_t id) : 28 _critSect(*CriticalSectionWrapper::CreateCriticalSection()), 29 _id(id), 30 _outputMixerHandle(NULL), 31 _inputMixerHandle(NULL), 32 _outputMixerElement(NULL), 33 _inputMixerElement(NULL) 34 { 35 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, 36 "%s constructed", __FUNCTION__); 37 38 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize); 39 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize); 40 } 41 42 AudioMixerManagerLinuxALSA::~AudioMixerManagerLinuxALSA() 43 { 44 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, 45 "%s destructed", __FUNCTION__); 46 47 Close(); 48 49 delete &_critSect; 50 } 51 52 // ============================================================================ 53 // PUBLIC METHODS 54 // ============================================================================ 55 56 int32_t AudioMixerManagerLinuxALSA::Close() 57 { 58 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", 59 __FUNCTION__); 60 61 CriticalSectionScoped lock(&_critSect); 62 63 CloseSpeaker(); 64 CloseMicrophone(); 65 66 return 0; 67 68 } 69 70 int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() 71 { 72 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", 73 __FUNCTION__); 74 75 CriticalSectionScoped lock(&_critSect); 76 77 int errVal = 0; 78 79 if (_outputMixerHandle != NULL) 80 { 81 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 82 "Closing playout mixer"); 83 LATE(snd_mixer_free)(_outputMixerHandle); 84 if (errVal < 0) 85 { 86 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 87 " Error freeing playout mixer: %s", 88 LATE(snd_strerror)(errVal)); 89 } 90 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr); 91 if (errVal < 0) 92 { 93 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 94 " Error detachinging playout mixer: %s", 95 LATE(snd_strerror)(errVal)); 96 } 97 errVal = LATE(snd_mixer_close)(_outputMixerHandle); 98 if (errVal < 0) 99 { 100 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 101 " Error snd_mixer_close(handleMixer) errVal=%d", 102 errVal); 103 } 104 _outputMixerHandle = NULL; 105 _outputMixerElement = NULL; 106 } 107 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize); 108 109 return 0; 110 } 111 112 int32_t AudioMixerManagerLinuxALSA::CloseMicrophone() 113 { 114 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 115 116 CriticalSectionScoped lock(&_critSect); 117 118 int errVal = 0; 119 120 if (_inputMixerHandle != NULL) 121 { 122 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 123 "Closing record mixer"); 124 125 LATE(snd_mixer_free)(_inputMixerHandle); 126 if (errVal < 0) 127 { 128 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 129 " Error freeing record mixer: %s", 130 LATE(snd_strerror)(errVal)); 131 } 132 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 133 "Closing record mixer 2"); 134 135 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr); 136 if (errVal < 0) 137 { 138 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 139 " Error detachinging record mixer: %s", 140 LATE(snd_strerror)(errVal)); 141 } 142 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 143 "Closing record mixer 3"); 144 145 errVal = LATE(snd_mixer_close)(_inputMixerHandle); 146 if (errVal < 0) 147 { 148 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 149 " Error snd_mixer_close(handleMixer) errVal=%d", 150 errVal); 151 } 152 153 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 154 "Closing record mixer 4"); 155 _inputMixerHandle = NULL; 156 _inputMixerElement = NULL; 157 } 158 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize); 159 160 return 0; 161 } 162 163 int32_t AudioMixerManagerLinuxALSA::OpenSpeaker(char* deviceName) 164 { 165 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 166 "AudioMixerManagerLinuxALSA::OpenSpeaker(name=%s)", deviceName); 167 168 CriticalSectionScoped lock(&_critSect); 169 170 int errVal = 0; 171 172 // Close any existing output mixer handle 173 // 174 if (_outputMixerHandle != NULL) 175 { 176 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 177 "Closing playout mixer"); 178 179 LATE(snd_mixer_free)(_outputMixerHandle); 180 if (errVal < 0) 181 { 182 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 183 " Error freeing playout mixer: %s", 184 LATE(snd_strerror)(errVal)); 185 } 186 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr); 187 if (errVal < 0) 188 { 189 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 190 " Error detachinging playout mixer: %s", 191 LATE(snd_strerror)(errVal)); 192 } 193 errVal = LATE(snd_mixer_close)(_outputMixerHandle); 194 if (errVal < 0) 195 { 196 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 197 " Error snd_mixer_close(handleMixer) errVal=%d", 198 errVal); 199 } 200 } 201 _outputMixerHandle = NULL; 202 _outputMixerElement = NULL; 203 204 errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0); 205 if (errVal < 0) 206 { 207 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 208 "snd_mixer_open(&_outputMixerHandle, 0) - error"); 209 return -1; 210 } 211 212 char controlName[kAdmMaxDeviceNameSize] = { 0 }; 213 GetControlName(controlName, deviceName); 214 215 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 216 " snd_mixer_attach(_outputMixerHandle, %s)", controlName); 217 218 errVal = LATE(snd_mixer_attach)(_outputMixerHandle, controlName); 219 if (errVal < 0) 220 { 221 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 222 " snd_mixer_attach(_outputMixerHandle, %s) error: %s", 223 controlName, LATE(snd_strerror)(errVal)); 224 _outputMixerHandle = NULL; 225 return -1; 226 } 227 strcpy(_outputMixerStr, controlName); 228 229 errVal = LATE(snd_mixer_selem_register)(_outputMixerHandle, NULL, NULL); 230 if (errVal < 0) 231 { 232 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 233 " snd_mixer_selem_register(_outputMixerHandle," 234 " NULL, NULL), error: %s", 235 LATE(snd_strerror)(errVal)); 236 _outputMixerHandle = NULL; 237 return -1; 238 } 239 240 // Load and find the proper mixer element 241 if (LoadSpeakerMixerElement() < 0) 242 { 243 return -1; 244 } 245 246 if (_outputMixerHandle != NULL) 247 { 248 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 249 " the output mixer device is now open (0x%x)", 250 _outputMixerHandle); 251 } 252 253 return 0; 254 } 255 256 int32_t AudioMixerManagerLinuxALSA::OpenMicrophone(char *deviceName) 257 { 258 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 259 "AudioMixerManagerLinuxALSA::OpenMicrophone(name=%s)", 260 deviceName); 261 262 CriticalSectionScoped lock(&_critSect); 263 264 int errVal = 0; 265 266 // Close any existing input mixer handle 267 // 268 if (_inputMixerHandle != NULL) 269 { 270 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 271 "Closing record mixer"); 272 273 LATE(snd_mixer_free)(_inputMixerHandle); 274 if (errVal < 0) 275 { 276 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 277 " Error freeing record mixer: %s", 278 LATE(snd_strerror)(errVal)); 279 } 280 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 281 "Closing record mixer"); 282 283 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr); 284 if (errVal < 0) 285 { 286 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 287 " Error detachinging record mixer: %s", 288 LATE(snd_strerror)(errVal)); 289 } 290 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 291 "Closing record mixer"); 292 293 errVal = LATE(snd_mixer_close)(_inputMixerHandle); 294 if (errVal < 0) 295 { 296 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 297 " Error snd_mixer_close(handleMixer) errVal=%d", 298 errVal); 299 } 300 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 301 "Closing record mixer"); 302 } 303 _inputMixerHandle = NULL; 304 _inputMixerElement = NULL; 305 306 errVal = LATE(snd_mixer_open)(&_inputMixerHandle, 0); 307 if (errVal < 0) 308 { 309 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 310 " snd_mixer_open(&_inputMixerHandle, 0) - error"); 311 return -1; 312 } 313 314 char controlName[kAdmMaxDeviceNameSize] = { 0 }; 315 GetControlName(controlName, deviceName); 316 317 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 318 " snd_mixer_attach(_inputMixerHandle, %s)", controlName); 319 320 errVal = LATE(snd_mixer_attach)(_inputMixerHandle, controlName); 321 if (errVal < 0) 322 { 323 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 324 " snd_mixer_attach(_inputMixerHandle, %s) error: %s", 325 controlName, LATE(snd_strerror)(errVal)); 326 327 _inputMixerHandle = NULL; 328 return -1; 329 } 330 strcpy(_inputMixerStr, controlName); 331 332 errVal = LATE(snd_mixer_selem_register)(_inputMixerHandle, NULL, NULL); 333 if (errVal < 0) 334 { 335 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 336 " snd_mixer_selem_register(_inputMixerHandle," 337 " NULL, NULL), error: %s", 338 LATE(snd_strerror)(errVal)); 339 340 _inputMixerHandle = NULL; 341 return -1; 342 } 343 // Load and find the proper mixer element 344 if (LoadMicMixerElement() < 0) 345 { 346 return -1; 347 } 348 349 if (_inputMixerHandle != NULL) 350 { 351 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 352 " the input mixer device is now open (0x%x)", 353 _inputMixerHandle); 354 } 355 356 return 0; 357 } 358 359 bool AudioMixerManagerLinuxALSA::SpeakerIsInitialized() const 360 { 361 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); 362 363 return (_outputMixerHandle != NULL); 364 } 365 366 bool AudioMixerManagerLinuxALSA::MicrophoneIsInitialized() const 367 { 368 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", 369 __FUNCTION__); 370 371 return (_inputMixerHandle != NULL); 372 } 373 374 int32_t AudioMixerManagerLinuxALSA::SetSpeakerVolume( 375 uint32_t volume) 376 { 377 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 378 "AudioMixerManagerLinuxALSA::SetSpeakerVolume(volume=%u)", 379 volume); 380 381 CriticalSectionScoped lock(&_critSect); 382 383 if (_outputMixerElement == NULL) 384 { 385 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 386 " no avaliable output mixer element exists"); 387 return -1; 388 } 389 390 int errVal = 391 LATE(snd_mixer_selem_set_playback_volume_all)(_outputMixerElement, 392 volume); 393 if (errVal < 0) 394 { 395 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 396 " Error changing master volume: %s", 397 LATE(snd_strerror)(errVal)); 398 return -1; 399 } 400 401 return (0); 402 } 403 404 int32_t AudioMixerManagerLinuxALSA::SpeakerVolume( 405 uint32_t& volume) const 406 { 407 408 if (_outputMixerElement == NULL) 409 { 410 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 411 " no avaliable output mixer element exists"); 412 return -1; 413 } 414 415 long int vol(0); 416 417 int 418 errVal = LATE(snd_mixer_selem_get_playback_volume)( 419 _outputMixerElement, 420 (snd_mixer_selem_channel_id_t) 0, 421 &vol); 422 if (errVal < 0) 423 { 424 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 425 "Error getting outputvolume: %s", 426 LATE(snd_strerror)(errVal)); 427 return -1; 428 } 429 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 430 " AudioMixerManagerLinuxALSA::SpeakerVolume() => vol=%i", 431 vol); 432 433 volume = static_cast<uint32_t> (vol); 434 435 return 0; 436 } 437 438 int32_t AudioMixerManagerLinuxALSA::MaxSpeakerVolume( 439 uint32_t& maxVolume) const 440 { 441 442 if (_outputMixerElement == NULL) 443 { 444 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 445 " no avilable output mixer element exists"); 446 return -1; 447 } 448 449 long int minVol(0); 450 long int maxVol(0); 451 452 int errVal = 453 LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement, 454 &minVol, &maxVol); 455 456 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 457 " Playout hardware volume range, min: %d, max: %d", 458 minVol, maxVol); 459 460 if (maxVol <= minVol) 461 { 462 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 463 " Error getting get_playback_volume_range: %s", 464 LATE(snd_strerror)(errVal)); 465 } 466 467 maxVolume = static_cast<uint32_t> (maxVol); 468 469 return 0; 470 } 471 472 int32_t AudioMixerManagerLinuxALSA::MinSpeakerVolume( 473 uint32_t& minVolume) const 474 { 475 476 if (_outputMixerElement == NULL) 477 { 478 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 479 " no avaliable output mixer element exists"); 480 return -1; 481 } 482 483 long int minVol(0); 484 long int maxVol(0); 485 486 int errVal = 487 LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement, 488 &minVol, &maxVol); 489 490 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 491 " Playout hardware volume range, min: %d, max: %d", 492 minVol, maxVol); 493 494 if (maxVol <= minVol) 495 { 496 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 497 " Error getting get_playback_volume_range: %s", 498 LATE(snd_strerror)(errVal)); 499 } 500 501 minVolume = static_cast<uint32_t> (minVol); 502 503 return 0; 504 } 505 506 // TL: Have done testnig with these but they don't seem reliable and 507 // they were therefore not added 508 /* 509 // ---------------------------------------------------------------------------- 510 // SetMaxSpeakerVolume 511 // ---------------------------------------------------------------------------- 512 513 int32_t AudioMixerManagerLinuxALSA::SetMaxSpeakerVolume( 514 uint32_t maxVolume) 515 { 516 517 if (_outputMixerElement == NULL) 518 { 519 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 520 " no avaliable output mixer element exists"); 521 return -1; 522 } 523 524 long int minVol(0); 525 long int maxVol(0); 526 527 int errVal = snd_mixer_selem_get_playback_volume_range( 528 _outputMixerElement, &minVol, &maxVol); 529 if ((maxVol <= minVol) || (errVal != 0)) 530 { 531 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 532 " Error getting playback volume range: %s", snd_strerror(errVal)); 533 } 534 535 maxVol = maxVolume; 536 errVal = snd_mixer_selem_set_playback_volume_range( 537 _outputMixerElement, minVol, maxVol); 538 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 539 " Playout hardware volume range, min: %d, max: %d", minVol, maxVol); 540 if (errVal != 0) 541 { 542 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 543 " Error setting playback volume range: %s", snd_strerror(errVal)); 544 return -1; 545 } 546 547 return 0; 548 } 549 550 // ---------------------------------------------------------------------------- 551 // SetMinSpeakerVolume 552 // ---------------------------------------------------------------------------- 553 554 int32_t AudioMixerManagerLinuxALSA::SetMinSpeakerVolume( 555 uint32_t minVolume) 556 { 557 558 if (_outputMixerElement == NULL) 559 { 560 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 561 " no avaliable output mixer element exists"); 562 return -1; 563 } 564 565 long int minVol(0); 566 long int maxVol(0); 567 568 int errVal = snd_mixer_selem_get_playback_volume_range( 569 _outputMixerElement, &minVol, &maxVol); 570 if ((maxVol <= minVol) || (errVal != 0)) 571 { 572 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 573 " Error getting playback volume range: %s", snd_strerror(errVal)); 574 } 575 576 minVol = minVolume; 577 errVal = snd_mixer_selem_set_playback_volume_range( 578 _outputMixerElement, minVol, maxVol); 579 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 580 " Playout hardware volume range, min: %d, max: %d", minVol, maxVol); 581 if (errVal != 0) 582 { 583 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 584 " Error setting playback volume range: %s", snd_strerror(errVal)); 585 return -1; 586 } 587 588 return 0; 589 } 590 */ 591 592 int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeStepSize( 593 uint16_t& stepSize) const 594 { 595 596 if (_outputMixerHandle == NULL) 597 { 598 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 599 " no avaliable output mixer exists"); 600 return -1; 601 } 602 603 // The step size is always 1 for ALSA 604 stepSize = 1; 605 606 return 0; 607 } 608 609 int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeIsAvailable( 610 bool& available) 611 { 612 if (_outputMixerElement == NULL) 613 { 614 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 615 " no avaliable output mixer element exists"); 616 return -1; 617 } 618 619 available = LATE(snd_mixer_selem_has_playback_volume)(_outputMixerElement); 620 621 return 0; 622 } 623 624 int32_t AudioMixerManagerLinuxALSA::SpeakerMuteIsAvailable( 625 bool& available) 626 { 627 if (_outputMixerElement == NULL) 628 { 629 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 630 " no avaliable output mixer element exists"); 631 return -1; 632 } 633 634 available = LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement); 635 636 return 0; 637 } 638 639 int32_t AudioMixerManagerLinuxALSA::SetSpeakerMute(bool enable) 640 { 641 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 642 "AudioMixerManagerLinuxALSA::SetSpeakerMute(enable=%u)", 643 enable); 644 645 CriticalSectionScoped lock(&_critSect); 646 647 if (_outputMixerElement == NULL) 648 { 649 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 650 " no avaliable output mixer element exists"); 651 return -1; 652 } 653 654 // Ensure that the selected speaker destination has a valid mute control. 655 bool available(false); 656 SpeakerMuteIsAvailable(available); 657 if (!available) 658 { 659 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 660 " it is not possible to mute the speaker"); 661 return -1; 662 } 663 664 // Note value = 0 (off) means muted 665 int errVal = 666 LATE(snd_mixer_selem_set_playback_switch_all)(_outputMixerElement, 667 !enable); 668 if (errVal < 0) 669 { 670 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 671 " Error setting playback switch: %s", 672 LATE(snd_strerror)(errVal)); 673 return -1; 674 } 675 676 return (0); 677 } 678 679 int32_t AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const 680 { 681 682 if (_outputMixerElement == NULL) 683 { 684 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 685 " no avaliable output mixer exists"); 686 return -1; 687 } 688 689 // Ensure that the selected speaker destination has a valid mute control. 690 bool available = 691 LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement); 692 if (!available) 693 { 694 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 695 " it is not possible to mute the speaker"); 696 return -1; 697 } 698 699 int value(false); 700 701 // Retrieve one boolean control value for a specified mute-control 702 // 703 int 704 errVal = LATE(snd_mixer_selem_get_playback_switch)( 705 _outputMixerElement, 706 (snd_mixer_selem_channel_id_t) 0, 707 &value); 708 if (errVal < 0) 709 { 710 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 711 " Error getting playback switch: %s", 712 LATE(snd_strerror)(errVal)); 713 return -1; 714 } 715 716 // Note value = 0 (off) means muted 717 enabled = (bool) !value; 718 719 return 0; 720 } 721 722 int32_t AudioMixerManagerLinuxALSA::MicrophoneMuteIsAvailable( 723 bool& available) 724 { 725 if (_inputMixerElement == NULL) 726 { 727 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 728 " no avaliable input mixer element exists"); 729 return -1; 730 } 731 732 available = LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement); 733 return 0; 734 } 735 736 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneMute(bool enable) 737 { 738 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 739 "AudioMixerManagerLinuxALSA::SetMicrophoneMute(enable=%u)", 740 enable); 741 742 CriticalSectionScoped lock(&_critSect); 743 744 if (_inputMixerElement == NULL) 745 { 746 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 747 " no avaliable input mixer element exists"); 748 return -1; 749 } 750 751 // Ensure that the selected microphone destination has a valid mute control. 752 bool available(false); 753 MicrophoneMuteIsAvailable(available); 754 if (!available) 755 { 756 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 757 " it is not possible to mute the microphone"); 758 return -1; 759 } 760 761 // Note value = 0 (off) means muted 762 int errVal = 763 LATE(snd_mixer_selem_set_capture_switch_all)(_inputMixerElement, 764 !enable); 765 if (errVal < 0) 766 { 767 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 768 " Error setting capture switch: %s", 769 LATE(snd_strerror)(errVal)); 770 return -1; 771 } 772 773 return (0); 774 } 775 776 int32_t AudioMixerManagerLinuxALSA::MicrophoneMute(bool& enabled) const 777 { 778 779 if (_inputMixerElement == NULL) 780 { 781 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 782 " no avaliable input mixer exists"); 783 return -1; 784 } 785 786 // Ensure that the selected microphone destination has a valid mute control. 787 bool available = 788 LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement); 789 if (!available) 790 { 791 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 792 " it is not possible to mute the microphone"); 793 return -1; 794 } 795 796 int value(false); 797 798 // Retrieve one boolean control value for a specified mute-control 799 // 800 int 801 errVal = LATE(snd_mixer_selem_get_capture_switch)( 802 _inputMixerElement, 803 (snd_mixer_selem_channel_id_t) 0, 804 &value); 805 if (errVal < 0) 806 { 807 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 808 " Error getting capture switch: %s", 809 LATE(snd_strerror)(errVal)); 810 return -1; 811 } 812 813 // Note value = 0 (off) means muted 814 enabled = (bool) !value; 815 816 return 0; 817 } 818 819 int32_t AudioMixerManagerLinuxALSA::MicrophoneBoostIsAvailable( 820 bool& available) 821 { 822 if (_inputMixerHandle == NULL) 823 { 824 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 825 " no avaliable input mixer exists"); 826 return -1; 827 } 828 829 // Microphone boost cannot be enabled through ALSA Simple Mixer Interface 830 available = false; 831 832 return 0; 833 } 834 835 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneBoost(bool enable) 836 { 837 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 838 "AudioMixerManagerLinuxALSA::SetMicrophoneBoost(enable=%u)", 839 enable); 840 841 CriticalSectionScoped lock(&_critSect); 842 843 if (_inputMixerHandle == NULL) 844 { 845 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 846 " no avaliable input mixer exists"); 847 return -1; 848 } 849 850 // Ensure that the selected microphone destination has a valid mute control. 851 bool available(false); 852 MicrophoneMuteIsAvailable(available); 853 if (!available) 854 { 855 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 856 " it is not possible to enable microphone boost"); 857 return -1; 858 } 859 860 // It is assumed that the call above fails! 861 862 return (0); 863 } 864 865 int32_t AudioMixerManagerLinuxALSA::MicrophoneBoost(bool& enabled) const 866 { 867 868 if (_inputMixerHandle == NULL) 869 { 870 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 871 " no avaliable input mixer exists"); 872 return -1; 873 } 874 875 // Microphone boost cannot be enabled on this platform! 876 enabled = false; 877 878 return 0; 879 } 880 881 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeIsAvailable( 882 bool& available) 883 { 884 if (_inputMixerElement == NULL) 885 { 886 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 887 " no avaliable input mixer element exists"); 888 return -1; 889 } 890 891 available = LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement); 892 893 return 0; 894 } 895 896 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneVolume( 897 uint32_t volume) 898 { 899 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 900 "AudioMixerManagerLinuxALSA::SetMicrophoneVolume(volume=%u)", 901 volume); 902 903 CriticalSectionScoped lock(&_critSect); 904 905 if (_inputMixerElement == NULL) 906 { 907 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 908 " no avaliable input mixer element exists"); 909 return -1; 910 } 911 912 int 913 errVal = 914 LATE(snd_mixer_selem_set_capture_volume_all)(_inputMixerElement, 915 volume); 916 if (errVal < 0) 917 { 918 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 919 " Error changing microphone volume: %s", 920 LATE(snd_strerror)(errVal)); 921 return -1; 922 } 923 924 return (0); 925 } 926 927 // TL: Have done testnig with these but they don't seem reliable and 928 // they were therefore not added 929 /* 930 // ---------------------------------------------------------------------------- 931 // SetMaxMicrophoneVolume 932 // ---------------------------------------------------------------------------- 933 934 int32_t AudioMixerManagerLinuxALSA::SetMaxMicrophoneVolume( 935 uint32_t maxVolume) 936 { 937 938 if (_inputMixerElement == NULL) 939 { 940 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 941 " no avaliable output mixer element exists"); 942 return -1; 943 } 944 945 long int minVol(0); 946 long int maxVol(0); 947 948 int errVal = snd_mixer_selem_get_capture_volume_range(_inputMixerElement, 949 &minVol, &maxVol); 950 if ((maxVol <= minVol) || (errVal != 0)) 951 { 952 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 953 " Error getting capture volume range: %s", snd_strerror(errVal)); 954 } 955 956 maxVol = (long int)maxVolume; 957 printf("min %d max %d", minVol, maxVol); 958 errVal = snd_mixer_selem_set_capture_volume_range(_inputMixerElement, minVol, maxVol); 959 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 960 " Capture hardware volume range, min: %d, max: %d", minVol, maxVol); 961 if (errVal != 0) 962 { 963 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 964 " Error setting capture volume range: %s", snd_strerror(errVal)); 965 return -1; 966 } 967 968 return 0; 969 } 970 971 // ---------------------------------------------------------------------------- 972 // SetMinMicrophoneVolume 973 // ---------------------------------------------------------------------------- 974 975 int32_t AudioMixerManagerLinuxALSA::SetMinMicrophoneVolume( 976 uint32_t minVolume) 977 { 978 979 if (_inputMixerElement == NULL) 980 { 981 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 982 " no avaliable output mixer element exists"); 983 return -1; 984 } 985 986 long int minVol(0); 987 long int maxVol(0); 988 989 int errVal = snd_mixer_selem_get_capture_volume_range( 990 _inputMixerElement, &minVol, &maxVol); 991 if (maxVol <= minVol) 992 { 993 //maxVol = 255; 994 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 995 " Error getting capture volume range: %s", snd_strerror(errVal)); 996 } 997 998 printf("min %d max %d", minVol, maxVol); 999 minVol = (long int)minVolume; 1000 errVal = snd_mixer_selem_set_capture_volume_range( 1001 _inputMixerElement, minVol, maxVol); 1002 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1003 " Capture hardware volume range, min: %d, max: %d", minVol, maxVol); 1004 if (errVal != 0) 1005 { 1006 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1007 " Error setting capture volume range: %s", snd_strerror(errVal)); 1008 return -1; 1009 } 1010 1011 return 0; 1012 } 1013 */ 1014 1015 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolume( 1016 uint32_t& volume) const 1017 { 1018 1019 if (_inputMixerElement == NULL) 1020 { 1021 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1022 " no avaliable input mixer element exists"); 1023 return -1; 1024 } 1025 1026 long int vol(0); 1027 1028 int 1029 errVal = 1030 LATE(snd_mixer_selem_get_capture_volume)( 1031 _inputMixerElement, 1032 (snd_mixer_selem_channel_id_t) 0, 1033 &vol); 1034 if (errVal < 0) 1035 { 1036 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1037 "Error getting inputvolume: %s", 1038 LATE(snd_strerror)(errVal)); 1039 return -1; 1040 } 1041 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1042 " AudioMixerManagerLinuxALSA::MicrophoneVolume() => vol=%i", 1043 vol); 1044 1045 volume = static_cast<uint32_t> (vol); 1046 1047 return 0; 1048 } 1049 1050 int32_t AudioMixerManagerLinuxALSA::MaxMicrophoneVolume( 1051 uint32_t& maxVolume) const 1052 { 1053 1054 if (_inputMixerElement == NULL) 1055 { 1056 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1057 " no avaliable input mixer element exists"); 1058 return -1; 1059 } 1060 1061 long int minVol(0); 1062 long int maxVol(0); 1063 1064 // check if we have mic volume at all 1065 if (!LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement)) 1066 { 1067 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1068 " No microphone volume available"); 1069 return -1; 1070 } 1071 1072 int errVal = 1073 LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement, 1074 &minVol, &maxVol); 1075 1076 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1077 " Microphone hardware volume range, min: %d, max: %d", 1078 minVol, maxVol); 1079 if (maxVol <= minVol) 1080 { 1081 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1082 " Error getting microphone volume range: %s", 1083 LATE(snd_strerror)(errVal)); 1084 } 1085 1086 maxVolume = static_cast<uint32_t> (maxVol); 1087 1088 return 0; 1089 } 1090 1091 int32_t AudioMixerManagerLinuxALSA::MinMicrophoneVolume( 1092 uint32_t& minVolume) const 1093 { 1094 1095 if (_inputMixerElement == NULL) 1096 { 1097 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1098 " no avaliable input mixer element exists"); 1099 return -1; 1100 } 1101 1102 long int minVol(0); 1103 long int maxVol(0); 1104 1105 int errVal = 1106 LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement, 1107 &minVol, &maxVol); 1108 1109 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1110 " Microphone hardware volume range, min: %d, max: %d", 1111 minVol, maxVol); 1112 if (maxVol <= minVol) 1113 { 1114 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1115 " Error getting microphone volume range: %s", 1116 LATE(snd_strerror)(errVal)); 1117 } 1118 1119 minVolume = static_cast<uint32_t> (minVol); 1120 1121 return 0; 1122 } 1123 1124 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeStepSize( 1125 uint16_t& stepSize) const 1126 { 1127 1128 if (_inputMixerHandle == NULL) 1129 { 1130 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, 1131 " no avaliable input mixer exists"); 1132 return -1; 1133 } 1134 1135 // The step size is always 1 for ALSA 1136 stepSize = 1; 1137 1138 return 0; 1139 } 1140 1141 // ============================================================================ 1142 // Private Methods 1143 // ============================================================================ 1144 1145 int32_t AudioMixerManagerLinuxALSA::LoadMicMixerElement() const 1146 { 1147 int errVal = LATE(snd_mixer_load)(_inputMixerHandle); 1148 if (errVal < 0) 1149 { 1150 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1151 "snd_mixer_load(_inputMixerHandle), error: %s", 1152 LATE(snd_strerror)(errVal)); 1153 _inputMixerHandle = NULL; 1154 return -1; 1155 } 1156 1157 snd_mixer_elem_t *elem = NULL; 1158 snd_mixer_elem_t *micElem = NULL; 1159 unsigned mixerIdx = 0; 1160 const char *selemName = NULL; 1161 1162 // Find and store handles to the right mixer elements 1163 for (elem = LATE(snd_mixer_first_elem)(_inputMixerHandle); elem; elem 1164 = LATE(snd_mixer_elem_next)(elem), mixerIdx++) 1165 { 1166 if (LATE(snd_mixer_selem_is_active)(elem)) 1167 { 1168 selemName = LATE(snd_mixer_selem_get_name)(elem); 1169 if (strcmp(selemName, "Capture") == 0) // "Capture", "Mic" 1170 { 1171 _inputMixerElement = elem; 1172 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1173 _id, " Capture element set"); 1174 } else if (strcmp(selemName, "Mic") == 0) 1175 { 1176 micElem = elem; 1177 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1178 _id, " Mic element found"); 1179 } 1180 } 1181 1182 if (_inputMixerElement) 1183 { 1184 // Use the first Capture element that is found 1185 // The second one may not work 1186 break; 1187 } 1188 } 1189 1190 if (_inputMixerElement == NULL) 1191 { 1192 // We didn't find a Capture handle, use Mic. 1193 if (micElem != NULL) 1194 { 1195 _inputMixerElement = micElem; 1196 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1197 " Using Mic as capture volume."); 1198 } else 1199 { 1200 _inputMixerElement = NULL; 1201 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1202 "Could not find capture volume on the mixer."); 1203 1204 return -1; 1205 } 1206 } 1207 1208 return 0; 1209 } 1210 1211 int32_t AudioMixerManagerLinuxALSA::LoadSpeakerMixerElement() const 1212 { 1213 int errVal = LATE(snd_mixer_load)(_outputMixerHandle); 1214 if (errVal < 0) 1215 { 1216 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1217 " snd_mixer_load(_outputMixerHandle), error: %s", 1218 LATE(snd_strerror)(errVal)); 1219 _outputMixerHandle = NULL; 1220 return -1; 1221 } 1222 1223 snd_mixer_elem_t *elem = NULL; 1224 snd_mixer_elem_t *masterElem = NULL; 1225 snd_mixer_elem_t *speakerElem = NULL; 1226 unsigned mixerIdx = 0; 1227 const char *selemName = NULL; 1228 1229 // Find and store handles to the right mixer elements 1230 for (elem = LATE(snd_mixer_first_elem)(_outputMixerHandle); elem; elem 1231 = LATE(snd_mixer_elem_next)(elem), mixerIdx++) 1232 { 1233 if (LATE(snd_mixer_selem_is_active)(elem)) 1234 { 1235 selemName = LATE(snd_mixer_selem_get_name)(elem); 1236 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1237 "snd_mixer_selem_get_name %d: %s =%x", mixerIdx, 1238 selemName, elem); 1239 1240 // "Master", "PCM", "Wave", "Master Mono", "PC Speaker", "PCM", "Wave" 1241 if (strcmp(selemName, "PCM") == 0) 1242 { 1243 _outputMixerElement = elem; 1244 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1245 _id, " PCM element set"); 1246 } else if (strcmp(selemName, "Master") == 0) 1247 { 1248 masterElem = elem; 1249 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1250 _id, " Master element found"); 1251 } else if (strcmp(selemName, "Speaker") == 0) 1252 { 1253 speakerElem = elem; 1254 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, 1255 _id, " Speaker element found"); 1256 } 1257 } 1258 1259 if (_outputMixerElement) 1260 { 1261 // We have found the element we want 1262 break; 1263 } 1264 } 1265 1266 // If we didn't find a PCM Handle, use Master or Speaker 1267 if (_outputMixerElement == NULL) 1268 { 1269 if (masterElem != NULL) 1270 { 1271 _outputMixerElement = masterElem; 1272 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1273 " Using Master as output volume."); 1274 } else if (speakerElem != NULL) 1275 { 1276 _outputMixerElement = speakerElem; 1277 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 1278 " Using Speaker as output volume."); 1279 } else 1280 { 1281 _outputMixerElement = NULL; 1282 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, 1283 "Could not find output volume in the mixer."); 1284 return -1; 1285 } 1286 } 1287 1288 return 0; 1289 } 1290 1291 void AudioMixerManagerLinuxALSA::GetControlName(char* controlName, 1292 char* deviceName) const 1293 { 1294 // Example 1295 // deviceName: "front:CARD=Intel,DEV=0" 1296 // controlName: "hw:CARD=Intel" 1297 char* pos1 = strchr(deviceName, ':'); 1298 char* pos2 = strchr(deviceName, ','); 1299 if (!pos2) 1300 { 1301 // Can also be default:CARD=Intel 1302 pos2 = &deviceName[strlen(deviceName)]; 1303 } 1304 if (pos1 && pos2) 1305 { 1306 strcpy(controlName, "hw"); 1307 int nChar = (int) (pos2 - pos1); 1308 strncpy(&controlName[2], pos1, nChar); 1309 controlName[2 + nChar] = '\0'; 1310 } else 1311 { 1312 strcpy(controlName, deviceName); 1313 } 1314 1315 } 1316 1317 } 1318