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