Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmixer.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS Sound Volume Control 00003 * Copyright (C) 2004-2005 Thomas Weidenmueller 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 /* $Id: mixer.c 51274 2011-04-07 21:31:21Z janderwald $ 00020 * 00021 * COPYRIGHT: See COPYING in the top level directory 00022 * PROJECT: ReactOS Sound Volume Control 00023 * FILE: subsys/system/sndvol32/mixer.c 00024 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com> 00025 */ 00026 #include "sndvol32.h" 00027 00028 #define NO_MIXER_SELECTED ((UINT)(~0)) 00029 00030 static VOID 00031 ClearMixerCache(PSND_MIXER Mixer) 00032 { 00033 PSND_MIXER_DESTINATION Line, NextLine; 00034 PSND_MIXER_CONNECTION Con, NextCon; 00035 00036 for (Line = Mixer->Lines; Line != NULL; Line = NextLine) 00037 { 00038 if (Line->Controls != NULL) 00039 { 00040 HeapFree(GetProcessHeap(), 00041 0, 00042 Line->Controls); 00043 } 00044 00045 for (Con = Line->Connections; Con != NULL; Con = NextCon) 00046 { 00047 if (Con->Controls != NULL) 00048 { 00049 HeapFree(GetProcessHeap(), 00050 0, 00051 Con->Controls); 00052 } 00053 00054 NextCon = Con->Next; 00055 HeapFree(GetProcessHeap(), 00056 0, 00057 Con); 00058 } 00059 00060 NextLine = Line->Next; 00061 HeapFree(GetProcessHeap(), 00062 0, 00063 Line); 00064 } 00065 Mixer->Lines = NULL; 00066 } 00067 00068 PSND_MIXER 00069 SndMixerCreate(HWND hWndNotification) 00070 { 00071 PSND_MIXER Mixer = (PSND_MIXER) HeapAlloc(GetProcessHeap(), 00072 HEAP_ZERO_MEMORY, 00073 sizeof(SND_MIXER)); 00074 if (Mixer != NULL) 00075 { 00076 Mixer->hWndNotification = hWndNotification; 00077 Mixer->MixersCount = mixerGetNumDevs(); 00078 Mixer->MixerId = NO_MIXER_SELECTED; 00079 00080 if (Mixer->MixersCount > 0) 00081 { 00082 /* select the first mixer by default */ 00083 SndMixerSelect(Mixer, 0); 00084 } 00085 } 00086 00087 return Mixer; 00088 } 00089 00090 VOID 00091 SndMixerDestroy(PSND_MIXER Mixer) 00092 { 00093 SndMixerClose(Mixer); 00094 HeapFree(GetProcessHeap(), 00095 0, 00096 Mixer); 00097 } 00098 00099 VOID 00100 SndMixerClose(PSND_MIXER Mixer) 00101 { 00102 if (Mixer->hmx != NULL) 00103 { 00104 mixerClose(Mixer->hmx); 00105 Mixer->hmx = NULL; 00106 Mixer->MixerId = NO_MIXER_SELECTED; 00107 } 00108 } 00109 00110 BOOL 00111 SndMixerQueryControls(PSND_MIXER Mixer, 00112 PUINT DisplayControls, 00113 LPMIXERLINE LineInfo, 00114 LPMIXERCONTROL *Controls) 00115 { 00116 if (LineInfo->cControls > 0) 00117 { 00118 *Controls = (MIXERCONTROL*) HeapAlloc(GetProcessHeap(), 00119 HEAP_ZERO_MEMORY, 00120 LineInfo->cControls * sizeof(MIXERCONTROL)); 00121 if (*Controls != NULL) 00122 { 00123 MIXERLINECONTROLS LineControls; 00124 MMRESULT Result; 00125 UINT j; 00126 00127 LineControls.cbStruct = sizeof(LineControls); 00128 LineControls.dwLineID = LineInfo->dwLineID; 00129 LineControls.cControls = LineInfo->cControls; 00130 LineControls.cbmxctrl = sizeof(MIXERCONTROL); 00131 LineControls.pamxctrl = (MIXERCONTROL*)(*Controls); 00132 00133 Result = mixerGetLineControls((HMIXEROBJ)Mixer->hmx, 00134 &LineControls, 00135 MIXER_GETLINECONTROLSF_ALL); 00136 if (Result == MMSYSERR_NOERROR) 00137 { 00138 for (j = 0; j < LineControls.cControls; j++) 00139 { 00140 if (SndMixerIsDisplayControl(Mixer, 00141 &(*Controls)[j])) 00142 { 00143 (*DisplayControls)++; 00144 } 00145 00146 DPRINT("Line control: %ws (0x%x, 0x%x)\n", (*Controls)[j].szName, (*Controls)[j].fdwControl, (*Controls)[j].dwControlType); 00147 } 00148 00149 return TRUE; 00150 } 00151 else 00152 { 00153 HeapFree(GetProcessHeap(), 00154 0, 00155 *Controls); 00156 *Controls = NULL; 00157 DPRINT("Failed to get line (ID: 0x%x) controls: %d\n", LineInfo->dwLineID, Result); 00158 } 00159 } 00160 else 00161 { 00162 DPRINT("Failed to allocate memory for %d line (ID: 0x%x) controls!\n", LineInfo->dwLineID, LineInfo->cControls); 00163 } 00164 00165 return FALSE; 00166 } 00167 else 00168 { 00169 return TRUE; 00170 } 00171 } 00172 00173 static BOOL 00174 SndMixerQueryConnections(PSND_MIXER Mixer, 00175 PSND_MIXER_DESTINATION Line) 00176 { 00177 UINT i, DispControls; 00178 MIXERLINE LineInfo; 00179 MMRESULT Result; 00180 BOOL Ret = TRUE; 00181 00182 LineInfo.cbStruct = sizeof(LineInfo); 00183 for (i = Line->Info.cConnections; i > 0; i--) 00184 { 00185 LineInfo.dwDestination = Line->Info.dwDestination; 00186 LineInfo.dwSource = i - 1; 00187 Result = mixerGetLineInfo((HMIXEROBJ)Mixer->hmx, 00188 &LineInfo, 00189 MIXER_GETLINEINFOF_SOURCE); 00190 if (Result == MMSYSERR_NOERROR) 00191 { 00192 LPMIXERCONTROL Controls = NULL; 00193 PSND_MIXER_CONNECTION Con; 00194 00195 DPRINT("++ Source: %ws\n", LineInfo.szName); 00196 00197 DispControls = 0; 00198 00199 if (!SndMixerQueryControls(Mixer, 00200 &DispControls, 00201 &LineInfo, 00202 &Controls)) 00203 { 00204 DPRINT("Failed to query connection controls\n"); 00205 Ret = FALSE; 00206 break; 00207 } 00208 00209 Con = (SND_MIXER_CONNECTION*) HeapAlloc(GetProcessHeap(), 00210 HEAP_ZERO_MEMORY, 00211 sizeof(SND_MIXER_CONNECTION)); 00212 if (Con != NULL) 00213 { 00214 Con->Info = LineInfo; 00215 Con->Controls = Controls; 00216 Con->DisplayControls = DispControls; 00217 Con->Next = Line->Connections; 00218 Line->Connections = Con; 00219 } 00220 else 00221 { 00222 HeapFree(GetProcessHeap(), 00223 0, 00224 Controls); 00225 } 00226 } 00227 else 00228 { 00229 DPRINT("Failed to get connection information: %d\n", Result); 00230 Ret = FALSE; 00231 break; 00232 } 00233 } 00234 00235 return Ret; 00236 } 00237 00238 static BOOL 00239 SndMixerQueryDestinations(PSND_MIXER Mixer) 00240 { 00241 UINT i; 00242 BOOL Ret = TRUE; 00243 00244 for (i = Mixer->Caps.cDestinations; i > 0; i--) 00245 { 00246 PSND_MIXER_DESTINATION Line; 00247 00248 Line = (SND_MIXER_DESTINATION*) HeapAlloc(GetProcessHeap(), 00249 HEAP_ZERO_MEMORY, 00250 sizeof(SND_MIXER_DESTINATION)); 00251 if (Line != NULL) 00252 { 00253 Line->Info.cbStruct = sizeof(Line->Info); 00254 Line->Info.dwDestination = i - 1; 00255 if (mixerGetLineInfo((HMIXEROBJ)Mixer->hmx, 00256 &Line->Info, 00257 MIXER_GETLINEINFOF_DESTINATION) == MMSYSERR_NOERROR) 00258 { 00259 DPRINT("+ Destination: %ws (0x%x, %d)\n", Line->Info.szName, Line->Info.dwLineID, Line->Info.dwComponentType); 00260 00261 if (!SndMixerQueryControls(Mixer, 00262 &Line->DisplayControls, 00263 &Line->Info, 00264 &Line->Controls)) 00265 { 00266 DPRINT("Failed to query mixer controls!\n"); 00267 Ret = FALSE; 00268 break; 00269 } 00270 00271 if (!SndMixerQueryConnections(Mixer, Line)) 00272 { 00273 DPRINT("Failed to query mixer connections!\n"); 00274 Ret = FALSE; 00275 break; 00276 } 00277 00278 Line->Next = Mixer->Lines; 00279 Mixer->Lines = Line; 00280 } 00281 else 00282 { 00283 DPRINT("Failed to get line information for id %d!\n", i); 00284 HeapFree(GetProcessHeap(), 00285 0, 00286 Line); 00287 Ret = FALSE; 00288 break; 00289 } 00290 } 00291 else 00292 { 00293 DPRINT("Allocation of SND_MIXER_DEST structure for id %d failed!\n", i); 00294 Ret = FALSE; 00295 break; 00296 } 00297 } 00298 00299 return Ret; 00300 } 00301 00302 BOOL 00303 SndMixerSelect(PSND_MIXER Mixer, 00304 UINT MixerId) 00305 { 00306 if (MixerId >= Mixer->MixersCount) 00307 { 00308 return FALSE; 00309 } 00310 00311 SndMixerClose(Mixer); 00312 00313 if (mixerOpen(&Mixer->hmx, 00314 MixerId, 00315 (DWORD_PTR)Mixer->hWndNotification, 00316 0, 00317 CALLBACK_WINDOW | MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR || 00318 mixerOpen(&Mixer->hmx, 00319 MixerId, 00320 (DWORD_PTR)Mixer->hWndNotification, 00321 0, 00322 CALLBACK_WINDOW) == MMSYSERR_NOERROR || 00323 mixerOpen(&Mixer->hmx, 00324 MixerId, 00325 0, 00326 0, 00327 0) == MMSYSERR_NOERROR) 00328 { 00329 if (mixerGetDevCaps(MixerId, 00330 &Mixer->Caps, 00331 sizeof(Mixer->Caps)) == MMSYSERR_NOERROR) 00332 { 00333 BOOL Ret = FALSE; 00334 00335 Mixer->MixerId = MixerId; 00336 00337 ClearMixerCache(Mixer); 00338 00339 Ret = SndMixerQueryDestinations(Mixer); 00340 00341 if (!Ret) 00342 { 00343 ClearMixerCache(Mixer); 00344 } 00345 00346 return Ret; 00347 } 00348 else 00349 { 00350 mixerClose(Mixer->hmx); 00351 } 00352 } 00353 00354 Mixer->hmx = NULL; 00355 Mixer->MixerId = NO_MIXER_SELECTED; 00356 return FALSE; 00357 } 00358 00359 UINT 00360 SndMixerGetSelection(PSND_MIXER Mixer) 00361 { 00362 return Mixer->MixerId; 00363 } 00364 00365 INT 00366 SndMixerGetProductName(PSND_MIXER Mixer, 00367 LPTSTR lpBuffer, 00368 UINT uSize) 00369 { 00370 if (Mixer->hmx) 00371 { 00372 UINT lnsz = (UINT) lstrlen(Mixer->Caps.szPname); 00373 if(lnsz + 1 > uSize) 00374 { 00375 return lnsz + 1; 00376 } 00377 else 00378 { 00379 memcpy(lpBuffer, Mixer->Caps.szPname, lnsz * sizeof(TCHAR)); 00380 lpBuffer[lnsz] = _T('\0'); 00381 return lnsz; 00382 } 00383 } 00384 00385 return -1; 00386 } 00387 00388 INT 00389 SndMixerGetLineName(PSND_MIXER Mixer, 00390 DWORD LineID, 00391 LPTSTR lpBuffer, 00392 UINT uSize, 00393 BOOL LongName) 00394 { 00395 if (Mixer->hmx) 00396 { 00397 UINT lnsz; 00398 PSND_MIXER_DESTINATION Line; 00399 LPMIXERLINE lpl = NULL; 00400 00401 for (Line = Mixer->Lines; Line != NULL; Line = Line->Next) 00402 { 00403 if (Line->Info.dwLineID == LineID) 00404 { 00405 lpl = &Line->Info; 00406 break; 00407 } 00408 } 00409 00410 if (lpl != NULL) 00411 { 00412 lnsz = (UINT) lstrlen(LongName ? lpl->szName : lpl->szShortName); 00413 if(lnsz + 1 > uSize) 00414 { 00415 return lnsz + 1; 00416 } 00417 else 00418 { 00419 memcpy(lpBuffer, LongName ? lpl->szName : lpl->szShortName, lnsz * sizeof(TCHAR)); 00420 lpBuffer[lnsz] = _T('\0'); 00421 return lnsz; 00422 } 00423 } 00424 } 00425 00426 return -1; 00427 } 00428 00429 BOOL 00430 SndMixerEnumProducts(PSND_MIXER Mixer, 00431 PFNSNDMIXENUMPRODUCTS EnumProc, 00432 PVOID Context) 00433 { 00434 MIXERCAPS Caps; 00435 HMIXER hMixer; 00436 UINT i; 00437 BOOL Ret = TRUE; 00438 00439 for (i = 0; i < Mixer->MixersCount; i++) 00440 { 00441 if (mixerOpen(&hMixer, 00442 i, 00443 0, 00444 0, 00445 0) == MMSYSERR_NOERROR) 00446 { 00447 if (mixerGetDevCaps(i, 00448 &Caps, 00449 sizeof(Caps)) == MMSYSERR_NOERROR) 00450 { 00451 if (!EnumProc(Mixer, 00452 i, 00453 Caps.szPname, 00454 Context)) 00455 { 00456 mixerClose(hMixer); 00457 Ret = FALSE; 00458 break; 00459 } 00460 } 00461 else 00462 { 00463 DPRINT("Failed to get device capabilities for mixer id %d!\n", i); 00464 } 00465 mixerClose(hMixer); 00466 } 00467 } 00468 00469 return Ret; 00470 } 00471 00472 INT 00473 SndMixerSetVolumeControlDetails(PSND_MIXER Mixer, DWORD dwControlID, DWORD cbDetails, LPVOID paDetails) 00474 { 00475 MIXERCONTROLDETAILS MixerDetails; 00476 00477 if (Mixer->hmx) 00478 { 00479 MixerDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 00480 MixerDetails.dwControlID = dwControlID; 00481 MixerDetails.cChannels = 1; //FIXME 00482 MixerDetails.cMultipleItems = 0; 00483 MixerDetails.cbDetails = cbDetails; 00484 MixerDetails.paDetails = paDetails; 00485 00486 if (mixerSetControlDetails((HMIXEROBJ)Mixer->hmx, &MixerDetails, MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR) 00487 { 00488 return 1; 00489 } 00490 } 00491 00492 return -1; 00493 } 00494 00495 00496 INT 00497 SndMixerGetVolumeControlDetails(PSND_MIXER Mixer, DWORD dwControlID, DWORD cbDetails, LPVOID paDetails) 00498 { 00499 MIXERCONTROLDETAILS MixerDetails; 00500 00501 if (Mixer->hmx) 00502 { 00503 MixerDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 00504 MixerDetails.dwControlID = dwControlID; 00505 MixerDetails.cChannels = 1; //FIXME 00506 MixerDetails.cMultipleItems = 0; 00507 MixerDetails.cbDetails = cbDetails; 00508 MixerDetails.paDetails = paDetails; 00509 00510 if (mixerGetControlDetails((HMIXEROBJ)Mixer->hmx, &MixerDetails, MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR) 00511 { 00512 return 1; 00513 } 00514 } 00515 return -1; 00516 } 00517 00518 INT 00519 SndMixerGetDestinationCount(PSND_MIXER Mixer) 00520 { 00521 return (Mixer->hmx ? (INT)Mixer->Caps.cDestinations : -1); 00522 } 00523 00524 BOOL 00525 SndMixerEnumLines(PSND_MIXER Mixer, 00526 PFNSNDMIXENUMLINES EnumProc, 00527 PVOID Context) 00528 { 00529 if (Mixer->hmx) 00530 { 00531 PSND_MIXER_DESTINATION Line; 00532 00533 for (Line = Mixer->Lines; Line != NULL; Line = Line->Next) 00534 { 00535 if (!EnumProc(Mixer, 00536 &Line->Info, 00537 Line->DisplayControls, 00538 Context)) 00539 { 00540 return FALSE; 00541 } 00542 } 00543 00544 return TRUE; 00545 } 00546 00547 return FALSE; 00548 } 00549 00550 BOOL 00551 SndMixerEnumConnections(PSND_MIXER Mixer, 00552 DWORD LineID, 00553 PFNSNDMIXENUMCONNECTIONS EnumProc, 00554 PVOID Context) 00555 { 00556 if (Mixer->hmx) 00557 { 00558 PSND_MIXER_DESTINATION Line; 00559 00560 for (Line = Mixer->Lines; Line != NULL; Line = Line->Next) 00561 { 00562 if (Line->Info.dwLineID == LineID) 00563 { 00564 PSND_MIXER_CONNECTION Connection; 00565 00566 if (Line->DisplayControls != 0) 00567 { 00568 if (!EnumProc(Mixer, 00569 LineID, 00570 &Line->Info, 00571 Context)) 00572 { 00573 return FALSE; 00574 } 00575 } 00576 00577 for (Connection = Line->Connections; Connection != NULL; Connection = Connection->Next) 00578 { 00579 if (!EnumProc(Mixer, 00580 LineID, 00581 &Connection->Info, 00582 Context)) 00583 { 00584 return FALSE; 00585 } 00586 } 00587 00588 return TRUE; 00589 } 00590 } 00591 } 00592 00593 return FALSE; 00594 } 00595 00596 BOOL 00597 SndMixerIsDisplayControl(PSND_MIXER Mixer, 00598 LPMIXERCONTROL Control) 00599 { 00600 if (Mixer->hmx && !(Control->fdwControl & MIXERCONTROL_CONTROLF_DISABLED)) 00601 { 00602 switch (Control->dwControlType & MIXERCONTROL_CT_CLASS_MASK) 00603 { 00604 case MIXERCONTROL_CT_CLASS_FADER: 00605 case MIXERCONTROL_CT_CLASS_SWITCH: 00606 return TRUE; 00607 } 00608 } 00609 00610 return FALSE; 00611 } 00612 Generated on Sun May 27 2012 04:17:44 for ReactOS by
1.7.6.1
|