logo

Previous Thread:   Rendering with VFW codec

7/15/2005 6:34:10 AM    How to Mute Microphone (not Speaker) for All Applications
Hello,  
  
Is it possible to Mute (and Unmute) microphone globally so that none of the  
  
applications can receive recording input? Is it possible to read such Mute  
  
state back? If yes, how? My application is in c# so managed code examples  
  
would be more helpful. Thanks.  
  
Regards,  
  
Vinay Agarwal

7/15/2005 10:03:24 AM    Re: How to Mute Microphone (not Speaker) for All Applications
"Vinay Agarwal" <VinayAgarwal@discussions.microsoft.com> wrote in message  
  
news:DA000264-B1E5-46D4-AB40-EDA02E92E362@microsoft.com...  
  
Yes, it is. See below.  
  
I haven't had the "pleasure" of doing multimedia tasks in managed code so I  
  
don't know what the platform offers. In the absence of better advice, what  
  
follows is a native approach which you could build into a DLL, export a  
  
function to do the job, and use Platform Invoke (aka P/Invoke) to do the  
  
job.  
  
In an old (Oct 2001) there is a knowledge base article on unmuting the  
  
microrphone. I couldn't find it online just now when I looked. :-(  
  
In any event, in the UnMute() function below, these lines  
  
// Unmute the microphone line (for both channels)  
  
pbool[0].fValue = pbool[cChannels - 1].fValue = 0;  
  
unmute the microphone. On the other hand, if you set the value of the  
  
control to 1, the mic should be muted.  
  
Regards,  
  
Will  
  
PRB: No Signal is Recorded When Using MCI or waveInxxx APIs  
  
Q159753  
  
--------------------------------------------------------------------------------  
  
The information in this article applies to:  
  
Microsoft Platform Software Development Kit (SDK), on platform(s):  
  
Microsoft Windows 98  
  
Microsoft Windows 95  
  
the operating system: Microsoft Windows 2000  
  
--------------------------------------------------------------------------------  
  
SYMPTOMS  
  
There is no signal recorded using MCI (Media Control Interface) or waveInXXX  
  
APIs to record through the microphone.  
  
CAUSE  
  
There are three possible causes:  
  
The microphone line is muted.  
  
The volume of the microphone line is turned to the minimum.  
  
The microphone line is not selected into the wave input destination.  
  
RESOLUTION  
  
You need to make sure that none of the above conditions exist in your  
  
applications. The audio mixer API set provides a means by which each  
  
condition can be checked and set accordingly.  
  
MORE INFORMATION  
  
Two input lines are involved when recording from the microphone: the  
  
physical source line (microphone) and the logical source line (wave in).  
  
This recording architecture can be separated into two distinct components  
  
where the signals from the microphone source line feed into the wave in  
  
destination line. Multiple controls influence these lines.  
  
The first condition is cleared through a mute control. The second condition  
  
through a volume control. To clear the third one, use a LIST control  
  
associated with the wave input line. The following Visual C++ sample code  
  
consists of three functions for clearing these conditions, respectively.  
  
Although this sample is written in Visual C++, you can move the in-line  
  
declarations up front and modify the Visual C++ style initialization to make  
  
it a C sample:  
  
void UnMute()  
  
{  
  
// Open the mixer device  
  
HMIXER hmx;  
  
mixerOpen(&hmx, 0, 0, 0, 0);  
  
// Get the line info for the wave in destination line  
  
MIXERLINE mxl;  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
// Now find the microphone source line connected to this wave in  
  
// destination  
  
DWORD cConnections = mxl.cConnections;  
  
for(DWORD j=0; j<cConnections; j++){  
  
mxl.dwSource = j;  
  
mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_SOURCE);  
  
if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == mxl.dwComponentType)  
  
break;  
  
}  
  
// Find a mute control, if any, of the microphone line  
  
LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof MIXERCONTROL);  
  
