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 "webrtc/modules/audio_device/win/audio_mixer_manager_win.h" 12 #include "webrtc/system_wrappers/interface/trace.h" 13 14 #include <assert.h> // assert() 15 #include <strsafe.h> // StringCchCopy(), StringCchCat(), StringCchPrintf() 16 17 #ifdef _WIN32 18 // removes warning: "reinterpret_cast: conversion from 'UINT' to 'HMIXEROBJ' 19 // of greater size" 20 #pragma warning(disable:4312) 21 #endif 22 23 // Avoids the need of Windows 7 SDK 24 #ifndef WAVE_MAPPED_kDefaultCommunicationDevice 25 #define WAVE_MAPPED_kDefaultCommunicationDevice 0x0010 26 #endif 27 28 namespace webrtc { 29 30 // ============================================================================ 31 // CONSTRUCTION/DESTRUCTION 32 // ============================================================================ 33 34 AudioMixerManager::AudioMixerManager(const int32_t id) : 35 _critSect(*CriticalSectionWrapper::CreateCriticalSection()), 36 _id(id), 37 _inputMixerHandle(NULL), 38 _outputMixerHandle(NULL) 39 { 40 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s constructed", __FUNCTION__); 41 ClearSpeakerState(); 42 ClearMicrophoneState(); 43 } 44 45 AudioMixerManager::~AudioMixerManager() 46 { 47 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destructed", __FUNCTION__); 48 49 Close(); 50 51 delete &_critSect; 52 } 53 54 // ============================================================================ 55 // PUBLIC METHODS 56 // ============================================================================ 57 58 // ---------------------------------------------------------------------------- 59 // Close 60 // ---------------------------------------------------------------------------- 61 62 int32_t AudioMixerManager::Close() 63 { 64 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 65 66 CriticalSectionScoped lock(&_critSect); 67 68 if (_outputMixerHandle != NULL) 69 { 70 mixerClose(_outputMixerHandle); 71 _outputMixerHandle = NULL; 72 } 73 if (_inputMixerHandle != NULL) 74 { 75 mixerClose(_inputMixerHandle); 76 _inputMixerHandle = NULL; 77 } 78 return 0; 79 80 } 81 82 // ---------------------------------------------------------------------------- 83 // CloseSpeaker 84 // ---------------------------------------------------------------------------- 85 86 int32_t AudioMixerManager::CloseSpeaker() 87 { 88 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 89 90 CriticalSectionScoped lock(&_critSect); 91 92 if (_outputMixerHandle == NULL) 93 { 94 return -1; 95 } 96 97 ClearSpeakerState(_outputMixerID); 98 99 mixerClose(_outputMixerHandle); 100 _outputMixerHandle = NULL; 101 102 return 0; 103 } 104 105 // ---------------------------------------------------------------------------- 106 // CloseMicrophone 107 // ---------------------------------------------------------------------------- 108 109 int32_t AudioMixerManager::CloseMicrophone() 110 { 111 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 112 113 CriticalSectionScoped lock(&_critSect); 114 115 if (_inputMixerHandle == NULL) 116 { 117 return -1; 118 } 119 120 ClearMicrophoneState(_inputMixerID); 121 122 mixerClose(_inputMixerHandle); 123 _inputMixerHandle = NULL; 124 125 return 0; 126 } 127 128 // ---------------------------------------------------------------------------- 129 // EnumerateAll 130 // ---------------------------------------------------------------------------- 131 132 int32_t AudioMixerManager::EnumerateAll() 133 { 134 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 135 136 UINT nDevices = mixerGetNumDevs(); 137 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices); 138 139 MIXERCAPS caps; 140 MIXERLINE destLine; 141 MIXERLINE sourceLine; 142 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS]; 143 144 UINT mixId(0); 145 UINT destId(0); 146 UINT sourceId(0); 147 148 for (mixId = 0; mixId < nDevices; mixId++) 149 { 150 if (!GetCapabilities(mixId, caps, true)) 151 continue; 152 153 for (destId = 0; destId < caps.cDestinations; destId++) 154 { 155 GetDestinationLineInfo(mixId, destId, destLine, true); 156 GetAllLineControls(mixId, destLine, controlArray, true); 157 158 for (sourceId = 0; sourceId < destLine.cConnections; sourceId++) 159 { 160 GetSourceLineInfo(mixId, destId, sourceId, sourceLine, true); 161 GetAllLineControls(mixId, sourceLine, controlArray, true); 162 } 163 } 164 } 165 166 return 0; 167 } 168 169 // ---------------------------------------------------------------------------- 170 // EnumerateSpeakers 171 // ---------------------------------------------------------------------------- 172 173 int32_t AudioMixerManager::EnumerateSpeakers() 174 { 175 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 176 177 UINT nDevices = mixerGetNumDevs(); 178 if (nDevices > MAX_NUMBER_MIXER_DEVICES) 179 { 180 assert(false); 181 return -1; 182 } 183 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices); 184 185 MIXERCAPS caps; 186 MIXERLINE destLine; 187 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS]; 188 189 UINT mixId(0); 190 UINT destId(0); 191 192 ClearSpeakerState(); 193 194 // scan all avaliable mixer devices 195 for (mixId = 0; mixId < nDevices; mixId++) 196 { 197 // get capabilities for the specified mixer ID 198 GetCapabilities(mixId, caps); 199 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[mixerID=%d] %s: ", mixId, WideToUTF8(caps.szPname)); 200 // scan all avaliable destinations for this mixer 201 for (destId = 0; destId < caps.cDestinations; destId++) 202 { 203 GetDestinationLineInfo(mixId, destId, destLine); 204 if ((destLine.cControls == 0) || // no controls or 205 (destLine.cConnections == 0) || // no source lines or 206 (destLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) || // disconnected or 207 !(destLine.fdwLine & MIXERLINE_LINEF_ACTIVE)) // inactive 208 { 209 // don't store this line ID since it will not be possible to control 210 continue; 211 } 212 if ((destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) || 213 (destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES)) 214 { 215 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found valid speaker/headphone (name: %s, ID: %u)", WideToUTF8(destLine.szName), destLine.dwLineID); 216 _speakerState[mixId].dwLineID = destLine.dwLineID; 217 _speakerState[mixId].speakerIsValid = true; 218 // retrieve all controls for the speaker component 219 GetAllLineControls(mixId, destLine, controlArray); 220 for (UINT c = 0; c < destLine.cControls; c++) 221 { 222 if (controlArray[c].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) 223 { 224 _speakerState[mixId].dwVolumeControlID = controlArray[c].dwControlID; 225 _speakerState[mixId].volumeControlIsValid = true; 226 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[c].szName), controlArray[c].dwControlID); 227 } 228 else if (controlArray[c].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) 229 { 230 _speakerState[mixId].dwMuteControlID = controlArray[c].dwControlID; 231 _speakerState[mixId].muteControlIsValid = true; 232 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[c].szName), controlArray[c].dwControlID); 233 } 234 } 235 break; 236 } 237 } 238 if (!SpeakerIsValid(mixId)) 239 { 240 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to find a valid speaker destination line", mixId); 241 } 242 } 243 244 if (ValidSpeakers() == 0) 245 { 246 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to locate any valid speaker line"); 247 return -1; 248 } 249 250 return 0; 251 } 252 253 // ---------------------------------------------------------------------------- 254 // EnumerateMicrophones 255 // ---------------------------------------------------------------------------- 256 257 int32_t AudioMixerManager::EnumerateMicrophones() 258 { 259 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); 260 261 UINT nDevices = mixerGetNumDevs(); 262 if (nDevices > MAX_NUMBER_MIXER_DEVICES) 263 { 264 assert(false); 265 return -1; 266 } 267 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices); 268 269 MIXERCAPS caps; 270 MIXERLINE destLine; 271 MIXERLINE sourceLine; 272 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS]; 273 274 UINT mixId(0); 275 UINT destId(0); 276 277 ClearMicrophoneState(); 278 279 // scan all avaliable mixer devices 280 for (mixId = 0; mixId < nDevices; mixId++) 281 { 282 // get capabilities for the specified mixer ID 283 GetCapabilities(mixId, caps); 284 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[mixerID=%d] %s: ", mixId, WideToUTF8(caps.szPname)); 285 // scan all avaliable destinations for this mixer 286 for (destId = 0; destId < caps.cDestinations; destId++) 287 { 288 GetDestinationLineInfo(mixId, destId, destLine); 289 290 if ((destLine.cConnections == 0) || // no source lines or 291 (destLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) || // disconnected or 292 !(destLine.fdwLine & MIXERLINE_LINEF_ACTIVE)) // inactive 293 { 294 // Don't store this line ID since there are no sources connected to this destination. 295 // Compare with the speaker side where we also exclude lines with no controls. 296 continue; 297 } 298 299 if (destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN) 300 { 301 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found valid Wave In destination (name: %s, ID: %u)", WideToUTF8(destLine.szName), destLine.dwLineID); 302 _microphoneState[mixId].dwLineID = destLine.dwLineID; 303 _microphoneState[mixId].microphoneIsValid = true; 304 305 // retrieve all controls for the identified wave-in destination 306 if (!GetAllLineControls(mixId, destLine, controlArray)) 307 { 308 // This destination has no controls. We must try to control 309 // one of its sources instead. 310 // This is a rare state but has been found for some 311 // Logitech USB headsets. 312 313 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 314 "this destination has no controls => must control source"); 315 for (DWORD sourceId = 0; sourceId < destLine.cConnections; sourceId++) 316 { 317 GetSourceLineInfo(mixId, destId, sourceId, sourceLine, false); 318 if (sourceLine.dwComponentType == 319 MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) 320 { 321 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 322 "found microphone source ( name: %s, ID: %u)", 323 WideToUTF8(sourceLine.szName), sourceId); 324 GetAllLineControls(mixId, sourceLine, controlArray, false); 325 // scan the controls for this source and search for volume, 326 // mute and on/off (<=> boost) controls 327 for (UINT sc = 0; sc < sourceLine.cControls; sc++) 328 { 329 if (controlArray[sc].dwControlType == 330 MIXERCONTROL_CONTROLTYPE_VOLUME) 331 { 332 // store this volume control 333 _microphoneState[mixId].dwVolumeControlID = 334 controlArray[sc].dwControlID; 335 _microphoneState[mixId].volumeControlIsValid = true; 336 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 337 "found volume control (name: %s, ID: %u)", 338 WideToUTF8(controlArray[sc].szName), 339 controlArray[sc].dwControlID); 340 } 341 else if (controlArray[sc].dwControlType == 342 MIXERCONTROL_CONTROLTYPE_MUTE) 343 { 344 // store this mute control 345 _microphoneState[mixId].dwMuteControlID = 346 controlArray[sc].dwControlID; 347 _microphoneState[mixId].muteControlIsValid = true; 348 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 349 "found mute control (name: %s, ID: %u)", 350 WideToUTF8(controlArray[sc].szName), 351 controlArray[sc].dwControlID); 352 } 353 else if (controlArray[sc].dwControlType == 354 MIXERCONTROL_CONTROLTYPE_ONOFF || 355 controlArray[sc].dwControlType == 356 MIXERCONTROL_CONTROLTYPE_LOUDNESS) 357 { 358 // store this on/off control (most likely a Boost control) 359 _microphoneState[mixId].dwOnOffControlID = 360 controlArray[sc].dwControlID; 361 _microphoneState[mixId].onOffControlIsValid = true; 362 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 363 "found on/off control (name: %s, ID: %u)", 364 WideToUTF8(controlArray[sc].szName), 365 controlArray[sc].dwControlID); 366 } 367 } 368 } 369 } 370 371 break; 372 } 373 374 // It seems like there are three different configurations we can find in this state: 375 // 376 // (1) The Wave-in destination contains one MUX control only 377 // (2) The Wave-in destination contains one or more controls where one is a volume control 378 // (3) On Vista and Win 7, it seems like case 2 above is extended. 379 // It is common that a Wave-in destination has two master controls (volume and mute), 380 // AND a microphone source as well with its own volume and mute controls with unique 381 // identifiers. Initial tests have shown that it is sufficient to modify the master 382 // controls only. The source controls will "follow" the master settings, hence the 383 // source controls seem to be redundant. 384 // 385 // For case 1, we should locate the selected source and its controls. The MUX setting will 386 // give us the selected source. NOTE - the selecion might not be a microphone. 387 // 388 // For case 2, the volume control works as a master level control and we should use that one. 389 // 390 // For case 3, we use the master controls only and assume that the source control will "follow". 391 // 392 // Examples of case 1: - SigmaTel Audio (built-in) 393 // - add more.. 394 // 395 // Examples of case 2: - Plantronics USB Headset 396 // - Eutectics IPP 200 USB phone 397 // - add more... 398 // 399 // Examples of case 3: - Realtek High Definition on Vista (TL) 400 // - add more... 401 402 if ((destLine.cControls == 1) && 403 (controlArray[0].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)) 404 { 405 // Case 1: MUX control detected => locate the selected source and its volume control 406 // Note that, the selecion might not be a microphone. A warning is given for 407 // this case only, i.e., it is OK to control a selected Line In source as long 408 // as it is connected to the wave-in destination. 409 410 UINT selection(0); 411 const DWORD nItemsInMux(controlArray[0].cMultipleItems); 412 413 // decide which source line that is selected in the mux 414 if (GetSelectedMuxSource(mixId, controlArray[0].dwControlID, nItemsInMux, selection)) 415 { 416 // selection now contains the index of the selected source => 417 // read the line information for this source 418 // if conditions listed below 419 // condition 1: invalid source 420 // condition 2: no controls 421 // condition 3: disconnected 422 // condition 4: inactive 423 if (!GetSourceLineInfo(mixId, destId, selection, sourceLine) || 424 (sourceLine.cControls == 0) || 425 (sourceLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) || 426 !(sourceLine.fdwLine & MIXERLINE_LINEF_ACTIVE)) 427 { 428 continue; 429 } 430 431 if (sourceLine.dwComponentType != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) 432 { 433 // add more details about the selected source (not a microphone) 434 TraceComponentType(sourceLine.dwComponentType); 435 // send a warning just to inform about the fact that a non-microphone source will be controlled 436 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "the selected (to be controlled) source is not a microphone type"); 437 } 438 439 // retrieve all controls for the selected source 440 GetAllLineControls(mixId, sourceLine, controlArray); 441 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "MUX selection is %u [0,%u]", selection, nItemsInMux-1); 442 443 // scan the controls for this source and search for volume, mute and on/off (<=> boost) controls 444 for (UINT sc = 0; sc < sourceLine.cControls; sc++) 445 { 446 if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) 447 { 448 // store this volume control 449 _microphoneState[mixId].dwVolumeControlID = controlArray[sc].dwControlID; 450 _microphoneState[mixId].volumeControlIsValid = true; 451 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID); 452 } 453 else if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) 454 { 455 // store this mute control 456 _microphoneState[mixId].dwMuteControlID = controlArray[sc].dwControlID; 457 _microphoneState[mixId].muteControlIsValid = true; 458 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID); 459 } 460 else if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF || 461 controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_LOUDNESS) 462 { 463 // store this on/off control (most likely a Boost control) 464 _microphoneState[mixId].dwOnOffControlID = controlArray[sc].dwControlID; 465 _microphoneState[mixId].onOffControlIsValid = true; 466 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found on/off control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID); 467 } 468 } 469 } 470 else 471 { 472 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to detect which source to control"); 473 } 474 475 } 476 else if (destLine.cConnections == 1) 477 { 478 // Case 2 or Case 3: 479 480 GetSourceLineInfo(mixId, destId, 0, sourceLine); 481 if ((sourceLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) && 482 (sourceLine.cControls > 0)) 483 { 484 // Case 3: same as Case 2 below but we have also detected a Microphone source 485 // with its own controls. So far, I have not been able to find any device 486 // where it is required to modify these controls. Until I have found such 487 // a device, this case will be handled as a Case 2 (see below). 488 489 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "microphone source controls will not be controlled"); 490 } 491 else if ((sourceLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) && 492 (sourceLine.cControls == 0)) 493 { 494 // default state on non Vista/Win 7 machines 495 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "microphone source has no controls => use master controls instead"); 496 } 497 else 498 { 499 // add more details about the selected source (not a microphone) 500 TraceComponentType(sourceLine.dwComponentType); 501 // send a warning just to inform about the fact that a non-microphone source will be controlled 502 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "the connected (to be controlled) source is not a microphone type"); 503 } 504 505 // Case 2 : one source only and no MUX control detected => 506 // locate the master volume control (and mute + boost controls if possible) 507 508 // scan the controls for this wave-in destination and search for volume, mute and on/off (<=> boost) controls 509 for (UINT dc = 0; dc < destLine.cControls; dc++) 510 { 511 if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) 512 { 513 // store this volume control 514 _microphoneState[mixId].dwVolumeControlID = controlArray[dc].dwControlID; 515 _microphoneState[mixId].volumeControlIsValid = true; 516 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID); 517 } 518 else if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) 519 { 520 // store this mute control 521 _microphoneState[mixId].dwMuteControlID = controlArray[dc].dwControlID; 522 _microphoneState[mixId].muteControlIsValid = true; 523 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID); 524 } 525 else if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF || 526 controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_LOUDNESS || 527 controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) 528 { 529 // store this on/off control 530 _microphoneState[mixId].dwOnOffControlID = controlArray[dc].dwControlID; 531 _microphoneState[mixId].onOffControlIsValid = true; 532 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found on/off control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID); 533 } 534 } 535 } 536 else 537 { 538 // We are in a state where more than one source is connected to the wave-in destination. 539 // I am bailing out here for now until I understand this case better. 540 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to locate valid microphone controls for this mixer"); 541 } 542 break; 543 } 544 } // for (destId = 0; destId < caps.cDestinations; destId++) 545 546 if (!MicrophoneIsValid(mixId)) 547 { 548 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to find a valid microphone destination line", mixId); 549 } 550 } // for (mixId = 0; mixId < nDevices; mixId++) 551 552 if (ValidMicrophones() == 0) 553 { 554 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to locate any valid microphone line"); 555 return -1; 556 } 557 558 return 0; 559 } 560 561 // ---------------------------------------------------------------------------- 562 // OpenSpeaker I(II) 563 // 564 // Verifies that the mixer contains a valid speaker destination line. 565 // Avoids opening the mixer if valid control has not been found. 566 // ---------------------------------------------------------------------------- 567 568 int32_t AudioMixerManager::OpenSpeaker(AudioDeviceModule::WindowsDeviceType device) 569 { 570 if (device == AudioDeviceModule::kDefaultDevice) 571 { 572 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(kDefaultDevice)"); 573 } 574 else if (device == AudioDeviceModule::kDefaultCommunicationDevice) 575 { 576 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(kDefaultCommunicationDevice)"); 577 } 578 579 CriticalSectionScoped lock(&_critSect); 580 581 // Close any existing output mixer handle 582 // 583 if (_outputMixerHandle != NULL) 584 { 585 mixerClose(_outputMixerHandle); 586 _outputMixerHandle = NULL; 587 } 588 589 MMRESULT res = MMSYSERR_NOERROR; 590 WAVEFORMATEX waveFormat; 591 HWAVEOUT hWaveOut(NULL); 592 593 waveFormat.wFormatTag = WAVE_FORMAT_PCM ; 594 waveFormat.nChannels = 2; 595 waveFormat.nSamplesPerSec = 48000; 596 waveFormat.wBitsPerSample = 16; 597 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 598 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 599 waveFormat.cbSize = 0; 600 601 // We need a waveform-audio output handle for the currently selected output device. 602 // This handle will then give us the corresponding mixer identifier. Once the mixer 603 // ID is known, it is possible to open the output mixer. 604 // 605 if (device == AudioDeviceModule::kDefaultCommunicationDevice) 606 { 607 // check if it is possible to open the default communication device (supported on Windows 7) 608 res = waveOutOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | 609 WAVE_MAPPED_kDefaultCommunicationDevice | WAVE_FORMAT_QUERY); 610 if (MMSYSERR_NOERROR == res) 611 { 612 // if so, open the default communication device for real 613 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_kDefaultCommunicationDevice); 614 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device"); 615 } 616 else 617 { 618 // use default device since default communication device was not avaliable 619 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 620 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 621 "unable to open default communication device => using default instead"); 622 } 623 } 624 else if (device == AudioDeviceModule::kDefaultDevice) 625 { 626 // open default device since it has been requested 627 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 628 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default output device"); 629 } 630 631 if (MMSYSERR_NOERROR != res) 632 { 633 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutOpen() failed (err=%d)", res); 634 TraceWaveOutError(res); 635 } 636 637 UINT mixerId(0); 638 HMIXER hMixer(NULL); 639 640 // Retrieve the device identifier for a mixer device associated with the 641 // aquired waveform-audio output handle. 642 // 643 res = mixerGetID((HMIXEROBJ)hWaveOut, &mixerId, MIXER_OBJECTF_HWAVEOUT); 644 if (MMSYSERR_NOERROR != res) 645 { 646 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEOUT) failed (err=%d)", res); 647 // identification failed => use default mixer identifier (=0) 648 mixerId = 0; 649 } 650 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified output device <=> mixer ID %u", mixerId); 651 652 // The waveform-audio output handle is no longer needed. 653 // 654 waveOutClose(hWaveOut); 655 656 // Verify that the mixer contains a valid speaker destination line. 657 // Avoid opening the mixer if valid control has not been found. 658 // 659 if (!SpeakerIsValid(mixerId)) 660 { 661 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the speaker volume for this mixer device"); 662 return -1; 663 } 664 665 // Open the specified mixer device and ensure that the device will not 666 // be removed until the application closes the handle. 667 // 668 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER); 669 if (MMSYSERR_NOERROR != res) 670 { 671 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res); 672 } 673 674 // Store the output mixer handle and active mixer identifier 675 // 676 _outputMixerHandle = hMixer; 677 _outputMixerID = mixerId; 678 679 if (_outputMixerHandle != NULL) 680 { 681 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the output mixer device is now open (0x%x)", _outputMixerHandle); 682 } 683 684 return 0; 685 } 686 687 // ---------------------------------------------------------------------------- 688 // OpenSpeaker II(II) 689 // 690 // Verifies that the mixer contains a valid speaker destination line. 691 // Avoids opening the mixer if valid control has not been found. 692 // ---------------------------------------------------------------------------- 693 694 int32_t AudioMixerManager::OpenSpeaker(uint16_t index) 695 { 696 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(index=%d)", index); 697 698 CriticalSectionScoped lock(&_critSect); 699 700 // Close any existing output mixer handle 701 // 702 if (_outputMixerHandle != NULL) 703 { 704 mixerClose(_outputMixerHandle); 705 _outputMixerHandle = NULL; 706 } 707 708 MMRESULT res; 709 WAVEFORMATEX waveFormat; 710 HWAVEOUT hWaveOut(NULL); 711 712 const UINT deviceID(index); // use index parameter as device identifier 713 714 waveFormat.wFormatTag = WAVE_FORMAT_PCM ; 715 waveFormat.nChannels = 2; 716 waveFormat.nSamplesPerSec = 48000; 717 waveFormat.wBitsPerSample = 16; 718 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 719 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 720 waveFormat.cbSize = 0; 721 722 // We need a waveform-audio output handle for the currently selected output device. 723 // This handle will then give us the corresponding mixer identifier. Once the mixer 724 // ID is known, it is possible to open the output mixer. 725 // 726 res = waveOutOpen(&hWaveOut, deviceID, &waveFormat, 0, 0, CALLBACK_NULL); 727 if (MMSYSERR_NOERROR != res) 728 { 729 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutOpen(deviceID=%u) failed (err=%d)", index, res); 730 TraceWaveOutError(res); 731 } 732 733 UINT mixerId(0); 734 HMIXER hMixer(NULL); 735 736 // Retrieve the device identifier for a mixer device associated with the 737 // aquired waveform-audio output handle. 738 // 739 res = mixerGetID((HMIXEROBJ)hWaveOut, &mixerId, MIXER_OBJECTF_HWAVEOUT); 740 if (MMSYSERR_NOERROR != res) 741 { 742 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEOUT) failed (err=%d)", res); 743 // identification failed => use default mixer identifier (=0) 744 mixerId = 0; 745 } 746 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified output device <=> mixer ID %u", mixerId); 747 748 // The waveform-audio output handle is no longer needed. 749 // 750 waveOutClose(hWaveOut); 751 752 // Verify that the mixer contains a valid speaker destination line. 753 // Avoid opening the mixer if valid control has not been found. 754 // 755 if (!SpeakerIsValid(mixerId)) 756 { 757 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the speaker volume for this mixer device"); 758 return -1; 759 } 760 761 // Open the specified mixer device and ensure that the device will not 762 // be removed until the application closes the handle. 763 // 764 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER); 765 if (MMSYSERR_NOERROR != res) 766 { 767 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res); 768 } 769 770 // Store the output mixer handle and active mixer identifier 771 // 772 _outputMixerHandle = hMixer; 773 _outputMixerID = mixerId; 774 775 if (_outputMixerHandle != NULL) 776 { 777 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the output mixer device is now open (0x%x)", _outputMixerHandle); 778 } 779 780 return 0; 781 } 782 783 // ---------------------------------------------------------------------------- 784 // OpenMicrophone I(II) 785 // 786 // Verifies that the mixer contains a valid wave-in destination line. 787 // Avoids opening the mixer if valid control has not been found. 788 // ---------------------------------------------------------------------------- 789 790 int32_t AudioMixerManager::OpenMicrophone(AudioDeviceModule::WindowsDeviceType device) 791 { 792 if (device == AudioDeviceModule::kDefaultDevice) 793 { 794 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(kDefaultDevice)"); 795 } 796 else if (device == AudioDeviceModule::kDefaultCommunicationDevice) 797 { 798 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(kDefaultCommunicationDevice)"); 799 } 800 801 CriticalSectionScoped lock(&_critSect); 802 803 // Close any existing output mixer handle 804 // 805 if (_inputMixerHandle != NULL) 806 { 807 mixerClose(_inputMixerHandle); 808 _inputMixerHandle = NULL; 809 } 810 811 MMRESULT res = MMSYSERR_NOERROR; 812 WAVEFORMATEX waveFormat; 813 HWAVEIN hWaveIn(NULL); 814 815 waveFormat.wFormatTag = WAVE_FORMAT_PCM ; 816 waveFormat.nChannels = 1; 817 waveFormat.nSamplesPerSec = 48000; 818 waveFormat.wBitsPerSample = 16; 819 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 820 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 821 waveFormat.cbSize = 0 ; 822 823 // We need a waveform-audio input handle for the currently selected input device. 824 // This handle will then give us the corresponding mixer identifier. Once the mixer 825 // ID is known, it is possible to open the input mixer. 826 // 827 if (device == AudioDeviceModule::kDefaultCommunicationDevice) 828 { 829 // check if it is possible to open the default communication device (supported on Windows 7) 830 res = waveInOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | 831 WAVE_MAPPED_kDefaultCommunicationDevice | WAVE_FORMAT_QUERY); 832 if (MMSYSERR_NOERROR == res) 833 { 834 // if so, open the default communication device for real 835 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_kDefaultCommunicationDevice); 836 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device"); 837 } 838 else 839 { 840 // use default device since default communication device was not avaliable 841 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 842 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, 843 "unable to open default communication device => using default instead"); 844 } 845 } 846 else if (device == AudioDeviceModule::kDefaultDevice) 847 { 848 // open default device since it has been requested 849 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL); 850 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default input device"); 851 } 852 853 if (MMSYSERR_NOERROR != res) 854 { 855 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInOpen() failed (err=%d)", res); 856 TraceWaveInError(res); 857 } 858 859 UINT mixerId(0); 860 HMIXER hMixer(NULL); 861 862 // Retrieve the device identifier for a mixer device associated with the 863 // aquired waveform-audio input handle. 864 // 865 res = mixerGetID((HMIXEROBJ)hWaveIn, &mixerId, MIXER_OBJECTF_HWAVEIN); 866 if (MMSYSERR_NOERROR != res) 867 { 868 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEIN) failed (err=%d)", res); 869 // identification failed => use default mixer identifier (=0) 870 mixerId = 0; 871 } 872 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified input device <=> mixer ID %u", mixerId); 873 874 // The waveform-audio input handle is no longer needed. 875 // 876 waveInClose(hWaveIn); 877 878 // Verify that the mixer contains a valid wave-in destination line and a volume control. 879 // Avoid opening the mixer if valid control has not been found. 880 // 881 if (!MicrophoneIsValid(mixerId)) 882 { 883 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the microphone volume for this mixer device"); 884 return -1; 885 } 886 887 // Open the specified mixer device and ensure that the device will not 888 // be removed until the application closes the handle. 889 // 890 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER); 891 if (MMSYSERR_NOERROR != res) 892 { 893 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res); 894 } 895 896 // Store the input mixer handle and active mixer identifier 897 // 898 _inputMixerHandle = hMixer; 899 _inputMixerID = mixerId; 900 901 if (_inputMixerHandle != NULL) 902 { 903 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the input mixer device is now open (0x%x)", _inputMixerHandle); 904 } 905 906 return 0; 907 } 908 909 // ---------------------------------------------------------------------------- 910 // OpenMicrophone II(II) 911 // 912 // Verifies that the mixer contains a valid wave-in destination line. 913 // Avoids opening the mixer if valid control has not been found. 914 // ---------------------------------------------------------------------------- 915 916 int32_t AudioMixerManager::OpenMicrophone(uint16_t index) 917 { 918 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(index=%d)", index); 919 920 CriticalSectionScoped lock(&_critSect); 921 922 // Close any existing input mixer handle 923 // 924 if (_inputMixerHandle != NULL) 925 { 926 mixerClose(_inputMixerHandle); 927 _inputMixerHandle = NULL; 928 } 929 930 MMRESULT res; 931 WAVEFORMATEX waveFormat; 932 HWAVEIN hWaveIn(NULL); 933 934 const UINT deviceID(index); // use index parameter as device identifier 935 936 waveFormat.wFormatTag = WAVE_FORMAT_PCM ; 937 waveFormat.nChannels = 1; 938 waveFormat.nSamplesPerSec = 48000; 939 waveFormat.wBitsPerSample = 16; 940 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 941 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 942 waveFormat.cbSize = 0; 943 944 // We need a waveform-audio input handle for the currently selected input device. 945 // This handle will then give us the corresponding mixer identifier. Once the mixer 946 // ID is known, it is possible to open the input mixer. 947 // 948 res = waveInOpen(&hWaveIn, deviceID, &waveFormat, 0, 0, CALLBACK_NULL); 949 if (MMSYSERR_NOERROR != res) 950 { 951 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInOpen(deviceID=%u) failed (err=%d)", index, res); 952 TraceWaveInError(res); 953 } 954 955 UINT mixerId(0); 956 HMIXER hMixer(NULL); 957 958 // Retrieve the device identifier for a mixer device associated with the 959 // aquired waveform-audio input handle. 960 // 961 res = mixerGetID((HMIXEROBJ)hWaveIn, &mixerId, MIXER_OBJECTF_HWAVEIN); 962 if (MMSYSERR_NOERROR != res) 963 { 964 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEIN) failed (err=%d)", res); 965 // identification failed => use default mixer identifier (=0) 966 mixerId = 0; 967 } 968 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified input device <=> mixer ID %u", mixerId); 969 970 // The waveform-audio input handle is no longer needed. 971 // 972 waveInClose(hWaveIn); 973 974 // Verify that the mixer contains a valid wave-in destination line. 975 // Avoid opening the mixer if valid control has not been found. 976 // 977 if (!MicrophoneIsValid(mixerId)) 978 { 979 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the microphone volume for this mixer device"); 980 return -1; 981 } 982 983 // Open the specified mixer device and ensure that the device will not 984 // be removed until the application closes the handle. 985 // 986 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER); 987 if (MMSYSERR_NOERROR != res) 988 { 989 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res); 990 } 991 992 // Store the input mixer handle and active mixer identifier 993 // 994 _inputMixerHandle = hMixer; 995 _inputMixerID = mixerId; 996 997 if (_inputMixerHandle != NULL) 998 { 999 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the input mixer device is now open (0x%x)", _inputMixerHandle); 1000 } 1001 1002 return 0; 1003 } 1004 1005 // ---------------------------------------------------------------------------- 1006 // SpeakerIsInitialized 1007 // ---------------------------------------------------------------------------- 1008 1009 bool AudioMixerManager::SpeakerIsInitialized() const 1010 { 1011 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); 1012 1013 return (_outputMixerHandle != NULL); 1014 } 1015 1016 // ---------------------------------------------------------------------------- 1017 // MicrophoneIsInitialized 1018 // ---------------------------------------------------------------------------- 1019 1020 bool AudioMixerManager::MicrophoneIsInitialized() const 1021 { 1022 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); 1023 1024 return (_inputMixerHandle != NULL); 1025 } 1026 1027 // ---------------------------------------------------------------------------- 1028 // SetSpeakerVolume 1029 // ---------------------------------------------------------------------------- 1030 1031 int32_t AudioMixerManager::SetSpeakerVolume(uint32_t volume) 1032 { 1033 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetSpeakerVolume(volume=%u)", volume); 1034 1035 CriticalSectionScoped lock(&_critSect); 1036 1037 if (_outputMixerHandle == NULL) 1038 { 1039 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1040 return -1; 1041 } 1042 1043 const UINT mixerID(_outputMixerID); 1044 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID); 1045 DWORD dwValue(volume); 1046 1047 // Set one unsigned control value for a specified volume-control identifier 1048 // 1049 if (!SetUnsignedControlValue(mixerID, dwControlID, dwValue)) 1050 { 1051 return -1; 1052 } 1053 1054 return (0); 1055 } 1056 1057 // ---------------------------------------------------------------------------- 1058 // SpeakerVolume 1059 // 1060 // Note that (MIXERCONTROL_CONTROLTYPE_VOLUME & MIXERCONTROL_CT_UNITS_MASK) 1061 // always equals MIXERCONTROL_CT_UNITS_UNSIGNED; 1062 // ---------------------------------------------------------------------------- 1063 1064 int32_t AudioMixerManager::SpeakerVolume(uint32_t& volume) const 1065 { 1066 1067 if (_outputMixerHandle == NULL) 1068 { 1069 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1070 return -1; 1071 } 1072 1073 const UINT mixerID(_outputMixerID); 1074 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID); 1075 DWORD dwValue(0); 1076 1077 // Retrieve one unsigned control value for a specified volume-control identifier 1078 // 1079 if (!GetUnsignedControlValue(mixerID, dwControlID, dwValue)) 1080 { 1081 return -1; 1082 } 1083 1084 volume = dwValue; 1085 1086 return 0; 1087 } 1088 1089 // ---------------------------------------------------------------------------- 1090 // MaxSpeakerVolume 1091 // 1092 // Note that (MIXERCONTROL_CONTROLTYPE_VOLUME & MIXERCONTROL_CT_UNITS_MASK) 1093 // always equals MIXERCONTROL_CT_UNITS_UNSIGNED 1094 // ---------------------------------------------------------------------------- 1095 1096 int32_t AudioMixerManager::MaxSpeakerVolume(uint32_t& maxVolume) const 1097 { 1098 1099 if (_outputMixerHandle == NULL) 1100 { 1101 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1102 return -1; 1103 } 1104 1105 const UINT mixerID(_outputMixerID); 1106 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID); 1107 MIXERCONTROL mixerControl; 1108 1109 // Retrieve one control line for a specified volume-control identifier 1110 // 1111 if (!GetLineControl(mixerID, dwControlID, mixerControl)) 1112 { 1113 return -1; 1114 } 1115 1116 maxVolume = mixerControl.Bounds.dwMaximum; 1117 1118 return 0; 1119 } 1120 1121 // ---------------------------------------------------------------------------- 1122 // MinSpeakerVolume 1123 // ---------------------------------------------------------------------------- 1124 1125 int32_t AudioMixerManager::MinSpeakerVolume(uint32_t& minVolume) const 1126 { 1127 1128 if (_outputMixerHandle == NULL) 1129 { 1130 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1131 return -1; 1132 } 1133 1134 const UINT mixerID(_outputMixerID); 1135 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID); 1136 MIXERCONTROL mixerControl; 1137 1138 // Retrieve one control line for a specified volume-control identifier 1139 // 1140 if (!GetLineControl(mixerID, dwControlID, mixerControl)) 1141 { 1142 return -1; 1143 } 1144 1145 minVolume = mixerControl.Bounds.dwMinimum; 1146 1147 return 0; 1148 } 1149 1150 // ---------------------------------------------------------------------------- 1151 // SpeakerVolumeStepSize 1152 // ---------------------------------------------------------------------------- 1153 1154 int32_t AudioMixerManager::SpeakerVolumeStepSize(uint16_t& stepSize) const 1155 { 1156 1157 if (_outputMixerHandle == NULL) 1158 { 1159 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1160 return -1; 1161 } 1162 1163 const UINT mixerID(_outputMixerID); 1164 MIXERCONTROL mixerControl; 1165 1166 // Retrieve one control line for a specified volume-control identifier 1167 // 1168 if (!GetLineControl(mixerID, _speakerState[mixerID].dwVolumeControlID, mixerControl)) 1169 { 1170 return -1; 1171 } 1172 1173 stepSize = static_cast<uint16_t> (mixerControl.Metrics.cSteps); 1174 1175 return 0; 1176 } 1177 1178 // ---------------------------------------------------------------------------- 1179 // SpeakerVolumeIsAvailable 1180 // ---------------------------------------------------------------------------- 1181 1182 int32_t AudioMixerManager::SpeakerVolumeIsAvailable(bool& available) 1183 { 1184 if (_outputMixerHandle == NULL) 1185 { 1186 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1187 return -1; 1188 } 1189 1190 available = _speakerState[_outputMixerID].volumeControlIsValid; 1191 1192 return 0; 1193 } 1194 1195 // ---------------------------------------------------------------------------- 1196 // SpeakerMuteIsAvailable 1197 // ---------------------------------------------------------------------------- 1198 1199 int32_t AudioMixerManager::SpeakerMuteIsAvailable(bool& available) 1200 { 1201 if (_outputMixerHandle == NULL) 1202 { 1203 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1204 return -1; 1205 } 1206 1207 available = _speakerState[_outputMixerID].muteControlIsValid; 1208 1209 return 0; 1210 } 1211 1212 // ---------------------------------------------------------------------------- 1213 // SetSpeakerMute 1214 // 1215 // This mute function works a master mute for the output speaker. 1216 // ---------------------------------------------------------------------------- 1217 1218 int32_t AudioMixerManager::SetSpeakerMute(bool enable) 1219 { 1220 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetSpeakerMute(enable=%u)", enable); 1221 1222 CriticalSectionScoped lock(&_critSect); 1223 1224 if (_outputMixerHandle == NULL) 1225 { 1226 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1227 return -1; 1228 } 1229 1230 // Ensure that the selected speaker destination has a valid mute control. 1231 // If so, its identifier was stored during the enumeration phase which must 1232 // have taken place since the output mixer handle exists. 1233 // 1234 if (!_speakerState[_outputMixerID].muteControlIsValid) 1235 { 1236 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this speaker line"); 1237 return -1; 1238 } 1239 1240 const DWORD dwControlID(_speakerState[_outputMixerID].dwMuteControlID); 1241 1242 // Set one boolean control value for the specified mute-control 1243 // 1244 if (!SetBooleanControlValue(_outputMixerID, dwControlID, enable)) 1245 { 1246 return -1; 1247 } 1248 1249 return (0); 1250 } 1251 1252 // ---------------------------------------------------------------------------- 1253 // SpeakerMute 1254 // ---------------------------------------------------------------------------- 1255 1256 int32_t AudioMixerManager::SpeakerMute(bool& enabled) const 1257 { 1258 1259 if (_outputMixerHandle == NULL) 1260 { 1261 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists"); 1262 return -1; 1263 } 1264 1265 // Ensure that the selected speaker destination has a valid mute control. 1266 // If so, its identifier was stored during the enumeration phase which must 1267 // have taken place since the output mixer handle exists. 1268 // 1269 if (!_speakerState[_outputMixerID].muteControlIsValid) 1270 { 1271 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this speaker line"); 1272 return -1; 1273 } 1274 1275 const DWORD dwControlID(_speakerState[_outputMixerID].dwMuteControlID); 1276 bool value(false); 1277 1278 // Retrieve one boolean control value for a specified mute-control identifier 1279 // 1280 if (!GetBooleanControlValue(_outputMixerID, dwControlID, value)) 1281 { 1282 return -1; 1283 } 1284 1285 enabled = value; 1286 1287 return 0; 1288 } 1289 1290 // ---------------------------------------------------------------------------- 1291 // MicrophoneMuteIsAvailable 1292 // ---------------------------------------------------------------------------- 1293 1294 int32_t AudioMixerManager::MicrophoneMuteIsAvailable(bool& available) 1295 { 1296 if (_inputMixerHandle == NULL) 1297 { 1298 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1299 return -1; 1300 } 1301 1302 available = _microphoneState[_inputMixerID].muteControlIsValid; 1303 1304 return 0; 1305 } 1306 1307 // ---------------------------------------------------------------------------- 1308 // SetMicrophoneMute 1309 // 1310 // This mute function works a master mute for the input microphone. 1311 // ---------------------------------------------------------------------------- 1312 1313 int32_t AudioMixerManager::SetMicrophoneMute(bool enable) 1314 { 1315 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetMicrophoneMute(enable=%u)", enable); 1316 1317 CriticalSectionScoped lock(&_critSect); 1318 1319 if (_inputMixerHandle == NULL) 1320 { 1321 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1322 return -1; 1323 } 1324 1325 // Ensure that the selected wave-in destinationhas a valid mute control. 1326 // If so, its identifier was stored during the enumeration phase which must 1327 // have taken place since the input mixer handle exists. 1328 // 1329 if (!_microphoneState[_inputMixerID].muteControlIsValid) 1330 { 1331 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this microphone line"); 1332 return -1; 1333 } 1334 1335 const DWORD dwControlID(_microphoneState[_inputMixerID].dwMuteControlID); 1336 1337 // Set one boolean control value for the specified mute-control 1338 // 1339 if (!SetBooleanControlValue(_inputMixerID, dwControlID, enable)) 1340 { 1341 return -1; 1342 } 1343 1344 return (0); 1345 } 1346 1347 // ---------------------------------------------------------------------------- 1348 // MicrophoneMute 1349 // ---------------------------------------------------------------------------- 1350 1351 int32_t AudioMixerManager::MicrophoneMute(bool& enabled) const 1352 { 1353 1354 if (_inputMixerHandle == NULL) 1355 { 1356 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1357 return -1; 1358 } 1359 1360 // Ensure that the selected wave-in destinationhas a valid mute control. 1361 // If so, its identifier was stored during the enumeration phase which must 1362 // have taken place since the input mixer handle exists. 1363 // 1364 if (!_microphoneState[_inputMixerID].muteControlIsValid) 1365 { 1366 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this microphone line"); 1367 return -1; 1368 } 1369 1370 const DWORD dwControlID(_microphoneState[_inputMixerID].dwMuteControlID); 1371 bool value(false); 1372 1373 // Retrieve one boolean control value for a specified mute-control identifier 1374 // 1375 if (!GetBooleanControlValue(_inputMixerID, dwControlID, value)) 1376 { 1377 return -1; 1378 } 1379 1380 enabled = value; 1381 1382 return 0; 1383 } 1384 1385 // ---------------------------------------------------------------------------- 1386 // MicrophoneBoostIsAvailable 1387 // ---------------------------------------------------------------------------- 1388 1389 int32_t AudioMixerManager::MicrophoneBoostIsAvailable(bool& available) 1390 { 1391 if (_inputMixerHandle == NULL) 1392 { 1393 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1394 return -1; 1395 } 1396 1397 available = _microphoneState[_inputMixerID].onOffControlIsValid; 1398 1399 return 0; 1400 } 1401 1402 // ---------------------------------------------------------------------------- 1403 // SetMicrophoneBoost 1404 // ---------------------------------------------------------------------------- 1405 1406 int32_t AudioMixerManager::SetMicrophoneBoost(bool enable) 1407 { 1408 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetMicrophoneBoost(enable=%u)", enable); 1409 1410 CriticalSectionScoped lock(&_critSect); 1411 1412 if (_inputMixerHandle == NULL) 1413 { 1414 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1415 return -1; 1416 } 1417 1418 // Ensure that the selected wave-in destination has a valid boost (on/off) control. 1419 // If so, its identifier was stored during the enumeration phase which must 1420 // have taken place since the input mixer handle exists. 1421 // 1422 if (!_microphoneState[_inputMixerID].onOffControlIsValid) 1423 { 1424 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no boost control exists for this wave-in line"); 1425 return -1; 1426 } 1427 1428 const DWORD dwControlID(_microphoneState[_inputMixerID].dwOnOffControlID); 1429 1430 // Set one boolean control value for the specified boost (on/off) control 1431 // 1432 if (!SetBooleanControlValue(_inputMixerID, dwControlID, enable)) 1433 { 1434 return -1; 1435 } 1436 1437 return (0); 1438 } 1439 1440 // ---------------------------------------------------------------------------- 1441 // MicrophoneBoost 1442 // ---------------------------------------------------------------------------- 1443 1444 int32_t AudioMixerManager::MicrophoneBoost(bool& enabled) const 1445 { 1446 1447 if (_inputMixerHandle == NULL) 1448 { 1449 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1450 return -1; 1451 } 1452 1453 // Ensure that the selected wave-in destination has a valid boost (on/off) control. 1454 // If so, its identifier was stored during the enumeration phase which must 1455 // have taken place since the input mixer handle exists. 1456 // 1457 if (!_microphoneState[_inputMixerID].onOffControlIsValid) 1458 { 1459 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no boost control exists for this wave-in line"); 1460 return -1; 1461 } 1462 1463 const DWORD dwControlID(_microphoneState[_inputMixerID].dwOnOffControlID); 1464 bool value(false); 1465 1466 // Retrieve one boolean control value for a specified boost-control identifier 1467 // 1468 if (!GetBooleanControlValue(_inputMixerID, dwControlID, value)) 1469 { 1470 return -1; 1471 } 1472 1473 enabled = value; 1474 1475 return 0; 1476 } 1477 1478 // ---------------------------------------------------------------------------- 1479 // MicrophoneVolumeIsAvailable 1480 // ---------------------------------------------------------------------------- 1481 1482 int32_t AudioMixerManager::MicrophoneVolumeIsAvailable(bool& available) 1483 { 1484 if (_inputMixerHandle == NULL) 1485 { 1486 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1487 return -1; 1488 } 1489 1490 available = _microphoneState[_inputMixerID].volumeControlIsValid; 1491 1492 return 0; 1493 } 1494 1495 // ---------------------------------------------------------------------------- 1496 // SetMicrophoneVolume 1497 // ---------------------------------------------------------------------------- 1498 1499 int32_t AudioMixerManager::SetMicrophoneVolume(uint32_t volume) 1500 { 1501 CriticalSectionScoped lock(&_critSect); 1502 1503 if (_inputMixerHandle == NULL) 1504 { 1505 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1506 return -1; 1507 } 1508 1509 const UINT mixerID(_inputMixerID); 1510 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID); 1511 DWORD dwValue(volume); 1512 1513 // Set one unsigned control value for a specified volume-control identifier 1514 // 1515 if (!SetUnsignedControlValue(mixerID, dwControlID, dwValue)) 1516 { 1517 return -1; 1518 } 1519 1520 return (0); 1521 } 1522 1523 // ---------------------------------------------------------------------------- 1524 // MicrophoneVolume 1525 // ---------------------------------------------------------------------------- 1526 1527 int32_t AudioMixerManager::MicrophoneVolume(uint32_t& volume) const 1528 { 1529 CriticalSectionScoped lock(&_critSect); 1530 1531 if (_inputMixerHandle == NULL) 1532 { 1533 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1534 return -1; 1535 } 1536 1537 const UINT mixerID(_inputMixerID); 1538 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID); 1539 DWORD dwValue(0); 1540 1541 // Retrieve one unsigned control value for a specified volume-control identifier 1542 // 1543 if (!GetUnsignedControlValue(mixerID, dwControlID, dwValue)) 1544 { 1545 return -1; 1546 } 1547 1548 volume = dwValue; 1549 1550 return 0; 1551 } 1552 1553 // ---------------------------------------------------------------------------- 1554 // MaxMicrophoneVolume 1555 // ---------------------------------------------------------------------------- 1556 1557 int32_t AudioMixerManager::MaxMicrophoneVolume(uint32_t& maxVolume) const 1558 { 1559 WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "%s", __FUNCTION__); 1560 1561 if (_inputMixerHandle == NULL) 1562 { 1563 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1564 return -1; 1565 } 1566 1567 const UINT mixerID(_inputMixerID); 1568 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID); 1569 MIXERCONTROL mixerControl; 1570 1571 // Retrieve one control line for a specified volume-control identifier 1572 // 1573 if (!GetLineControl(mixerID, dwControlID, mixerControl)) 1574 { 1575 return -1; 1576 } 1577 1578 maxVolume = mixerControl.Bounds.dwMaximum; 1579 1580 return 0; 1581 } 1582 1583 // ---------------------------------------------------------------------------- 1584 // MinMicrophoneVolume 1585 // ---------------------------------------------------------------------------- 1586 1587 int32_t AudioMixerManager::MinMicrophoneVolume(uint32_t& minVolume) const 1588 { 1589 1590 if (_inputMixerHandle == NULL) 1591 { 1592 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1593 return -1; 1594 } 1595 1596 const UINT mixerID(_inputMixerID); 1597 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID); 1598 MIXERCONTROL mixerControl; 1599 1600 // Retrieve one control line for a specified volume-control identifier 1601 // 1602 if (!GetLineControl(mixerID, dwControlID, mixerControl)) 1603 { 1604 return -1; 1605 } 1606 1607 minVolume = mixerControl.Bounds.dwMinimum; 1608 1609 return 0; 1610 } 1611 1612 // ---------------------------------------------------------------------------- 1613 // MicrophoneVolumeStepSize 1614 // ---------------------------------------------------------------------------- 1615 1616 int32_t AudioMixerManager::MicrophoneVolumeStepSize(uint16_t& stepSize) const 1617 { 1618 1619 if (_inputMixerHandle == NULL) 1620 { 1621 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists"); 1622 return -1; 1623 } 1624 1625 const UINT mixerID(_inputMixerID); 1626 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID); 1627 MIXERCONTROL mixerControl; 1628 1629 // Retrieve one control line for a specified volume-control identifier 1630 // 1631 if (!GetLineControl(mixerID, dwControlID, mixerControl)) 1632 { 1633 return -1; 1634 } 1635 1636 stepSize = static_cast<uint16_t> (mixerControl.Metrics.cSteps); 1637 1638 return 0; 1639 } 1640 1641 // ============================================================================ 1642 // PRIVATE METHODS 1643 // ============================================================================ 1644 1645 // ---------------------------------------------------------------------------- 1646 // Devices 1647 // 1648 // A given audio card has one Mixer device associated with it. All of the 1649 // various components on that card are controlled through that card's one 1650 // Mixer device. 1651 // ---------------------------------------------------------------------------- 1652 1653 UINT AudioMixerManager::Devices() const 1654 { 1655 UINT nDevs = mixerGetNumDevs(); 1656 return nDevs; 1657 } 1658 1659 // ---------------------------------------------------------------------------- 1660 // DestinationLines 1661 // 1662 // # destination lines given mixer ID. 1663 // ---------------------------------------------------------------------------- 1664 1665 UINT AudioMixerManager::DestinationLines(UINT mixId) const 1666 { 1667 MIXERCAPS caps; 1668 if (!GetCapabilities(mixId, caps)) 1669 { 1670 return 0; 1671 } 1672 return (caps.cDestinations); 1673 } 1674 // ---------------------------------------------------------------------------- 1675 // DestinationLines 1676 // 1677 // # source lines given mixer ID and destination ID. 1678 // ---------------------------------------------------------------------------- 1679 1680 UINT AudioMixerManager::SourceLines(UINT mixId, DWORD destId) const 1681 { 1682 MIXERLINE dline; 1683 if (!GetDestinationLineInfo(mixId, destId, dline)) 1684 { 1685 return 0; 1686 } 1687 return (dline.cConnections); 1688 } 1689 1690 // ---------------------------------------------------------------------------- 1691 // GetCapabilities 1692 // 1693 // Queries a specified mixer device to determine its capabilities. 1694 // ---------------------------------------------------------------------------- 1695 1696 bool AudioMixerManager::GetCapabilities(UINT mixId, MIXERCAPS& caps, bool trace) const 1697 { 1698 MMRESULT res; 1699 MIXERCAPS mcaps; 1700 1701 res = mixerGetDevCaps(mixId, &mcaps, sizeof(MIXERCAPS)); 1702 if (res != MMSYSERR_NOERROR) 1703 { 1704 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetDevCaps() failed (err=%d)", res); 1705 return false; 1706 } 1707 1708 memcpy(&caps, &mcaps, sizeof(MIXERCAPS)); 1709 1710 if (trace) 1711 { 1712 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 1713 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Mixer ID %u:", mixId); 1714 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", caps.wMid); 1715 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u", caps.wPid); 1716 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "version of driver : %u", caps.vDriverVersion); 1717 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", WideToUTF8(caps.szPname)); 1718 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "misc. support bits : %u", caps.fdwSupport); 1719 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "count of destinations: %u (+)", caps.cDestinations); 1720 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "==============================================================="); 1721 } 1722 1723 if (caps.cDestinations == 0) 1724 { 1725 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "invalid number of mixer destinations"); 1726 return false; 1727 } 1728 1729 return true; 1730 } 1731 1732 // ---------------------------------------------------------------------------- 1733 // GetDestinationLineInfo 1734 // ---------------------------------------------------------------------------- 1735 1736 bool AudioMixerManager::GetDestinationLineInfo(UINT mixId, DWORD destId, MIXERLINE& line, bool trace) const 1737 { 1738 MMRESULT res; 1739 MIXERLINE mline; 1740 1741 mline.cbStruct = sizeof(MIXERLINE); 1742 mline.dwDestination = destId; // max destination index is cDestinations-1 1743 mline.dwSource = 0; // not set for MIXER_GETLINEINFOF_DESTINATION 1744 1745 // Retrieve information about the specified destination line of a mixer device. 1746 // Note that we use the mixer ID here and not a handle to an opened mixer. 1747 // It is not required to open the mixer for enumeration purposes only. 1748 // 1749 res = mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(mixId), &mline, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_DESTINATION); 1750 if (res != MMSYSERR_NOERROR) 1751 { 1752 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineInfo(MIXER_GETLINEINFOF_DESTINATION) failed (err=%d)", res); 1753 return false; 1754 } 1755 1756 memcpy(&line, &mline, sizeof(MIXERLINE)); 1757 1758 if (trace) 1759 { 1760 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "> Destination Line ID %u:", destId); 1761 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); 1762 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "destination line index : %u", mline.dwDestination); 1763 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwLineID : %lu (unique)", mline.dwLineID); 1764 TraceStatusAndSupportFlags(mline.fdwLine); 1765 TraceComponentType(mline.dwComponentType); 1766 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "count of channels : %u", mline.cChannels); 1767 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# audio source lines : %u (+)", mline.cConnections); // valid only for destinations 1768 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# controls : %u (*)", mline.cControls); // can be zero 1769 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "short name : %s", WideToUTF8(mline.szShortName)); 1770 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(mline.szName)); 1771 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); 1772 TraceTargetType(mline.Target.dwType); 1773 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "target device ID : %lu", mline.Target.dwDeviceID); 1774 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", mline.Target.wMid); 1775 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u", mline.Target.wPid); 1776 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "driver version : %u", mline.Target.vDriverVersion); 1777 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", WideToUTF8(mline.Target.szPname)); 1778 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "---------------------------------------------------------------"); 1779 } 1780 1781 return true; 1782 } 1783 1784 // ---------------------------------------------------------------------------- 1785 // GetSourceLineInfo 1786 // ---------------------------------------------------------------------------- 1787 1788 bool AudioMixerManager::GetSourceLineInfo(UINT mixId, DWORD destId, DWORD srcId, MIXERLINE& line, bool trace) const 1789 { 1790 MMRESULT res; 1791 MIXERLINE mline; 1792 1793 mline.cbStruct = sizeof(MIXERLINE); 1794 mline.dwDestination = destId; // we want the source info for this destination 1795 mline.dwSource = srcId; // source index (enumerate over these) 1796 1797 // Retrieve information about the specified source line of a mixer device. 1798 // Note that we use the mixer ID here and not a handle to an opened mixer. 1799 // It is not required to open the mixer for enumeration purposes only. 1800 // 1801 res = mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(mixId), &mline, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_SOURCE); 1802 if (res != MMSYSERR_NOERROR) 1803 { 1804 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineInfo(MIXER_GETLINEINFOF_SOURCE) failed (err=%d)", res); 1805 return false; 1806 } 1807 1808 memcpy(&line, &mline, sizeof(MIXERLINE)); 1809 1810 if (trace) 1811 { 1812 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " >> Source Line ID %u:", srcId); 1813 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "destination line index : %u", mline.dwDestination); 1814 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwSource : %u", mline.dwSource); 1815 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwLineID : %lu (unique)", mline.dwLineID); 1816 TraceStatusAndSupportFlags(mline.fdwLine); 1817 TraceComponentType(mline.dwComponentType); 1818 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# controls : %u (*)", mline.cControls); 1819 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(mline.szName)); 1820 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); 1821 TraceTargetType(mline.Target.dwType); 1822 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "---------------------------------------------------------------"); 1823 } 1824 1825 return true; 1826 } 1827 1828 // ---------------------------------------------------------------------------- 1829 // GetAllLineControls 1830 // ---------------------------------------------------------------------------- 1831 1832 bool AudioMixerManager::GetAllLineControls(UINT mixId, const MIXERLINE& line, MIXERCONTROL* controlArray, bool trace) const 1833 { 1834 // Ensure that we don't try to aquire information if there are no controls for this line 1835 // 1836 if (line.cControls == 0) 1837 return false; 1838 1839 MMRESULT res; 1840 MIXERLINECONTROLS mlineControls; // contains information about the controls of an audio line 1841 1842 mlineControls.dwLineID = line.dwLineID; // unique audio line identifier 1843 mlineControls.cControls = line.cControls; // number of controls associated with the line 1844 mlineControls.pamxctrl = controlArray; // points to the first MIXERCONTROL structure to be filled 1845 mlineControls.cbStruct = sizeof(MIXERLINECONTROLS); 1846 mlineControls.cbmxctrl = sizeof(MIXERCONTROL); 1847 1848 // Get information on ALL controls associated with the specified audio line 1849 // 1850 res = mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(mixId), &mlineControls, MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ALL); 1851 if (res != MMSYSERR_NOERROR) 1852 { 1853 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineControls(MIXER_GETLINECONTROLSF_ALL) failed (err=%d)", res); 1854 return false; 1855 } 1856 1857 if (trace) 1858 { 1859 for (UINT c = 0; c < line.cControls; c++) 1860 { 1861 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " >> Control ID %u:", c); 1862 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwControlID : %u (unique)", controlArray[c].dwControlID); 1863 TraceControlType(controlArray[c].dwControlType); 1864 TraceControlStatusAndSupportFlags(controlArray[c].fdwControl); 1865 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cMultipleItems : %u", controlArray[c].cMultipleItems); 1866 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "short name : %s", WideToUTF8(controlArray[c].szShortName)); 1867 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(controlArray[c].szName)); 1868 if ((controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_SIGNED) 1869 { 1870 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "min signed value : %d", controlArray[c].Bounds.lMinimum); 1871 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "max signed value : %d", controlArray[c].Bounds.lMaximum); 1872 } 1873 else if ((controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_UNSIGNED || 1874 (controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_BOOLEAN) 1875 { 1876 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "min unsigned value : %u", controlArray[c].Bounds.dwMinimum); 1877 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "max unsigned value : %u", controlArray[c].Bounds.dwMaximum); 1878 } 1879 if (controlArray[c].dwControlType != MIXERCONTROL_CONTROLTYPE_CUSTOM) 1880 { 1881 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cSteps : %u", controlArray[c].Metrics.cSteps); 1882 } 1883 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "..............................................................."); 1884 GetControlDetails(mixId, controlArray[c], true); 1885 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "..............................................................."); 1886 1887 } 1888 } 1889 1890 return true; 1891 } 1892 1893 // ---------------------------------------------------------------------------- 1894 // GetLineControls 1895 // ---------------------------------------------------------------------------- 1896 1897 bool AudioMixerManager::GetLineControl(UINT mixId, DWORD dwControlID, MIXERCONTROL& control) const 1898 { 1899 MMRESULT res; 1900 MIXERLINECONTROLS mlineControl; 1901 1902 mlineControl.dwControlID = dwControlID; 1903 mlineControl.cControls = 1; 1904 mlineControl.pamxctrl = &control; 1905 mlineControl.cbStruct = sizeof(MIXERLINECONTROLS); 1906 mlineControl.cbmxctrl = sizeof(MIXERCONTROL); 1907 1908 // Get information on one controls associated with the specified conrol identifier 1909 // 1910 res = mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(mixId), &mlineControl, MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYID); 1911 if (res != MMSYSERR_NOERROR) 1912 { 1913 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineControls(MIXER_GETLINECONTROLSF_ONEBYID) failed (err=%d)", res); 1914 return false; 1915 } 1916 1917 return true; 1918 } 1919 1920 // ---------------------------------------------------------------------------- 1921 // GetControlDetails 1922 // ---------------------------------------------------------------------------- 1923 1924 bool AudioMixerManager::GetControlDetails(UINT mixId, MIXERCONTROL& controlArray, bool trace) const 1925 { 1926 assert(controlArray.cMultipleItems <= MAX_NUMBER_OF_MULTIPLE_ITEMS); 1927 1928 MMRESULT res; 1929 MIXERCONTROLDETAILS controlDetails; 1930 1931 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned[MAX_NUMBER_OF_MULTIPLE_ITEMS]; 1932 MIXERCONTROLDETAILS_SIGNED valueSigned[MAX_NUMBER_OF_MULTIPLE_ITEMS]; 1933 MIXERCONTROLDETAILS_BOOLEAN valueBoolean[MAX_NUMBER_OF_MULTIPLE_ITEMS]; 1934 1935 enum ControlType 1936 { 1937 CT_UNITS_UNSIGNED, 1938 CT_UNITS_SIGNED, 1939 CT_UNITS_BOOLEAN 1940 }; 1941 1942 ControlType ctype(CT_UNITS_UNSIGNED); 1943 1944 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 1945 controlDetails.dwControlID = controlArray.dwControlID; // control identifier 1946 controlDetails.cChannels = 1; // we need to set values as if they were uniform 1947 controlDetails.cMultipleItems = controlArray.cMultipleItems; // only nonzero for CONTROLF_MULTIPLE controls 1948 // can e.g. happen for CONTROLTYPE_MUX 1949 if (controlDetails.cMultipleItems > MAX_NUMBER_OF_MULTIPLE_ITEMS) 1950 { 1951 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "cMultipleItems > %d", MAX_NUMBER_OF_MULTIPLE_ITEMS); 1952 controlDetails.cMultipleItems = MAX_NUMBER_OF_MULTIPLE_ITEMS; 1953 } 1954 1955 if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_SIGNED) 1956 { 1957 ctype = CT_UNITS_SIGNED; 1958 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED); 1959 controlDetails.paDetails = &valueSigned[0]; 1960 } 1961 else if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_UNSIGNED) 1962 { 1963 ctype = CT_UNITS_UNSIGNED; 1964 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 1965 controlDetails.paDetails = &valueUnsigned[0]; 1966 } 1967 else if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_BOOLEAN) 1968 { 1969 ctype = CT_UNITS_BOOLEAN; 1970 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 1971 controlDetails.paDetails = &valueBoolean[0]; 1972 } 1973 1974 // Retrieve a control's value 1975 // 1976 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 1977 if (res != MMSYSERR_NOERROR) 1978 { 1979 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 1980 return false; 1981 } 1982 1983 if (trace) 1984 { 1985 UINT nItems(1); 1986 nItems = (controlDetails.cMultipleItems > 0 ? controlDetails.cMultipleItems : 1); 1987 for (UINT i = 0; i < nItems; i++) 1988 { 1989 if (ctype == CT_UNITS_SIGNED) 1990 { 1991 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "signed value : %d", valueSigned[i].lValue); 1992 } 1993 else if (ctype == CT_UNITS_UNSIGNED) 1994 { 1995 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unsigned value : %u", valueUnsigned[i].dwValue); 1996 } 1997 else if (ctype == CT_UNITS_BOOLEAN) 1998 { 1999 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "boolean value : %u", valueBoolean[i].fValue); 2000 } 2001 } 2002 } 2003 2004 return true; 2005 } 2006 2007 // ---------------------------------------------------------------------------- 2008 // GetUnsignedControlValue 2009 // ---------------------------------------------------------------------------- 2010 2011 bool AudioMixerManager::GetUnsignedControlValue(UINT mixId, DWORD dwControlID, DWORD& dwValue) const 2012 { 2013 MMRESULT res; 2014 MIXERCONTROLDETAILS controlDetails; 2015 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned; 2016 2017 controlDetails.dwControlID = dwControlID; 2018 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 2019 controlDetails.cChannels = 1; 2020 controlDetails.cMultipleItems = 0; 2021 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 2022 controlDetails.paDetails = &valueUnsigned; 2023 2024 // Retrieve the unsigned value 2025 // 2026 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 2027 if (res != MMSYSERR_NOERROR) 2028 { 2029 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 2030 return false; 2031 } 2032 2033 // Deliver the retrieved value 2034 // 2035 dwValue = valueUnsigned.dwValue; 2036 2037 return true; 2038 } 2039 2040 // ---------------------------------------------------------------------------- 2041 // SetUnsignedControlValue 2042 // ---------------------------------------------------------------------------- 2043 2044 bool AudioMixerManager::SetUnsignedControlValue(UINT mixId, DWORD dwControlID, DWORD dwValue) const 2045 { 2046 WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "AudioMixerManager::SetUnsignedControlValue(mixId=%u, dwControlID=%d, dwValue=%d)", mixId, dwControlID, dwValue); 2047 2048 MMRESULT res; 2049 MIXERCONTROLDETAILS controlDetails; 2050 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned; 2051 2052 controlDetails.dwControlID = dwControlID; 2053 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 2054 controlDetails.cChannels = 1; 2055 controlDetails.cMultipleItems = 0; 2056 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 2057 controlDetails.paDetails = &valueUnsigned; 2058 2059 valueUnsigned.dwValue = dwValue; 2060 2061 // Set the unsigned value 2062 // 2063 res = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 2064 if (res != MMSYSERR_NOERROR) 2065 { 2066 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerSetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 2067 return false; 2068 } 2069 2070 return true; 2071 } 2072 2073 // ---------------------------------------------------------------------------- 2074 // SetBooleanControlValue 2075 // ---------------------------------------------------------------------------- 2076 2077 bool AudioMixerManager::SetBooleanControlValue(UINT mixId, DWORD dwControlID, bool value) const 2078 { 2079 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetBooleanControlValue(mixId=%u, dwControlID=%d, value=%d)", mixId, dwControlID, value); 2080 2081 MMRESULT res; 2082 MIXERCONTROLDETAILS controlDetails; 2083 MIXERCONTROLDETAILS_BOOLEAN valueBoolean; 2084 2085 controlDetails.dwControlID = dwControlID; 2086 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 2087 controlDetails.cChannels = 1; 2088 controlDetails.cMultipleItems = 0; 2089 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 2090 controlDetails.paDetails = &valueBoolean; 2091 2092 if (value == true) 2093 valueBoolean.fValue = TRUE; 2094 else 2095 valueBoolean.fValue = FALSE; 2096 2097 // Set the boolean value 2098 // 2099 res = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 2100 if (res != MMSYSERR_NOERROR) 2101 { 2102 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerSetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 2103 return false; 2104 } 2105 2106 return true; 2107 } 2108 2109 // ---------------------------------------------------------------------------- 2110 // GetBooleanControlValue 2111 // ---------------------------------------------------------------------------- 2112 2113 bool AudioMixerManager::GetBooleanControlValue(UINT mixId, DWORD dwControlID, bool& value) const 2114 { 2115 MMRESULT res; 2116 MIXERCONTROLDETAILS controlDetails; 2117 MIXERCONTROLDETAILS_BOOLEAN valueBoolean; 2118 2119 controlDetails.dwControlID = dwControlID; 2120 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 2121 controlDetails.cChannels = 1; 2122 controlDetails.cMultipleItems = 0; 2123 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 2124 controlDetails.paDetails = &valueBoolean; 2125 2126 // Retrieve the boolean value 2127 // 2128 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 2129 if (res != MMSYSERR_NOERROR) 2130 { 2131 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 2132 return false; 2133 } 2134 2135 // Deliver the retrieved value 2136 // 2137 if (valueBoolean.fValue == 0) 2138 value = false; 2139 else 2140 value = true; 2141 2142 return true; 2143 } 2144 2145 // ---------------------------------------------------------------------------- 2146 // GetSelectedMuxSource 2147 // ---------------------------------------------------------------------------- 2148 2149 bool AudioMixerManager::GetSelectedMuxSource(UINT mixId, DWORD dwControlID, DWORD cMultipleItems, UINT& index) const 2150 { 2151 assert(cMultipleItems <= MAX_NUMBER_OF_MULTIPLE_ITEMS); 2152 2153 MMRESULT res; 2154 MIXERCONTROLDETAILS controlDetails; 2155 MIXERCONTROLDETAILS_BOOLEAN valueBoolean[MAX_NUMBER_OF_MULTIPLE_ITEMS]; 2156 memset(&valueBoolean, 0, sizeof(valueBoolean)); 2157 2158 controlDetails.dwControlID = dwControlID; 2159 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 2160 controlDetails.cChannels = 1; 2161 controlDetails.cMultipleItems = cMultipleItems; 2162 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 2163 controlDetails.paDetails = &valueBoolean; 2164 2165 // Retrieve the boolean values 2166 // 2167 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE); 2168 if (res != MMSYSERR_NOERROR) 2169 { 2170 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res); 2171 return false; 2172 } 2173 2174 // Map the current MUX setting to an index corresponding to a source index. 2175 // e.g. with cMultipleItems = 3, 2176 // valueBoolean[] = {1,0,0} => index = 2 2177 // valueBoolean[] = {0,1,0} => index = 1 2178 // valueBoolean[] = {0,0,1} => index = 0 2179 // 2180 // If there is no "1" in the array, we assume index should be 0. 2181 index = 0; 2182 for (DWORD i = 0; i < cMultipleItems; i++) 2183 { 2184 if (valueBoolean[i].fValue > 0) 2185 { 2186 index = (cMultipleItems - 1) - i; 2187 break; 2188 } 2189 } 2190 2191 return true; 2192 } 2193 2194 // ---------------------------------------------------------------------------- 2195 // TraceStatusAndSupportFlags 2196 // ---------------------------------------------------------------------------- 2197 2198 void AudioMixerManager::TraceStatusAndSupportFlags(DWORD fdwLine) const 2199 { 2200 TCHAR buf[128]; 2201 2202 StringCchPrintf(buf, 128, TEXT("status & support flags : 0x%x "), fdwLine); 2203 2204 switch (fdwLine) 2205 { 2206 case MIXERLINE_LINEF_ACTIVE: 2207 StringCchCat(buf, 128, TEXT("(ACTIVE DESTINATION)")); 2208 break; 2209 case MIXERLINE_LINEF_DISCONNECTED: 2210 StringCchCat(buf, 128, TEXT("(DISCONNECTED)")); 2211 break; 2212 case MIXERLINE_LINEF_SOURCE: 2213 StringCchCat(buf, 128, TEXT("(INACTIVE SOURCE)")); 2214 break; 2215 case MIXERLINE_LINEF_SOURCE | MIXERLINE_LINEF_ACTIVE: 2216 StringCchCat(buf, 128, TEXT("(ACTIVE SOURCE)")); 2217 break; 2218 default: 2219 StringCchCat(buf, 128, TEXT("(INVALID)")); 2220 break; 2221 } 2222 2223 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2224 } 2225 2226 // ---------------------------------------------------------------------------- 2227 // TraceComponentType 2228 // ---------------------------------------------------------------------------- 2229 2230 void AudioMixerManager::TraceComponentType(DWORD dwComponentType) const 2231 { 2232 TCHAR buf[128]; 2233 2234 StringCchPrintf(buf, 128, TEXT("component type : 0x%x "), dwComponentType); 2235 2236 switch (dwComponentType) 2237 { 2238 // Destination 2239 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: 2240 StringCchCat(buf, 128, TEXT("(DST_UNDEFINED)")); 2241 break; 2242 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: 2243 StringCchCat(buf, 128, TEXT("(DST_DIGITAL)")); 2244 break; 2245 case MIXERLINE_COMPONENTTYPE_DST_LINE: 2246 StringCchCat(buf, 128, TEXT("(DST_LINE)")); 2247 break; 2248 case MIXERLINE_COMPONENTTYPE_DST_MONITOR: 2249 StringCchCat(buf, 128, TEXT("(DST_MONITOR)")); 2250 break; 2251 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: 2252 StringCchCat(buf, 128, TEXT("(DST_SPEAKERS)")); 2253 break; 2254 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: 2255 StringCchCat(buf, 128, TEXT("(DST_HEADPHONES)")); 2256 break; 2257 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: 2258 StringCchCat(buf, 128, TEXT("(DST_TELEPHONE)")); 2259 break; 2260 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: 2261 StringCchCat(buf, 128, TEXT("(DST_WAVEIN)")); 2262 break; 2263 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: 2264 StringCchCat(buf, 128, TEXT("(DST_VOICEIN)")); 2265 break; 2266 // Source 2267 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: 2268 StringCchCat(buf, 128, TEXT("(SRC_UNDEFINED)")); 2269 break; 2270 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: 2271 StringCchCat(buf, 128, TEXT("(SRC_DIGITAL)")); 2272 break; 2273 case MIXERLINE_COMPONENTTYPE_SRC_LINE: 2274 StringCchCat(buf, 128, TEXT("(SRC_LINE)")); 2275 break; 2276 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: 2277 StringCchCat(buf, 128, TEXT("(SRC_MICROPHONE)")); 2278 break; 2279 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: 2280 StringCchCat(buf, 128, TEXT("(SRC_SYNTHESIZER)")); 2281 break; 2282 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: 2283 StringCchCat(buf, 128, TEXT("(SRC_COMPACTDISC)")); 2284 break; 2285 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: 2286 StringCchCat(buf, 128, TEXT("(SRC_TELEPHONE)")); 2287 break; 2288 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: 2289 StringCchCat(buf, 128, TEXT("(SRC_PCSPEAKER)")); 2290 break; 2291 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: 2292 StringCchCat(buf, 128, TEXT("(SRC_WAVEOUT)")); 2293 break; 2294 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: 2295 StringCchCat(buf, 128, TEXT("(SRC_AUXILIARY)")); 2296 break; 2297 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: 2298 StringCchCat(buf, 128, TEXT("(SRC_ANALOG)")); 2299 break; 2300 default: 2301 StringCchCat(buf, 128, TEXT("(INVALID)")); 2302 break; 2303 } 2304 2305 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2306 } 2307 2308 // ---------------------------------------------------------------------------- 2309 // TraceTargetType 2310 // ---------------------------------------------------------------------------- 2311 2312 void AudioMixerManager::TraceTargetType(DWORD dwType) const 2313 { 2314 TCHAR buf[128]; 2315 2316 StringCchPrintf(buf, 128, TEXT("media device type : 0x%x "), dwType); 2317 2318 switch (dwType) 2319 { 2320 case MIXERLINE_TARGETTYPE_UNDEFINED: 2321 StringCchCat(buf, 128, TEXT("(UNDEFINED)")); 2322 break; 2323 case MIXERLINE_TARGETTYPE_WAVEOUT: 2324 StringCchCat(buf, 128, TEXT("(WAVEOUT)")); 2325 break; 2326 case MIXERLINE_TARGETTYPE_WAVEIN: 2327 StringCchCat(buf, 128, TEXT("(WAVEIN)")); 2328 break; 2329 case MIXERLINE_TARGETTYPE_MIDIOUT: 2330 StringCchCat(buf, 128, TEXT("(MIDIOUT)")); 2331 break; 2332 case MIXERLINE_TARGETTYPE_MIDIIN: 2333 StringCchCat(buf, 128, TEXT("(MIDIIN)")); 2334 break; 2335 default: 2336 StringCchCat(buf, 128, TEXT("(INVALID)")); 2337 break; 2338 } 2339 2340 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2341 } 2342 2343 // ---------------------------------------------------------------------------- 2344 // TraceControlType 2345 // ---------------------------------------------------------------------------- 2346 2347 void AudioMixerManager::TraceControlType(DWORD dwControlType) const 2348 { 2349 TCHAR buf[128]; 2350 2351 // Class type classification 2352 // 2353 StringCchPrintf(buf, 128, TEXT("class type : 0x%x "), dwControlType); 2354 2355 switch (dwControlType & MIXERCONTROL_CT_CLASS_MASK) 2356 { 2357 case MIXERCONTROL_CT_CLASS_CUSTOM: 2358 StringCchCat(buf, 128, TEXT("(CT_CLASS_CUSTOM)")); 2359 break; 2360 case MIXERCONTROL_CT_CLASS_METER: 2361 StringCchCat(buf, 128, TEXT("(CT_CLASS_METER)")); 2362 break; 2363 case MIXERCONTROL_CT_CLASS_SWITCH: 2364 StringCchCat(buf, 128, TEXT("(CT_CLASS_SWITCH)")); 2365 break; 2366 case MIXERCONTROL_CT_CLASS_NUMBER: 2367 StringCchCat(buf, 128, TEXT("(CT_CLASS_NUMBER)")); 2368 break; 2369 case MIXERCONTROL_CT_CLASS_SLIDER: 2370 StringCchCat(buf, 128, TEXT("(CT_CLASS_SLIDER)")); 2371 break; 2372 case MIXERCONTROL_CT_CLASS_FADER: 2373 StringCchCat(buf, 128, TEXT("(CT_CLASS_FADER)")); 2374 break; 2375 case MIXERCONTROL_CT_CLASS_TIME: 2376 StringCchCat(buf, 128, TEXT("(CT_CLASS_TIME)")); 2377 break; 2378 case MIXERCONTROL_CT_CLASS_LIST: 2379 StringCchCat(buf, 128, TEXT("(CT_CLASS_LIST)")); 2380 break; 2381 default: 2382 StringCchCat(buf, 128, TEXT("(INVALID)")); 2383 break; 2384 } 2385 2386 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2387 2388 // Control type (for each class) 2389 // 2390 StringCchPrintf(buf, 128, TEXT("control type : 0x%x "), dwControlType); 2391 2392 switch (dwControlType) 2393 { 2394 case MIXERCONTROL_CONTROLTYPE_CUSTOM: 2395 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_CUSTOM)")); 2396 break; 2397 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER: 2398 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BOOLEANMETER)")); 2399 break; 2400 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER: 2401 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SIGNEDMETER)")); 2402 break; 2403 case MIXERCONTROL_CONTROLTYPE_PEAKMETER: 2404 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PEAKMETER)")); 2405 break; 2406 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER: 2407 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_UNSIGNEDMETER)")); 2408 break; 2409 case MIXERCONTROL_CONTROLTYPE_BOOLEAN: 2410 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BOOLEAN)")); 2411 break; 2412 case MIXERCONTROL_CONTROLTYPE_ONOFF: 2413 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_ONOFF)")); 2414 break; 2415 case MIXERCONTROL_CONTROLTYPE_MUTE: 2416 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MUTE)")); 2417 break; 2418 case MIXERCONTROL_CONTROLTYPE_MONO: 2419 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MONO)")); 2420 break; 2421 case MIXERCONTROL_CONTROLTYPE_LOUDNESS: 2422 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_LOUDNESS)")); 2423 break; 2424 case MIXERCONTROL_CONTROLTYPE_STEREOENH: 2425 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_STEREOENH)")); 2426 break; 2427 case MIXERCONTROL_CONTROLTYPE_BASS_BOOST: 2428 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BASS_BOOST)")); 2429 break; 2430 case MIXERCONTROL_CONTROLTYPE_BUTTON: 2431 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BUTTON)")); 2432 break; 2433 case MIXERCONTROL_CONTROLTYPE_DECIBELS: 2434 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_DECIBELS)")); 2435 break; 2436 case MIXERCONTROL_CONTROLTYPE_SIGNED: 2437 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SIGNED)")); 2438 break; 2439 case MIXERCONTROL_CONTROLTYPE_UNSIGNED: 2440 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_UNSIGNED)")); 2441 break; 2442 case MIXERCONTROL_CONTROLTYPE_PERCENT: 2443 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PERCENT)")); 2444 break; 2445 case MIXERCONTROL_CONTROLTYPE_SLIDER: 2446 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SLIDER)")); 2447 break; 2448 case MIXERCONTROL_CONTROLTYPE_PAN: 2449 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PAN)")); 2450 break; 2451 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN: 2452 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_QSOUNDPAN)")); 2453 break; 2454 case MIXERCONTROL_CONTROLTYPE_FADER: 2455 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_FADER)")); 2456 break; 2457 case MIXERCONTROL_CONTROLTYPE_VOLUME: 2458 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_VOLUME)")); 2459 break; 2460 case MIXERCONTROL_CONTROLTYPE_BASS: 2461 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BASS)")); 2462 break; 2463 case MIXERCONTROL_CONTROLTYPE_TREBLE: 2464 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_TREBLE)")); 2465 break; 2466 case MIXERCONTROL_CONTROLTYPE_EQUALIZER: 2467 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_EQUALIZER)")); 2468 break; 2469 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT: 2470 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SINGLESELECT)")); 2471 break; 2472 case MIXERCONTROL_CONTROLTYPE_MUX: 2473 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MUX)")); 2474 break; 2475 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT: 2476 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MULTIPLESELECT)")); 2477 break; 2478 case MIXERCONTROL_CONTROLTYPE_MIXER: 2479 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MIXER)")); 2480 break; 2481 case MIXERCONTROL_CONTROLTYPE_MICROTIME: 2482 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MICROTIME)")); 2483 break; 2484 case MIXERCONTROL_CONTROLTYPE_MILLITIME: 2485 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MILLITIME)")); 2486 break; 2487 default: 2488 StringCchCat(buf, 128, TEXT("(INVALID)")); 2489 break; 2490 } 2491 2492 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2493 } 2494 2495 // ---------------------------------------------------------------------------- 2496 // TraceControlStatusAndSupportFlags 2497 // 2498 // fdwControl 2499 // 2500 // Status and support flags for the audio line control. The following values 2501 // are defined: 2502 // 2503 // MIXERCONTROL_CONTROLF_DISABLED 2504 // 2505 // The control is disabled, perhaps due to other settings for the mixer hardware, 2506 // and cannot be used. An application can read current settings from a 2507 // disabled control, but it cannot apply settings. 2508 // 2509 // MIXERCONTROL_CONTROLF_MULTIPLE 2510 // 2511 // The control has two or more settings per channel. An equalizer, for example, 2512 // requires this flag because each frequency band can be set to a different value. 2513 // An equalizer that affects both channels of a stereo line in a uniform fashion 2514 // will also specify the MIXERCONTROL_CONTROLF_UNIFORM flag. 2515 // 2516 // MIXERCONTROL_CONTROLF_UNIFORM 2517 // 2518 // The control acts on all channels of a multichannel line in a uniform fashion. 2519 // For example, a control that mutes both channels of a stereo line would set 2520 // this flag. Most MIXERCONTROL_CONTROLTYPE_MUX and 2521 // MIXERCONTROL_CONTROLTYPE_MIXER controls also specify the 2522 // MIXERCONTROL_CONTROLF_UNIFORM flag. 2523 // ---------------------------------------------------------------------------- 2524 2525 void AudioMixerManager::TraceControlStatusAndSupportFlags(DWORD fdwControl) const 2526 { 2527 TCHAR buf[128]; 2528 2529 StringCchPrintf(buf, 128, TEXT("control support flags : 0x%x "), fdwControl); 2530 2531 if (fdwControl & MIXERCONTROL_CONTROLF_DISABLED) 2532 { 2533 // The control is disabled, perhaps due to other settings for the mixer hardware, 2534 // and cannot be used. An application can read current settings from a disabled 2535 // control, but it cannot apply settings. 2536 StringCchCat(buf, 128, TEXT("(CONTROLF_DISABLED)")); 2537 } 2538 2539 if (fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE) 2540 { 2541 // The control has two or more settings per channel. An equalizer, for example, 2542 // requires this flag because each frequency band can be set to a different 2543 // value. An equalizer that affects both channels of a stereo line in a 2544 // uniform fashion will also specify the MIXERCONTROL_CONTROLF_UNIFORM flag. 2545 StringCchCat(buf, 128, TEXT("(CONTROLF_MULTIPLE)")); 2546 } 2547 2548 if (fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) 2549 { 2550 // The control acts on all channels of a multichannel line in a uniform 2551 // fashion. For example, a control that mutes both channels of a stereo 2552 // line would set this flag. Most MIXERCONTROL_CONTROLTYPE_MUX and 2553 // MIXERCONTROL_CONTROLTYPE_MIXER controls also specify the 2554 // MIXERCONTROL_CONTROLF_UNIFORM flag. 2555 StringCchCat(buf, 128, TEXT("(CONTROLF_UNIFORM)")); 2556 } 2557 2558 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2559 } 2560 2561 // ---------------------------------------------------------------------------- 2562 // ClearSpeakerState I (II) 2563 // ---------------------------------------------------------------------------- 2564 2565 void AudioMixerManager::ClearSpeakerState(UINT idx) 2566 { 2567 _speakerState[idx].dwLineID = 0L; 2568 _speakerState[idx].dwVolumeControlID = 0L; 2569 _speakerState[idx].dwMuteControlID = 0L; 2570 _speakerState[idx].speakerIsValid = false; 2571 _speakerState[idx].muteControlIsValid = false; 2572 _speakerState[idx].volumeControlIsValid = false; 2573 } 2574 2575 // ---------------------------------------------------------------------------- 2576 // ClearSpeakerState II (II) 2577 // ---------------------------------------------------------------------------- 2578 2579 void AudioMixerManager::ClearSpeakerState() 2580 { 2581 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++) 2582 { 2583 ClearSpeakerState(i); 2584 } 2585 } 2586 2587 // ---------------------------------------------------------------------------- 2588 // SpeakerIsValid 2589 // ---------------------------------------------------------------------------- 2590 2591 bool AudioMixerManager::SpeakerIsValid(UINT idx) const 2592 { 2593 return (_speakerState[idx].speakerIsValid); 2594 } 2595 2596 // ---------------------------------------------------------------------------- 2597 // ValidSpeakers 2598 // 2599 // Counts number of valid speaker destinations for all mixer devices. 2600 // ---------------------------------------------------------------------------- 2601 2602 UINT AudioMixerManager::ValidSpeakers() const 2603 { 2604 UINT nSpeakers(0); 2605 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++) 2606 { 2607 if (SpeakerIsValid(i)) 2608 nSpeakers++; 2609 } 2610 return nSpeakers; 2611 } 2612 2613 // ---------------------------------------------------------------------------- 2614 // ClearMicrophoneState I (II) 2615 // ---------------------------------------------------------------------------- 2616 2617 void AudioMixerManager::ClearMicrophoneState(UINT idx) 2618 { 2619 _microphoneState[idx].dwLineID = 0L; 2620 _microphoneState[idx].dwVolumeControlID = 0L; 2621 _microphoneState[idx].dwMuteControlID = 0L; 2622 _microphoneState[idx].dwOnOffControlID = 0L; 2623 _microphoneState[idx].microphoneIsValid = false; 2624 _microphoneState[idx].muteControlIsValid = false; 2625 _microphoneState[idx].volumeControlIsValid = false; 2626 _microphoneState[idx].onOffControlIsValid = false; 2627 } 2628 2629 // ---------------------------------------------------------------------------- 2630 // ClearMicrophoneState II (II) 2631 // ---------------------------------------------------------------------------- 2632 2633 void AudioMixerManager::ClearMicrophoneState() 2634 { 2635 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++) 2636 { 2637 ClearMicrophoneState(i); 2638 } 2639 } 2640 2641 // ---------------------------------------------------------------------------- 2642 // MicrophoneIsValid 2643 // ---------------------------------------------------------------------------- 2644 2645 bool AudioMixerManager::MicrophoneIsValid(UINT idx) const 2646 { 2647 return (_microphoneState[idx].microphoneIsValid); 2648 2649 } 2650 2651 // ---------------------------------------------------------------------------- 2652 // ValidMicrophones 2653 // 2654 // Counts number of valid speaker destinations for all mixer devices. 2655 // To be valid, a speaker destination line must exist. 2656 // ---------------------------------------------------------------------------- 2657 2658 UINT AudioMixerManager::ValidMicrophones() const 2659 { 2660 UINT nMicrophones(0); 2661 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++) 2662 { 2663 if (MicrophoneIsValid(i)) 2664 nMicrophones++; 2665 } 2666 return nMicrophones; 2667 } 2668 2669 // ---------------------------------------------------------------------------- 2670 // TraceWaveInError 2671 // ---------------------------------------------------------------------------- 2672 2673 void AudioMixerManager::TraceWaveInError(MMRESULT error) const 2674 { 2675 TCHAR buf[MAXERRORLENGTH]; 2676 TCHAR msg[MAXERRORLENGTH]; 2677 2678 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: ")); 2679 waveInGetErrorText(error, msg, MAXERRORLENGTH); 2680 StringCchCat(buf, MAXERRORLENGTH, msg); 2681 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2682 } 2683 2684 // ---------------------------------------------------------------------------- 2685 // TraceWaveOutError 2686 // ---------------------------------------------------------------------------- 2687 2688 void AudioMixerManager::TraceWaveOutError(MMRESULT error) const 2689 { 2690 TCHAR buf[MAXERRORLENGTH]; 2691 TCHAR msg[MAXERRORLENGTH]; 2692 2693 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: ")); 2694 waveOutGetErrorText(error, msg, MAXERRORLENGTH); 2695 StringCchCat(buf, MAXERRORLENGTH, msg); 2696 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf)); 2697 } 2698 2699 // ---------------------------------------------------------------------------- 2700 // WideToUTF8 2701 // ---------------------------------------------------------------------------- 2702 2703 char* AudioMixerManager::WideToUTF8(const TCHAR* src) const { 2704 #ifdef UNICODE 2705 const size_t kStrLen = sizeof(_str); 2706 memset(_str, 0, kStrLen); 2707 // Get required size (in bytes) to be able to complete the conversion. 2708 int required_size = WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, 0, 0, 0); 2709 if (required_size <= kStrLen) 2710 { 2711 // Process the entire input string, including the terminating null char. 2712 if (WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, kStrLen, 0, 0) == 0) 2713 memset(_str, 0, kStrLen); 2714 } 2715 return _str; 2716 #else 2717 return const_cast<char*>(src); 2718 #endif 2719 } 2720 2721 } // namespace webrtc 2722