views:

262

answers:

0

Hi.

I am having a problem with the Mixer API in Windows XP.

I am trying to change the microphone recording level and mute state for a distinct sound device (I have multiple devices installed).

Do do this, I need the MIXERLINE.dwLineID member in order to obtain MIXERCONTROL.dwControlID.

I am trying to do this by passing MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE and MIXERCONTROL_CONTROLTYPE_VOLUME respective MIXERCONTROL_CONTROLTYPE_MUTE to the mixerGetLineInfo () and mixerGetLineControls () functions, but they always return the ControlID of the "Loudspeaker" Microphone control, i.e. the monitor control used to loop the voice directly back to the user. The input volume is not changed as this is the wrong control, I would suspect this (wrong) control to be obtained with MIXERLINE_COMPONENTTYPE_DST_VOICEIN.

Is there a bug in the mixer api which mixes up SRC and DST, or is my call wrong?

It works in Windows Vista, where the call successfully returns the correct ControlID of the RECORDING (SRC) device.

I tried different things, for example passing a HWAVEIN to the opened input device, a HMIXER object obtained with mixerOpen () and a mixer ID with mixerGetID (), using the Flags MIXER_OBJECTF_HWAVEIN, MIXER_OBJECTF_HMIXER and MIXER_OBJECTF_MIXER to all the mixerXX () functions used.

The mixer api seems to just ignore all these parameters for all mixer functions except for the control change callback.

The mixer open call: mixerOpen (&m_InMixer, (UINT)m_WaveIn, m_mm->getThreadID (), 0, CALLBACK_THREAD | MIXER_OBJECTF_HWAVEIN);

The code for obtaining the ControlID:

DWORD getMixerLine (HMIXER mix, DWORD comptype, DWORD ctrltype) {
    MMRESULT mm;
    DWORD mixid;

    mm = mixerGetID ((HMIXEROBJ)mix, (UINT *)&mixid, MIXER_OBJECTF_HMIXER);
    assert (mm == MMSYSERR_NOERROR);

    MIXERLINE mxl;
    memset (&mxl, 0, sizeof (mxl));
    mxl.cbStruct = sizeof (mxl);
    mxl.dwComponentType = comptype;
    mm = mixerGetLineInfo ((HMIXEROBJ)mixid, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_MIXER);
    if (mm == MMSYSERR_NOERROR)
    {
     MIXERCONTROL *mxc = (MIXERCONTROL *)alloca (sizeof (MIXERCONTROL) * mxl.cControls);
     memset (mxc, 0, sizeof (mxc) * mxl.cControls);
     for (size_t n = 0; n < mxl.cControls; n++)
      mxc[n].cbStruct = sizeof (mxc);

     MIXERLINECONTROLS mxlc;
     memset (&mxlc, 0, sizeof (mxlc));
     mxlc.cbStruct = sizeof (mxlc);
     mxlc.dwLineID = mxl.dwLineID;
     mxlc.dwControlType = ctrltype;
     mxlc.cControls = 1;// mxl.cControls;
     mxlc.cbmxctrl = sizeof (MIXERCONTROL);
     mxlc.pamxctrl = mxc;
     //mm = mixerGetLineControls ((HMIXEROBJ)mix, &mxlc,  
MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_MIXER);
     mm = mixerGetLineControls ((HMIXEROBJ)mixid, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_MIXER);
     if (mm == MMSYSERR_NOERROR)
     {
      //for (size_t n = 0; n < mxl.cControls; n++)
      //{
      // CTVObject::Log (LOG ("Audio: vin %1%") % mxc[n].dwControlID);
      //}
      return mxc[0].dwControlID;
     }
    }
    return -1;
}

and getMixerLine (m_InMixer, MIXERLINE_COMPONENTTYPE_DST_VOICEIN,
MIXERCONTROL_CONTROLTYPE_VOLUME);

Additional info: I KNOW the correct ControlID (which in my case is 1 and 12 for different sound input devices), as soon as the user changes the microphone input control, obtained from the callback MM_MIXM_CONTROL_CHANGE, but I have found no way to obtain this ID prior to the callback. To wait for the user to change the control to save the id is no option.

If no one has an idea, I might be forced to intercept the calls in sndvol32.exe, which somehow seems to be able to list all the controls for a device.

I would be very glad if someone had an advice.