MIXERLINECONTROLS mxlctrl = {sizeof mxlctrl, mxl.dwLineID,  
  
MIXERCONTROL_CONTROLTYPE_MUTE, 1, sizeof MIXERCONTROL, pmxctrl};  
  
if(!mixerGetLineControls((HMIXEROBJ) hmx, &mxlctrl,  
  
MIXER_GETLINECONTROLSF_ONEBYTYPE)){  
  
// Found, so proceed  
  
DWORD cChannels = mxl.cChannels;  
  
if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)  
  
cChannels = 1;  
  
LPMIXERCONTROLDETAILS_BOOLEAN pbool =  
  
(LPMIXERCONTROLDETAILS_BOOLEAN) malloc(cChannels * sizeof  
  
MIXERCONTROLDETAILS_BOOLEAN);  
  
MIXERCONTROLDETAILS mxcd = {sizeof(mxcd), pmxctrl->dwControlID,  
  
cChannels, (HWND)0,  
  
sizeof MIXERCONTROLDETAILS_BOOLEAN, (LPVOID) pbool};  
  
mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
// Unmute the microphone line (for both channels)  
  
pbool[0].fValue = pbool[cChannels - 1].fValue = 0;  
  
mixerSetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
free(pmxctrl);  
  
free(pbool);  
  
}  
  
else  
  
free(pmxctrl);  
  
mixerClose(hmx);  
  
}  
  
void SetVolume()  
  
{  
  
// Open the mixer device  
  
HMIXER hmx;  
  
mixerOpen(&hmx, 0, 0, 0, 0);  
  
// Get the line info for the wave in destination line  
  
MIXERLINE mxl;  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
mixerGetLineInfo((HMIXEROBJ)hmx, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
// Now find the microphone source line connected to this wave in  
  
// destination  
  
DWORD cConnections = mxl.cConnections;  
  
for(DWORD j=0; j<cConnections; j++){  
  
mxl.dwSource = j;  
  
mixerGetLineInfo((HMIXEROBJ)hmx, &mxl, MIXER_GETLINEINFOF_SOURCE);  
  
if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == mxl.dwComponentType)  
  
break;  
  
}  
  
// Find a volume control, if any, of the microphone line  
  
LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof MIXERCONTROL);  
  
MIXERLINECONTROLS mxlctrl = {sizeof mxlctrl, mxl.dwLineID,  
  
MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof MIXERCONTROL, pmxctrl};  
  
if(!mixerGetLineControls((HMIXEROBJ) hmx, &mxlctrl,  
  
MIXER_GETLINECONTROLSF_ONEBYTYPE)){  
  
// Found!  
  
DWORD cChannels = mxl.cChannels;  
  
if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl)  
  
cChannels = 1;  
  
LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned =  
  
(LPMIXERCONTROLDETAILS_UNSIGNED)  
  
malloc(cChannels * sizeof MIXERCONTROLDETAILS_UNSIGNED);  
  
MIXERCONTROLDETAILS mxcd = {sizeof(mxcd), pmxctrl->dwControlID,  
  
cChannels, (HWND)0,  
  
sizeof MIXERCONTROLDETAILS_UNSIGNED, (LPVOID) pUnsigned};  
  
mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
// Set the volume to the middle  (for both channels as needed)  
  
pUnsigned[0].dwValue = pUnsigned[cChannels - 1].dwValue =  
  
(pmxctrl->Bounds.dwMinimum+pmxctrl->Bounds.dwMaximum)/2;  
  
mixerSetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
free(pmxctrl);  
  
free(pUnsigned);  
  
}  
  
else  
  
free(pmxctrl);  
  
mixerClose(hmx);  
  
}  
  
void SelectMic()  
  
