/* * Test mixer * * Copyright (c) 2004 Robert Reif * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* * To Do: * add interactive tests */ #include #include #include #include #include "wine/test.h" #include "windef.h" #include "winbase.h" #include "winnls.h" #include "mmsystem.h" #include "winmm_test.h" static const char * line_flags(DWORD fdwLine) { static char flags[100]; BOOL first=TRUE; flags[0]=0; if (fdwLine&MIXERLINE_LINEF_ACTIVE) { strcat(flags,"MIXERLINE_LINEF_ACTIVE"); first=FALSE; } if (fdwLine&MIXERLINE_LINEF_DISCONNECTED) { if (!first) strcat(flags, "|"); strcat(flags,"MIXERLINE_LINEF_DISCONNECTED"); first=FALSE; } if (fdwLine&MIXERLINE_LINEF_SOURCE) { if (!first) strcat(flags, "|"); strcat(flags,"MIXERLINE_LINEF_SOURCE"); } return flags; } static const char * component_type(DWORD dwComponentType) { #define TYPE_TO_STR(x) case x: return #x switch (dwComponentType) { TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_UNDEFINED); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_DIGITAL); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_LINE); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_MONITOR); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_HEADPHONES); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_TELEPHONE); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_WAVEIN); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_VOICEIN); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_DIGITAL); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_LINE); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY); TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_ANALOG); } #undef TYPE_TO_STR return "UNKNOWN"; } static const char * target_type(DWORD dwType) { #define TYPE_TO_STR(x) case x: return #x switch (dwType) { TYPE_TO_STR(MIXERLINE_TARGETTYPE_UNDEFINED); TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEOUT); TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEIN); TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIOUT); TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIIN); TYPE_TO_STR(MIXERLINE_TARGETTYPE_AUX); } #undef TYPE_TO_STR return "UNKNOWN"; } static const char * control_type(DWORD dwControlType) { #define TYPE_TO_STR(x) case x: return #x switch (dwControlType) { TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME); TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME); } #undef TYPE_TO_STR return "UNKNOWN"; } static const char * control_flags(DWORD fdwControl) { static char flags[100]; BOOL first=TRUE; flags[0]=0; if (fdwControl&MIXERCONTROL_CONTROLF_UNIFORM) { strcat(flags,"MIXERCONTROL_CONTROLF_UNIFORM"); first=FALSE; } if (fdwControl&MIXERCONTROL_CONTROLF_MULTIPLE) { if (!first) strcat(flags, "|"); strcat(flags,"MIXERCONTROL_CONTROLF_MULTIPLE"); first=FALSE; } if (fdwControl&MIXERCONTROL_CONTROLF_DISABLED) { if (!first) strcat(flags, "|"); strcat(flags,"MIXERCONTROL_CONTROLF_DISABLED"); } return flags; } static void test_mixerClose(HMIXER mix) { MMRESULT rc; rc = mixerClose(mix); ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_INVALHANDLE, "mixerClose: MMSYSERR_NOERROR or MMSYSERR_INVALHANDLE expected, got %s\n", mmsys_error(rc)); } static void mixer_test_controlA(HMIXER mix, LPMIXERCONTROLA control) { MMRESULT rc; if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) { MIXERCONTROLDETAILS details; MIXERCONTROLDETAILS_UNSIGNED value; details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* read the current control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR && winetest_interactive) { MIXERCONTROLDETAILS new_details; MIXERCONTROLDETAILS_UNSIGNED new_value; trace(" Value=%d\n",value.dwValue); if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum) new_value.dwValue = value.dwValue + control->Metrics.cSteps; else new_value.dwValue = value.dwValue - control->Metrics.cSteps; new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); new_details.dwControlID = control->dwControlID; new_details.cChannels = 1; U(new_details).cMultipleItems = 0; new_details.paDetails = &new_value; new_details.cbDetails = sizeof(new_value); /* change the control value by one step */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { MIXERCONTROLDETAILS ret_details; MIXERCONTROLDETAILS_UNSIGNED ret_value; ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); ret_details.dwControlID = control->dwControlID; ret_details.cChannels = 1; U(ret_details).cMultipleItems = 0; ret_details.paDetails = &ret_value; ret_details.cbDetails = sizeof(ret_value); /* read back the new control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { /* result may not match exactly because of rounding */ ok(abs(ret_value.dwValue-new_value.dwValue)<=1, "Couldn't change value from %d to %d, returned %d\n", value.dwValue,new_value.dwValue,ret_value.dwValue); if (abs(ret_value.dwValue-new_value.dwValue)<=1) { details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* restore original value */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); } } } } } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) { MIXERCONTROLDETAILS details; MIXERCONTROLDETAILS_BOOLEAN value; details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR && winetest_interactive) { MIXERCONTROLDETAILS new_details; MIXERCONTROLDETAILS_BOOLEAN new_value; trace(" Value=%d\n",value.fValue); if (value.fValue == FALSE) new_value.fValue = TRUE; else new_value.fValue = FALSE; new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); new_details.dwControlID = control->dwControlID; new_details.cChannels = 1; U(new_details).cMultipleItems = 0; new_details.paDetails = &new_value; new_details.cbDetails = sizeof(new_value); /* change the control value by one step */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { MIXERCONTROLDETAILS ret_details; MIXERCONTROLDETAILS_BOOLEAN ret_value; ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); ret_details.dwControlID = control->dwControlID; ret_details.cChannels = 1; U(ret_details).cMultipleItems = 0; ret_details.paDetails = &ret_value; ret_details.cbDetails = sizeof(ret_value); /* read back the new control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { /* result may not match exactly because of rounding */ ok(ret_value.fValue==new_value.fValue, "Couldn't change value from %d to %d, returned %d\n", value.fValue,new_value.fValue,ret_value.fValue); if (ret_value.fValue==new_value.fValue) { details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* restore original value */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); } } } } } else { /* FIXME */ } } static void mixer_test_deviceA(int device) { MIXERCAPSA capsA; HMIXER mix; MMRESULT rc; DWORD d,s,ns,nc; rc=mixerGetDevCapsA(device,0,sizeof(capsA)); ok(rc==MMSYSERR_INVALPARAM, "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); rc=mixerGetDevCapsA(device,&capsA,4); ok(rc==MMSYSERR_NOERROR, "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA)); ok(rc==MMSYSERR_NOERROR, "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (winetest_interactive) { trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device, capsA.szPname, capsA.vDriverVersion >> 8, capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid, capsA.cDestinations); } else { trace(" %d: \"%s\" %d.%d (%d:%d)\n", device, capsA.szPname, capsA.vDriverVersion >> 8, capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid); } rc=mixerOpen(&mix, device, 0, 0, 0); ok(rc==MMSYSERR_NOERROR, "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { for (d=0;d> 8, mixerlineA.Target.vDriverVersion & 0xff, mixerlineA.Target.wMid, mixerlineA.Target.wPid); } ns=mixerlineA.cConnections; for(s=0;s> 8, mixerlineA.Target.vDriverVersion & 0xff, mixerlineA.Target.wMid, mixerlineA.Target.wPid); } if (mixerlineA.cControls) { array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, mixerlineA.cControls*sizeof(MIXERCONTROLA)); if (array) { memset(&controls, 0, sizeof(controls)); rc=mixerGetLineControlsA((HMIXEROBJ)mix,0, MIXER_GETLINECONTROLSF_ALL); ok(rc==MMSYSERR_INVALPARAM, "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): " "MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,-1); ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM, "mixerGetLineControlsA(-1): " "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); controls.cbStruct = sizeof(MIXERLINECONTROLSA); controls.cControls = mixerlineA.cControls; controls.dwLineID = mixerlineA.dwLineID; controls.pamxctrl = array; controls.cbmxctrl = sizeof(MIXERCONTROLA); /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID * and MIXER_GETLINECONTROLSF_ONEBYTYPE */ rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls, MIXER_GETLINECONTROLSF_ALL); ok(rc==MMSYSERR_NOERROR, "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { for(nc=0;ncdwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) { MIXERCONTROLDETAILS details; MIXERCONTROLDETAILS_UNSIGNED value; details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* read the current control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR && winetest_interactive) { MIXERCONTROLDETAILS new_details; MIXERCONTROLDETAILS_UNSIGNED new_value; trace(" Value=%d\n",value.dwValue); if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum) new_value.dwValue = value.dwValue + control->Metrics.cSteps; else new_value.dwValue = value.dwValue - control->Metrics.cSteps; new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); new_details.dwControlID = control->dwControlID; new_details.cChannels = 1; U(new_details).cMultipleItems = 0; new_details.paDetails = &new_value; new_details.cbDetails = sizeof(new_value); /* change the control value by one step */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { MIXERCONTROLDETAILS ret_details; MIXERCONTROLDETAILS_UNSIGNED ret_value; ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); ret_details.dwControlID = control->dwControlID; ret_details.cChannels = 1; U(ret_details).cMultipleItems = 0; ret_details.paDetails = &ret_value; ret_details.cbDetails = sizeof(ret_value); /* read back the new control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { /* result may not match exactly because of rounding */ ok(abs(ret_value.dwValue-new_value.dwValue)<=1, "Couldn't change value from %d to %d, returned %d\n", value.dwValue,new_value.dwValue,ret_value.dwValue); if (abs(ret_value.dwValue-new_value.dwValue)<=1) { details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* restore original value */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); } } } } } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) || (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) { MIXERCONTROLDETAILS details; MIXERCONTROLDETAILS_BOOLEAN value; details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR && winetest_interactive) { MIXERCONTROLDETAILS new_details; MIXERCONTROLDETAILS_BOOLEAN new_value; trace(" Value=%d\n",value.fValue); if (value.fValue == FALSE) new_value.fValue = TRUE; else new_value.fValue = FALSE; new_details.cbStruct = sizeof(MIXERCONTROLDETAILS); new_details.dwControlID = control->dwControlID; new_details.cChannels = 1; U(new_details).cMultipleItems = 0; new_details.paDetails = &new_value; new_details.cbDetails = sizeof(new_value); /* change the control value by one step */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { MIXERCONTROLDETAILS ret_details; MIXERCONTROLDETAILS_BOOLEAN ret_value; ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS); ret_details.dwControlID = control->dwControlID; ret_details.cChannels = 1; U(ret_details).cMultipleItems = 0; ret_details.paDetails = &ret_value; ret_details.cbDetails = sizeof(ret_value); /* read back the new control value */ rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { /* result may not match exactly because of rounding */ ok(ret_value.fValue==new_value.fValue, "Couldn't change value from %d to %d, returned %d\n", value.fValue,new_value.fValue,ret_value.fValue); if (ret_value.fValue==new_value.fValue) { details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = control->dwControlID; details.cChannels = 1; U(details).cMultipleItems = 0; details.paDetails = &value; details.cbDetails = sizeof(value); /* restore original value */ rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE); ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); } } } } } else { /* FIXME */ } } static void mixer_test_deviceW(int device) { MIXERCAPSW capsW; HMIXER mix; MMRESULT rc; DWORD d,s,ns,nc; char szShortName[MIXER_SHORT_NAME_CHARS]; char szName[MIXER_LONG_NAME_CHARS]; char szPname[MAXPNAMELEN]; rc=mixerGetDevCapsW(device,0,sizeof(capsW)); ok(rc==MMSYSERR_INVALPARAM, "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); rc=mixerGetDevCapsW(device,&capsW,4); ok(rc==MMSYSERR_NOERROR || rc==MMSYSERR_INVALPARAM, /* Vista and W2K8 */ "mixerGetDevCapsW: MMSYSERR_NOERROR or MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW)); ok(rc==MMSYSERR_NOERROR, "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname, MAXPNAMELEN,NULL,NULL); if (winetest_interactive) { trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device, szPname, capsW.vDriverVersion >> 8, capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid, capsW.cDestinations); } else { trace(" %d: \"%s\" %d.%d (%d:%d)\n", device, szPname, capsW.vDriverVersion >> 8, capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid); } rc=mixerOpen(&mix, device, 0, 0, 0); ok(rc==MMSYSERR_NOERROR, "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { for (d=0;d> 8, mixerlineW.Target.vDriverVersion & 0xff, mixerlineW.Target.wMid, mixerlineW.Target.wPid); } ns=mixerlineW.cConnections; for(s=0;s> 8, mixerlineW.Target.vDriverVersion & 0xff, mixerlineW.Target.wMid, mixerlineW.Target.wPid); } if (mixerlineW.cControls) { array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, mixerlineW.cControls*sizeof(MIXERCONTROLW)); if (array) { rc=mixerGetLineControlsW((HMIXEROBJ)mix,0, MIXER_GETLINECONTROLSF_ALL); ok(rc==MMSYSERR_INVALPARAM, "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): " "MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls, -1); ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM, "mixerGetLineControlsA(-1): " "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc)); controls.cbStruct = sizeof(MIXERLINECONTROLSW); controls.cControls = mixerlineW.cControls; controls.dwLineID = mixerlineW.dwLineID; controls.pamxctrl = array; controls.cbmxctrl = sizeof(MIXERCONTROLW); /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID * and MIXER_GETLINECONTROLSF_ONEBYTYPE */ rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls, MIXER_GETLINECONTROLSF_ALL); ok(rc==MMSYSERR_NOERROR, "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): " "MMSYSERR_NOERROR expected, got %s\n", mmsys_error(rc)); if (rc==MMSYSERR_NOERROR) { for(nc=0;nc