diff --git a/linphone/mediastreamer2/src/winsnd2.c b/linphone/mediastreamer2/src/winsnd2.c index 56a0e3cd2..8d5de36d4 100755 --- a/linphone/mediastreamer2/src/winsnd2.c +++ b/linphone/mediastreamer2/src/winsnd2.c @@ -62,6 +62,11 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; + MMRESULT mr = MMSYSERR_NOERROR; DWORD dwVolume = ((0xFFFF) * percent) / 100; @@ -76,11 +81,6 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc case MS_SND_CARD_PLAYBACK: case MS_SND_CARD_MASTER: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; - mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); if ( mr != MMSYSERR_NOERROR ) { @@ -168,6 +168,43 @@ static void winsndcard_set_level(MSSndCard *card, MSSndCardMixerElem e, int perc /* ms_message("Source Line: %d\n", MixerLine.dwSource); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ + mlc.cbStruct = sizeof(MIXERLINECONTROLS); + mlc.dwLineID = MixerLine.dwLineID; + mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mlc.cControls = 1; + mlc.pamxctrl = &mc; + mlc.cbmxctrl = sizeof(MIXERCONTROL); + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, + &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + + if (mr == MMSYSERR_NOERROR) + { + mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */ + + mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mcd.hwndOwner = 0; + mcd.dwControlID = mc.dwControlID; + mcd.paDetails = &mcdu; + mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mcd.cChannels = 1; + mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, + &mcd, MIXER_SETCONTROLDETAILSF_VALUE); + + if (mr == MMSYSERR_NOERROR) + { + return; + } + ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr); + ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead"); + } + else + { + ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr); + ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead"); + } + + /* In case capture doesn't work: use the SRC_MICROPHONE volume */ + for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++) { memset( &Line, 0, sizeof(MIXERLINE) ); @@ -260,6 +297,11 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){ MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; + MMRESULT mr = MMSYSERR_NOERROR; int percent; @@ -267,11 +309,6 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){ case MS_SND_CARD_MASTER: case MS_SND_CARD_PLAYBACK: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; - mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); if ( mr != MMSYSERR_NOERROR ) { @@ -360,6 +397,39 @@ static int winsndcard_get_level(MSSndCard *card, MSSndCardMixerElem e){ return -1; } + mlc.cbStruct = sizeof(MIXERLINECONTROLS); + mlc.dwLineID = MixerLine.dwLineID; + mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mlc.cControls = 1; + mlc.pamxctrl = &mc; + mlc.cbmxctrl = sizeof(MIXERCONTROL); + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, + &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (mr == MMSYSERR_NOERROR) + { + mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mcd.hwndOwner = 0; + mcd.dwControlID = mc.dwControlID; + mcd.paDetails = &mcdu; + mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mcd.cChannels = 1; + mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, + MIXER_SETCONTROLDETAILSF_VALUE); + percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum); + + if (mr == MMSYSERR_NOERROR) + { + return percent; + } + ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + else + { + ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + /* ms_message("Name: %s\n", MixerLine.szName); */ /* ms_message("Source Line: %d\n", MixerLine.dwSource); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ @@ -466,11 +536,18 @@ static int winsndcard_set_control(MSSndCard *card, MSSndCardControlElem e, int v MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_BOOLEAN bMute; + MMRESULT mr = MMSYSERR_NOERROR; switch(e){ case MS_SND_CARD_CAPTURE_MUTE: + bMute.fValue = (val>0); + mr = mixerGetID( (HMIXEROBJ)d->in_devid, &uMixerID, MIXER_OBJECTF_WAVEIN ); if ( mr != MMSYSERR_NOERROR ) { @@ -582,11 +659,6 @@ static int winsndcard_set_control(MSSndCard *card, MSSndCardControlElem e, int v case MS_SND_CARD_MASTER_MUTE: case MS_SND_CARD_PLAYBACK_MUTE: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_BOOLEAN bMute; - bMute.fValue = (val>0); mr = mixerGetID( (HMIXEROBJ)d->out_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); diff --git a/linphone/mediastreamer2/src/winsndds.cpp b/linphone/mediastreamer2/src/winsndds.cpp index d04b76bfa..391050e5a 100644 --- a/linphone/mediastreamer2/src/winsndds.cpp +++ b/linphone/mediastreamer2/src/winsndds.cpp @@ -146,6 +146,11 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; + MMRESULT mr = MMSYSERR_NOERROR; DWORD dwVolume = ((0xFFFF) * percent) / 100; @@ -163,10 +168,6 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe case MS_SND_CARD_PLAYBACK: case MS_SND_CARD_MASTER: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); if ( mr != MMSYSERR_NOERROR ) @@ -208,6 +209,11 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (mr != MMSYSERR_NOERROR) + { + ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr); + return; + } mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */ @@ -234,7 +240,7 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe ms_error("winsndcard_set_level: mixerGetID failed. (0x%x)", mr); return; } - mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L ); + mr = mixerOpen( (LPHMIXER)&dwMixerHandle, uMixerID, 0L, 0L, 0L ); if ( mr != MMSYSERR_NOERROR ) { mixerClose( (HMIXER)dwMixerHandle ); @@ -251,10 +257,48 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe ms_error("winsndcard_set_level: mixerGetLineInfo failed. (0x%x)", mr); return; } + /* ms_message("Name: %s\n", MixerLine.szName); */ /* ms_message("Source Line: %d\n", MixerLine.dwSource); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ + mlc.cbStruct = sizeof(MIXERLINECONTROLS); + mlc.dwLineID = MixerLine.dwLineID; + mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mlc.cControls = 1; + mlc.pamxctrl = &mc; + mlc.cbmxctrl = sizeof(MIXERCONTROL); + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, + &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + + if (mr == MMSYSERR_NOERROR) + { + mcdu.dwValue = 65535*percent/100; /* the volume is a number between 0 and 65535 */ + + mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mcd.hwndOwner = 0; + mcd.dwControlID = mc.dwControlID; + mcd.paDetails = &mcdu; + mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mcd.cChannels = 1; + mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, + &mcd, MIXER_SETCONTROLDETAILSF_VALUE); + + if (mr == MMSYSERR_NOERROR) + { + return; + } + ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr); + ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead"); + } + else + { + ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr); + ms_warning("winsndcard_set_level: control the SRC_MICROPHONE instead"); + } + + /* In case capture doesn't work: use the SRC_MICROPHONE volume */ + for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++) { memset( &Line, 0, sizeof(MIXERLINE) ); @@ -294,36 +338,48 @@ static void winsnddscard_set_level(MSSndCard *card, MSSndCardMixerElem e, int pe if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) { LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL)); - MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl}; - if(!mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, - MIXER_GETLINECONTROLSF_ONEBYTYPE)){ - DWORD cChannels = Line.cChannels; - LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned; - MIXERCONTROLDETAILS mxcd; - if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) - cChannels = 1; - pUnsigned = - (LPMIXERCONTROLDETAILS_UNSIGNED) - malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); + MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl}; + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, &mxlctrl, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if(!mr){ + DWORD cChannels = Line.cChannels; + LPMIXERCONTROLDETAILS_UNSIGNED pUnsigned; + MIXERCONTROLDETAILS mxcd; + if (MIXERCONTROL_CONTROLF_UNIFORM & pmxctrl->fdwControl) + cChannels = 1; + pUnsigned = + (LPMIXERCONTROLDETAILS_UNSIGNED) + malloc(cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED)); - mxcd.cbStruct = sizeof(mxcd); - mxcd.dwControlID = pmxctrl->dwControlID; - mxcd.cChannels = cChannels; - mxcd.hwndOwner = (HWND)0; - mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); - mxcd.paDetails = (LPVOID) pUnsigned; + mxcd.cbStruct = sizeof(mxcd); + mxcd.dwControlID = pmxctrl->dwControlID; + mxcd.cChannels = cChannels; + mxcd.hwndOwner = (HWND)0; + mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mxcd.paDetails = (LPVOID) pUnsigned; - mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, - MIXER_SETCONTROLDETAILSF_VALUE); + mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, + MIXER_SETCONTROLDETAILSF_VALUE); + if(!mr){ pUnsigned[0].dwValue = pUnsigned[cChannels - 1].dwValue = pmxctrl->Bounds.dwMaximum*percent/100; - mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, + mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE); - free(pmxctrl); - free(pUnsigned); + if(mr){ + ms_error("winsndcard_set_level: mixerSetControlDetails failed. (0x%x)", mr); + } + } + else + { + ms_error("winsndcard_set_level: mixerGetControlDetails failed. (0x%x)", mr); + } + free(pmxctrl); + free(pUnsigned); } else - free(pmxctrl); + { + ms_error("winsndcard_set_level: mixerGetLineControls failed. (0x%x)", mr); + free(pmxctrl); + } } } mixerClose( (HMIXER)dwMixerHandle ); @@ -349,6 +405,11 @@ static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; + MMRESULT mr = MMSYSERR_NOERROR; int percent; @@ -359,11 +420,6 @@ static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ case MS_SND_CARD_MASTER: case MS_SND_CARD_PLAYBACK: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_UNSIGNED mcdu = {0}; - mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); if ( mr != MMSYSERR_NOERROR ) { @@ -456,6 +512,39 @@ static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ /* ms_message("Source Line: %d\n", MixerLine.dwSource); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ + mlc.cbStruct = sizeof(MIXERLINECONTROLS); + mlc.dwLineID = MixerLine.dwLineID; + mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mlc.cControls = 1; + mlc.pamxctrl = &mc; + mlc.cbmxctrl = sizeof(MIXERCONTROL); + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, + &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (mr == MMSYSERR_NOERROR) + { + mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mcd.hwndOwner = 0; + mcd.dwControlID = mc.dwControlID; + mcd.paDetails = &mcdu; + mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + mcd.cChannels = 1; + mr = mixerGetControlDetails((HMIXEROBJ)dwMixerHandle, &mcd, + MIXER_SETCONTROLDETAILSF_VALUE); + percent = (mcdu.dwValue *100) / (mc.Bounds.dwMaximum); + + if (mr == MMSYSERR_NOERROR) + { + return percent; + } + ms_error("winsndcard_get_level: mixerGetControlDetails failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + else + { + ms_error("winsndcard_get_level: mixerGetLineControls failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++) { memset( &Line, 0, sizeof(MIXERLINE) ); @@ -492,7 +581,7 @@ static int winsnddscard_get_level(MSSndCard *card, MSSndCardMixerElem e){ /* ms_message("LineID: %d\n", MixerLine.dwLineID); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ - if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) + if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) { LPMIXERCONTROL pmxctrl = (LPMIXERCONTROL)malloc(sizeof(MIXERCONTROL)); MIXERLINECONTROLS mxlctrl = {sizeof(mxlctrl), Line.dwLineID, MIXERCONTROL_CONTROLTYPE_VOLUME, 1, sizeof(MIXERCONTROL), pmxctrl}; @@ -560,6 +649,11 @@ static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int MIXERLINE Line; UINT uLineIndex; + MIXERLINECONTROLS mlc = {0}; + MIXERCONTROL mc = {0}; + MIXERCONTROLDETAILS mcd = {0}; + MIXERCONTROLDETAILS_BOOLEAN bMute; + MMRESULT mr = MMSYSERR_NOERROR; GetWaveIdFromDSoundGUID(d->in_guid, &wavein_devid); @@ -567,6 +661,7 @@ static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int switch(e){ case MS_SND_CARD_CAPTURE_MUTE: + bMute.fValue = (val>0); mr = mixerGetID( (HMIXEROBJ)wavein_devid, &uMixerID, MIXER_OBJECTF_WAVEIN ); if ( mr != MMSYSERR_NOERROR ) @@ -595,6 +690,39 @@ static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int /* ms_message("Source Line: %d\n", MixerLine.dwSource); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ + mlc.cbStruct = sizeof(MIXERLINECONTROLS); + mlc.dwLineID = MixerLine.dwLineID; + mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; //MIXERCONTROL_CONTROLTYPE_VOLUME; + mlc.cControls = 1; + mlc.pamxctrl = &mc; + mlc.cbmxctrl = sizeof(MIXERCONTROL); + mr = mixerGetLineControls((HMIXEROBJ)dwMixerHandle, + &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (mr == MMSYSERR_NOERROR) + { + mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mcd.hwndOwner = 0; + mcd.dwControlID = mc.dwControlID; + mcd.paDetails = &bMute; + mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); + mcd.cChannels = 1; + mr = mixerSetControlDetails((HMIXEROBJ)dwMixerHandle, + &mcd, MIXER_SETCONTROLDETAILSF_VALUE); + + if (mr == MMSYSERR_NOERROR) + { + return 0; + } + ms_error("winsndcard_set_control: mixerSetControlDetails failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + else + { + ms_error("winsndcard_set_control: mixerGetLineControls failed. (0x%x)", mr); + ms_warning("winsndcard_get_level: control the SRC_MICROPHONE instead"); + } + + for (uLineIndex = 0; uLineIndex < MixerLine.cConnections; uLineIndex++) { memset( &Line, 0, sizeof(MIXERLINE) ); @@ -631,7 +759,7 @@ static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int /* ms_message("LineID: %d\n", MixerLine.dwLineID); */ /* ms_message("ComponentType: %d\n", MixerLine.dwComponentType); */ - if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) + if (MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE == Line.dwComponentType) { /* unmute */ /* Find a mute control, if any, of the microphone line */ @@ -679,11 +807,6 @@ static int winsnddscard_set_control(MSSndCard *card, MSSndCardControlElem e, int case MS_SND_CARD_MASTER_MUTE: case MS_SND_CARD_PLAYBACK_MUTE: { - MIXERLINECONTROLS mlc = {0}; - MIXERCONTROL mc = {0}; - MIXERCONTROLDETAILS mcd = {0}; - MIXERCONTROLDETAILS_BOOLEAN bMute; - bMute.fValue = (val>0); mr = mixerGetID( (HMIXEROBJ)waveout_devid, &uMixerID, MIXER_OBJECTF_WAVEOUT ); @@ -775,7 +898,7 @@ MSSndCardDesc winsndds_card_desc={ winsnddscard_set_level, winsnddscard_get_level, winsnddscard_set_source, - NULL, + winsnddscard_set_control, NULL, ms_winsndds_read_new, ms_winsndds_write_new,