{  
  
// Open the mixer device  
  
HMIXER hmx;  
  
mixerOpen(&hmx, 0, 0, 0, 0);  
  
// Get the line info for the wave in destination line  
  
MIXERLINE mxl;  
  
mxl.cbStruct      = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
mixerGetLineInfo((HMIXEROBJ)hmx, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
// Find a LIST control, if any, for the wave in line  
  
LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(mxl.cControls * sizeof  
  
MIXERCONTROL);  
  
MIXERLINECONTROLS mxlctrl = {sizeof mxlctrl, mxl.dwLineID, 0,  
  
mxl.cControls, sizeof MIXERCONTROL, pmxctrl};  
  
mixerGetLineControls((HMIXEROBJ) hmx, &mxlctrl,  
  
MIXER_GETLINECONTROLSF_ALL);  
  
// Now walk through each control to find a type of LIST control. This  
  
// can be either Mux, Single-select, Mixer or Multiple-select.  
  
DWORD i;  
  
for(i=0; i < mxl.cControls; i++)  
  
if (MIXERCONTROL_CT_CLASS_LIST == (pmxctrl[i].dwControlType  
  
&MIXERCONTROL_CT_CLASS_MASK))  
  
break;  
  
if (i < mxl.cControls) { // Found a LIST control  
  
// Check if the LIST control is a Mux or Single-select type  
  
BOOL bOneItemOnly = FALSE;  
  
switch (pmxctrl[i].dwControlType) {  
  
case MIXERCONTROL_CONTROLTYPE_MUX:  
  
case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:  
  
bOneItemOnly = TRUE;  
  
}  
  
DWORD cChannels = mxl.cChannels, cMultipleItems = 0;  
  
if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl[i].fdwControl)  
  
cChannels = 1;  
  
if (MIXERCONTROL_CONTROLF_MULTIPLE & pmxctrl[i].fdwControl)  
  
cMultipleItems = pmxctrl[i].cMultipleItems;  
  
// Get the text description of each item  
  
LPMIXERCONTROLDETAILS_LISTTEXT plisttext =  
  
(LPMIXERCONTROLDETAILS_LISTTEXT)  
  
malloc(cChannels * cMultipleItems * sizeof  
  
MIXERCONTROLDETAILS_LISTTEXT);  
  
MIXERCONTROLDETAILS mxcd = {sizeof(mxcd), pmxctrl[i].dwControlID,  
  
cChannels,  
  
(HWND)cMultipleItems, sizeof MIXERCONTROLDETAILS_LISTTEXT,  
  
(LPVOID) plisttext};  
  
mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_GETCONTROLDETAILSF_LISTTEXT);  
  
// Now get the value for each item  
  
LPMIXERCONTROLDETAILS_BOOLEAN plistbool =  
  
(LPMIXERCONTROLDETAILS_BOOLEAN)  
  
malloc(cChannels * cMultipleItems * sizeof  
  
MIXERCONTROLDETAILS_BOOLEAN);  
  
mxcd.cbDetails = sizeof MIXERCONTROLDETAILS_BOOLEAN;  
  
mxcd.paDetails = plistbool;  
  
mixerGetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_GETCONTROLDETAILSF_VALUE);  
  
// Select the "Microphone" item  
  
for (DWORD j=0; j<cMultipleItems; j = j + cChannels)  
  
if (0 == strcmp(plisttext[j].szName, "Microphone"))  
  
// Select it for both left and right channels  
  
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 1;  
  
else if (bOneItemOnly)  
  
// Mux or Single-select allows only one item to be selected  
  
// so clear other items as necessary  
  
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 0;  
  
// Now actually set the new values in  
  
mixerSetControlDetails((HMIXEROBJ)hmx, &mxcd,  
  
MIXER_GETCONTROLDETAILSF_VALUE);  
  
free(pmxctrl);  
  
free(plisttext);  
  
free(plistbool);  
  
}  
  
else  
  
free(pmxctrl);  
  
mixerClose(hmx);  
  
}  
  
Additional query words: 4.00 kbdsd waveInOpen waveInAddBuffer new type  
  
waveaudio  
  
Keywords : kbmm  
  
Issue type : kbprb  
  
Technology : kbWin32SDKSearch kbAudDeveloper kbSDKSearch  
  
Last Reviewed: December 15, 2000  
  
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.  
  
--------------------------------------------------------------------------------  
  
Send feedback to MSDN.Look here for MSDN Online resources.

7/15/2005 10:24:44 AM    Re: How to Mute Microphone (not Speaker) for All Applications
On Fri, 15 Jul 2005 06:34:10 -0700, Vinay Agarwal wrote:  
  
There is no mute mode for inputs, but you can set the volume to 0.  
  
I'm not aware of any mixer API for c# so you will be forced to call into  
  
the WinAPI.  
  
All mixer functionality is controlled by the mixer API, all functions start  
  
with mixer...  
  
Take a look at the follow C++ code derived from some on codeguru:  
  
main(...)  
  
{  
  
CMixer mixer(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE, CMixer::Record);  
  
saveVolume = mixer.GetVolume();  
  
mixer.SetVolume(0);  
  
...  
  
mixer.SetVolume(saveVolume);  
  
}  
  
CMixer::CMixer(DWORD ComponentType, DestKind dkKind): m_dwControlID(-1),  
  
m_bOK(false), m_dwChannels(0)  
  
{  
  
HMIXER hMixer;  
  
HRESULT hr;  
  
hr = mixerOpen(&hMixer, 0, 0, 0, 0);  
  
if (FAILED(hr)) return;  
  
MIXERLINE mxl;  
  
MIXERCONTROL mc;  
  
MIXERLINECONTROLS mxlc;  
  
DWORD kind, count;  
  
int item=-1;  
  
if (dkKind == Play)  
  
{  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = ComponentType;  
  
hr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
if (FAILED(hr))  
  
{  
  
mixerClose(hMixer);  
  
return;  
  
}  
  
kind = ComponentType;  
  
item = mxl.dwSource;  
  
}  
  
else  
  
{  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
// get the destination mxl.dwDestination  
  
hr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
mxl.dwComponentType = ComponentType;  
  
// loop through the sources  
  
count = 0xFFFF;  
  
for(UINT i = 0; i < count; i++)  
  
{  
  
mxl.dwSource = i;  
  
hr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,  
  
MIXER_GETLINEINFOF_SOURCE);  
  
if (FAILED(hr))  
  
return;  
  
if (mxl.dwComponentType == ComponentType)  
  
{  
  
item = i;  
  
m_dwChannels = mxl.cChannels;  
  
break;  
  
}  
  
}  
  
}  
  
if (item >= 0)  
  
{  
  
mc.cbStruct = sizeof(mc);  
  
mxlc.cbStruct = sizeof(mxlc);  
  
mxlc.dwLineID = mxl.dwLineID;  
  
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;  
  
mxlc.cControls = 1;  
  
mxlc.cbmxctrl = sizeof(MIXERCONTROL);  
  
mxlc.pamxctrl = &mc;  
  
hr = mixerGetLineControls((HMIXEROBJ)hMixer, &mxlc,  
  
MIXER_GETLINECONTROLSF_ONEBYTYPE);  
  
m_dwControlID = mc.dwControlID;  
  
}  
  
mixerClose(hMixer);  
  
m_bOK = true;  
  
}  
  
int CMixer::GetDestination(HMIXER hMixer, DWORD ComponentType)  
  
{  
  
MIXERLINE mxl;  
  
HRESULT hr;  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = ComponentType;  
  
hr = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
if (FAILED(hr))  
  
{  
  
mixerClose(hMixer);  
  
return -1;  
  
}  
  
return mxl.dwDestination;  
  
}  
  
void CMixer::SetVolume(DWORD dwVol)  
  
{  
  
if (!m_bOK) return;  
  
HMIXER hMixer;  
  
HRESULT hr;  
  
hr = mixerOpen(&hMixer, 0, 0, 0, 0);  
  
if (FAILED(hr)) return;  
  
MIXERCONTROLDETAILS mxcd;  
  
MIXERCONTROLDETAILS_UNSIGNED mxdu;  
  
mxdu.dwValue = dwVol;  
  
mxcd.cMultipleItems = 0;  
  
mxcd.cChannels = 1;  
  
mxcd.cbStruct = sizeof(mxcd);  
  
mxcd.dwControlID = m_dwControlID;  
  
mxcd.cbDetails = sizeof(mxdu);  
  
mxcd.paDetails = &mxdu;  
  
hr = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
mixerClose(hMixer);  
  
}  
  
DWORD CMixer::GetVolume()  
  
{  
  
if (!m_bOK) return 0;  
  
HMIXER hMixer;  
  
HRESULT hr;  
  
hr = mixerOpen(&hMixer, 0, 0, 0, 0);  
  
if (FAILED(hr)) return 0;  
  
MIXERCONTROLDETAILS mxcd;  
  
MIXERCONTROLDETAILS_UNSIGNED mxdu;  
  
mxcd.cMultipleItems = 0;  
  
mxcd.cChannels = m_dwChannels;  
  
mxcd.cbStruct = sizeof(mxcd);  
  
mxcd.dwControlID = m_dwControlID;  
  
mxcd.cbDetails = sizeof(mxdu);  
  
mxcd.paDetails = &mxdu;  
  
hr = mixerGetControlDetails((HMIXEROBJ)hMixer, &mxcd,  
  
MIXER_GETCONTROLDETAILSF_VALUE);  
  
mixerClose(hMixer);  
  
return mxdu.dwValue;  
  
}

7/15/2005 10:32:29 AM    Re: How to Mute Microphone (not Speaker) for All Applications
On Fri, 15 Jul 2005 10:03:24 -0400, William DePalo [MVP VC++] wrote:  
  
But there is no mute control for the controls on the Record mixer?  There  
  
is only a selection Mux, so you could effectively mute by selecting an  
  
unused input.

7/15/2005 1:48:39 PM    Re: How to Mute Microphone (not Speaker) for All Applications
"Chris P. [MVP]" <msdn@chrisnet.net> wrote in message  
  
news:i8l7e2kxl04a$.1ra9ko6i2xnvx$.dlg@40tude.net...  
  
My bad. Thanks for the correction.  
  
Regards,  
  
Will

7/16/2005 1:40:41 PM    Re: How to Mute Microphone (not Speaker) for All Applications
On Sat, 16 Jul 2005 08:29:02 -0700, Vinay Agarwal wrote:  
  
I imagine that it does a soft mute, rather than actually muting the mixer.  
  
For a soft mute the program would simply stop reading in audio data or set  
  
the data stream to silence.  You can't achieve this through external  
  
control.

7/16/2005 1:49:12 PM    Re: How to Mute Microphone (not Speaker) for All Applications
On Fri, 15 Jul 2005 15:21:03 -0700, Vinay Agarwal wrote:  
  
Some systems can have input mute controls, but most generic sound cards  
  
don't.  
  
All inputs have the potential to be used, but in a typical scenario there's  
  
usually at least one that isn't used.  
  
I will post a sample to that on Monday.

7/20/2005 1:01:21 PM    Re: How to Mute Microphone (not Speaker) for All Applications
On Wed, 20 Jul 2005 07:02:03 -0700, Vinay Agarwal wrote:  
  
Sorry for the delay.  Working on simplifying this ugly, ugly code.

7/23/2005 12:16:17 PM    Re: How to Mute Microphone (not Speaker) for All Applications
I recommend you to try some component.  
  
E.G. www.mmsw.cz/cz/devcorner.aspx  
  
Miroslav  
  
--  
  
"Vinay Agarwal" <VinayAgarwal@discussions.microsoft.com> pí¹e v diskusním pøíspìvku  
  
news:DA000264-B1E5-46D4-AB40-EDA02E92E362@microsoft.com...

7/23/2005 12:29:15 PM    Re: How to Mute Microphone (not Speaker) for All Applications
On Wed, 20 Jul 2005 13:01:21 -0400, Chris P. [MVP] wrote:  
  
Don't worry Vinay, I haven't forgotten about you.  I'm very busy with  
  
several projects and the "simple" code I wipped up for you wasn't working  
  
right so I'm doing things the hard way.

7/26/2005 12:14:26 PM    Re: How to Mute Microphone (not Speaker) for All Applications
On Sat, 23 Jul 2005 12:29:15 -0400, Chris P. [MVP] wrote:  
  
Sorry for the delay on this, here you go (the formatting is ugly):  
  
// return the current mux input number and the name string  
  
int GetMuxInput(HMIXER mix, CString &sInputName)  
  
{  
  
int retval = -1;  
  
MMRESULT error;  
  
MIXERLINE mxl;  
  
mxl.cbStruct = sizeof(mxl);  
  
MIXERLINECONTROLS controls;  
  
MIXERCONTROL * control;  
  
MIXERCONTROLDETAILS cd;  
  
HRESULT hr;  
  
memset(&mxl, 0, sizeof(mxl));  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
hr = mixerGetLineInfo((HMIXEROBJ)mix, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
hr = mixerGetLineInfo((HMIXEROBJ)mix, &mxl,  
  
MIXER_GETLINEINFOF_DESTINATION);  
  
if (hr == MMSYSERR_NOERROR)  
  
{  
  
// should always be the first, but should iterate to make sure  
  
//for (int dest=0; dest<mxl.dwDestination; dest++)  
  
{  
  
controls.cbStruct = sizeof(MIXERLINECONTROLS);  
  
controls.dwLineID = mxl.dwLineID;  // from MIXERLINE  
  
controls.cControls = mxl.cControls;  
  
controls.cbmxctrl = sizeof(MIXERCONTROL);  
  
control = (MIXERCONTROL *)LocalAlloc(LPTR, sizeof(MIXERCONTROL) *  
  
controls.cControls);  
  
controls.pamxctrl = control;  
  
controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;  
  
error = mixerGetLineControls((HMIXEROBJ)mix, &controls,  
  
MIXER_GETLINECONTROLSF_ONEBYTYPE);  
  
if (MMSYSERR_NOERROR == error)  
  
{  
  
for (int c=0; c < controls.cControls; c++) // c should equal 0 (1  
  
control) but you never know  
  
{  
  
// MUX - MULTIPLE SELECT  
  
if (MIXERCONTROL_CONTROLTYPE_MUX == (MIXERCONTROL_CONTROLTYPE_MUX &  
  
control[c].dwControlType))  
  
{  
  
cd.cbStruct = sizeof(MIXERCONTROLDETAILS);  
  
cd.dwControlID = control->dwControlID;  
  
cd.cChannels = 1;  
  
cd.cMultipleItems = control->cMultipleItems;  
  
//cd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);  
  
cd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);  
  
MIXERCONTROLDETAILS_BOOLEAN * lv = (MIXERCONTROLDETAILS_BOOLEAN  
  
*)LocalAlloc (LPTR, cd.cChannels * cd.cMultipleItems * cd.cbDetails);  
  
MIXERCONTROLDETAILS_LISTTEXT * lt = (MIXERCONTROLDETAILS_LISTTEXT  
  
*)LocalAlloc (LPTR, cd.cChannels * cd.cMultipleItems * cd.cbDetails);  
  
if (NULL != lv)  
  
{  
  
// get the text names  
  
cd.paDetails = lt;  
  
error = mixerGetControlDetails((HMIXEROBJ)mix, &cd,  
  
MIXER_GETCONTROLDETAILSF_LISTTEXT);  
  
// get the state values  
  
cd.paDetails = lv;  
  
error = mixerGetControlDetails((HMIXEROBJ)mix, &cd,  
  
MIXER_GETCONTROLDETAILSF_VALUE);  
  
// find out which mux input is selected  
  
for (int i = 0; i < cd.cMultipleItems; i++)  
  
{  
  
CString temp;  
  
temp.Format("%-30s [%c]\n", lt[i].szName, lv[i].fValue?'X':' ');  
  
OutputDebugString(temp);  
  
if (lv[i].fValue)  
  
{  
  
retval = i;  
  
sInputName = lt[i].szName;  
  
}  
  
}  
  
LocalFree(lv);  
  
LocalFree(lt);  
  
}  
  
}  
  
}  
  
}  
  
}  
  
}  
  
return retval;  
  
}  
  
// Set the active Mux input select and return previous selection  
  
int SetMuxInput(HMIXER mix, DWORD target)  
  
{  
  
int retval = -1;  
  
MMRESULT error;  
  
MIXERLINE mxl;  
  
mxl.cbStruct = sizeof(mxl);  
  
MIXERLINECONTROLS controls;  
  
MIXERCONTROL * control;  
  
MIXERCONTROLDETAILS cd;  
  
HRESULT hr;  
  
memset(&mxl, 0, sizeof(mxl));  
  
mxl.cbStruct = sizeof(mxl);  
  
mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;  
  
hr = mixerGetLineInfo((HMIXEROBJ)mix, &mxl,  
  
MIXER_GETLINEINFOF_COMPONENTTYPE);  
  
hr = mixerGetLineInfo((HMIXEROBJ)mix, &mxl,  
  
MIXER_GETLINEINFOF_DESTINATION);  
  
if (hr == MMSYSERR_NOERROR)  
  
{  
  
// should always be the first, but should iterate to make sure  
  
//for (int dest=0; dest<mxl.dwDestination; dest++)  
  
{  
  
controls.cbStruct = sizeof(MIXERLINECONTROLS);  
  
controls.dwLineID = mxl.dwLineID;  // from MIXERLINE  
  
controls.cControls = mxl.cControls;  
  
controls.cbmxctrl = sizeof(MIXERCONTROL);  
  
control = (MIXERCONTROL *)LocalAlloc(LPTR, sizeof(MIXERCONTROL) *  
  
controls.cControls);  
  
controls.pamxctrl = control;  
  
controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;  
  
error = mixerGetLineControls((HMIXEROBJ)mix, &controls,  
  
MIXER_GETLINECONTROLSF_ONEBYTYPE);  
  
if (MMSYSERR_NOERROR == error)  
  
{  
  
if (target > control->cMultipleItems)  
  
return -1; // value out of range  
  
for (int c=0; c < controls.cControls; c++) // c should equal 0 (1  
  
control) but you never know  
  
{  
  
// MUX - MULTIPLE SELECT  
  
if (MIXERCONTROL_CONTROLTYPE_MUX == (MIXERCONTROL_CONTROLTYPE_MUX &  
  
control[c].dwControlType))  
  
{  
  
cd.cbStruct = sizeof(MIXERCONTROLDETAILS);  
  
cd.dwControlID = control->dwControlID;  
  
cd.cChannels = 1;  
  
cd.cMultipleItems = control->cMultipleItems;  
  
cd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);  
  
MIXERCONTROLDETAILS_BOOLEAN * lv = (MIXERCONTROLDETAILS_BOOLEAN  
  
*)LocalAlloc (LPTR, cd.cChannels * cd.cMultipleItems * cd.cbDetails);  
  
if (NULL != lv)  
  
{  
  
// get the state values  
  
cd.paDetails = lv;  
  
error = mixerGetControlDetails((HMIXEROBJ)mix, &cd,  
  
MIXER_GETCONTROLDETAILSF_VALUE);  
  
// find out which mux input is selected  
  
for (int i = 0; i < cd.cMultipleItems; i++)  
  
{  
  
if (lv[i].fValue)  
  
{  
  
// if the select flag is on turn it off  
  
retval = i; // save it for return value  
  
lv[i].fValue = 0;  
  
}  
  
}  
  
// set the select flag for the target item  
  
lv[target].fValue = 1;  
  
error = mixerSetControlDetails((HMIXEROBJ)mix, &cd,  
  
MIXER_SETCONTROLDETAILSF_VALUE);  
  
LocalFree(lv);  
  
}  
  
}  
  
}  
  
}  
  
}  
  
}  
  
return retval; // return previously selected item  
  
}