| /* | |
| * 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 <stdarg.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <math.h> | |
| #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(HMIXEROBJ mix, MIXERCONTROLA *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.cbDetails = sizeof(value); | |
| /* test NULL paDetails */ | |
| details.paDetails = NULL; | |
| rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| /* read the current control value */ | |
| details.paDetails = &value; | |
| rc = mixerGetControlDetailsA(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(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 = mixerGetControlDetailsA(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(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 = mixerGetControlDetailsA(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(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 = mixerGetControlDetailsA(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(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; | |
| HMIXEROBJ 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((HMIXER*)&mix, device, 0, 0, 0); | |
| ok(rc==MMSYSERR_NOERROR, | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); | |
| if (rc==MMSYSERR_NOERROR) { | |
| MIXERCAPSA capsA2; | |
| rc=mixerGetDevCapsA((UINT_PTR)mix,&capsA2,sizeof(capsA2)); | |
| ok(rc==MMSYSERR_NOERROR, | |
| "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| ok(!strcmp(capsA2.szPname, capsA.szPname), "Got wrong device caps\n"); | |
| for (d=0;d<capsA.cDestinations;d++) { | |
| MIXERLINEA mixerlineA; | |
| mixerlineA.cbStruct = 0; | |
| mixerlineA.dwDestination=d; | |
| rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineA.cbStruct = sizeof(mixerlineA); | |
| mixerlineA.dwDestination=capsA.cDestinations; | |
| rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE, | |
| "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineA.cbStruct = sizeof(mixerlineA); | |
| mixerlineA.dwDestination=d; | |
| rc = mixerGetLineInfoA(mix, 0, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineA.cbStruct = sizeof(mixerlineA); | |
| mixerlineA.dwDestination=d; | |
| rc = mixerGetLineInfoA(mix, &mixerlineA, -1); | |
| ok(rc==MMSYSERR_INVALFLAG, | |
| "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineA.cbStruct = sizeof(mixerlineA); | |
| mixerlineA.dwDestination=d; | |
| mixerlineA.dwUser = (ULONG_PTR)0xdeadbeef; | |
| rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER, | |
| "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| ok(mixerlineA.dwUser == 0, "dwUser was not reset\n"); | |
| if (rc==MMSYSERR_NODRIVER) | |
| trace(" No Driver\n"); | |
| else if (rc==MMSYSERR_NOERROR) { | |
| if (winetest_interactive) { | |
| trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n", | |
| d,mixerlineA.szShortName, mixerlineA.szName, | |
| mixerlineA.dwDestination,mixerlineA.dwSource); | |
| trace(" LineID=%08x Channels=%d " | |
| "Connections=%d Controls=%d\n", | |
| mixerlineA.dwLineID,mixerlineA.cChannels, | |
| mixerlineA.cConnections,mixerlineA.cControls); | |
| trace(" State=0x%08x(%s)\n", | |
| mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine)); | |
| trace(" ComponentType=%s\n", | |
| component_type(mixerlineA.dwComponentType)); | |
| trace(" Type=%s\n", | |
| target_type(mixerlineA.Target.dwType)); | |
| trace(" Device=%d (%s) %d.%d (%d:%d)\n", | |
| mixerlineA.Target.dwDeviceID, | |
| mixerlineA.Target.szPname, | |
| mixerlineA.Target.vDriverVersion >> 8, | |
| mixerlineA.Target.vDriverVersion & 0xff, | |
| mixerlineA.Target.wMid, mixerlineA.Target.wPid); | |
| } | |
| ns=mixerlineA.cConnections; | |
| for(s=0;s<ns;s++) { | |
| mixerlineA.cbStruct = sizeof(mixerlineA); | |
| mixerlineA.dwDestination=d; | |
| mixerlineA.dwSource=s; | |
| rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_SOURCE); | |
| ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER, | |
| "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): " | |
| "MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc==MMSYSERR_NODRIVER) | |
| trace(" No Driver\n"); | |
| else if (rc==MMSYSERR_NOERROR) { | |
| LPMIXERCONTROLA array; | |
| MIXERLINECONTROLSA controls; | |
| if (winetest_interactive) { | |
| trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n", | |
| s,mixerlineA.szShortName, mixerlineA.szName, | |
| mixerlineA.dwDestination,mixerlineA.dwSource); | |
| trace(" LineID=%08x Channels=%d " | |
| "Connections=%d Controls=%d\n", | |
| mixerlineA.dwLineID,mixerlineA.cChannels, | |
| mixerlineA.cConnections,mixerlineA.cControls); | |
| trace(" State=0x%08x(%s)\n", | |
| mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine)); | |
| trace(" ComponentType=%s\n", | |
| component_type(mixerlineA.dwComponentType)); | |
| trace(" Type=%s\n", | |
| target_type(mixerlineA.Target.dwType)); | |
| trace(" Device=%d (%s) %d.%d (%d:%d)\n", | |
| mixerlineA.Target.dwDeviceID, | |
| mixerlineA.Target.szPname, | |
| mixerlineA.Target.vDriverVersion >> 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(mix, 0, MIXER_GETLINECONTROLSF_ALL); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| rc = mixerGetLineControlsA(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(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;nc<mixerlineA.cControls;nc++) { | |
| if (winetest_interactive) { | |
| trace(" %d: \"%s\" (%s) ControlID=%d\n", nc, | |
| array[nc].szShortName, | |
| array[nc].szName, array[nc].dwControlID); | |
| trace(" ControlType=%s\n", | |
| control_type(array[nc].dwControlType)); | |
| trace(" Control=0x%08x(%s)\n", | |
| array[nc].fdwControl, | |
| control_flags(array[nc].fdwControl)); | |
| trace(" Items=%d Min=%d Max=%d Step=%d\n", | |
| array[nc].cMultipleItems, | |
| S1(array[nc].Bounds).dwMinimum, | |
| S1(array[nc].Bounds).dwMaximum, | |
| array[nc].Metrics.cSteps); | |
| } | |
| mixer_test_controlA(mix, &array[nc]); | |
| } | |
| } | |
| HeapFree(GetProcessHeap(),0,array); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| test_mixerClose((HMIXER)mix); | |
| } | |
| } | |
| static void mixer_test_controlW(HMIXEROBJ mix, MIXERCONTROLW *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 = mixerGetControlDetailsW(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(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 = mixerGetControlDetailsW(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(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 = mixerGetControlDetailsW(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(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 = mixerGetControlDetailsW(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(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; | |
| HMIXEROBJ 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((HMIXER*)&mix, device, 0, 0, 0); | |
| ok(rc==MMSYSERR_NOERROR, | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc)); | |
| if (rc==MMSYSERR_NOERROR) { | |
| MIXERCAPSW capsW2; | |
| rc=mixerGetDevCapsW((UINT_PTR)mix,&capsW2,sizeof(capsW2)); | |
| ok(rc==MMSYSERR_NOERROR, | |
| "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| ok(!lstrcmpW(capsW2.szPname, capsW.szPname), "Got wrong device caps\n"); | |
| for (d=0;d<capsW.cDestinations;d++) { | |
| MIXERLINEW mixerlineW; | |
| mixerlineW.cbStruct = 0; | |
| mixerlineW.dwDestination=d; | |
| rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineW.cbStruct = sizeof(mixerlineW); | |
| mixerlineW.dwDestination=capsW.cDestinations; | |
| rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE, | |
| "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineW.cbStruct = sizeof(mixerlineW); | |
| mixerlineW.dwDestination=d; | |
| rc = mixerGetLineInfoW(mix, 0, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineW.cbStruct = sizeof(mixerlineW); | |
| mixerlineW.dwDestination=d; | |
| rc = mixerGetLineInfoW(mix, &mixerlineW, -1); | |
| ok(rc==MMSYSERR_INVALFLAG, | |
| "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n", | |
| mmsys_error(rc)); | |
| mixerlineW.cbStruct = sizeof(mixerlineW); | |
| mixerlineW.dwDestination=d; | |
| mixerlineW.dwUser = (ULONG_PTR)0xdeadbeef; | |
| rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION); | |
| ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER, | |
| "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): " | |
| "MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| ok(mixerlineW.dwUser == 0, "dwUser was not reset\n"); | |
| if (rc==MMSYSERR_NODRIVER) | |
| trace(" No Driver\n"); | |
| else if (rc==MMSYSERR_NOERROR && winetest_interactive) { | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName, | |
| MIXER_SHORT_NAME_CHARS,szShortName, | |
| MIXER_SHORT_NAME_CHARS,NULL,NULL); | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.szName, | |
| MIXER_LONG_NAME_CHARS,szName, | |
| MIXER_LONG_NAME_CHARS,NULL,NULL); | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname, | |
| MAXPNAMELEN,szPname, | |
| MAXPNAMELEN,NULL, NULL); | |
| trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n", | |
| d,szShortName,szName, | |
| mixerlineW.dwDestination,mixerlineW.dwSource); | |
| trace(" LineID=%08x Channels=%d " | |
| "Connections=%d Controls=%d\n", | |
| mixerlineW.dwLineID,mixerlineW.cChannels, | |
| mixerlineW.cConnections,mixerlineW.cControls); | |
| trace(" State=0x%08x(%s)\n", | |
| mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine)); | |
| trace(" ComponentType=%s\n", | |
| component_type(mixerlineW.dwComponentType)); | |
| trace(" Type=%s\n", | |
| target_type(mixerlineW.Target.dwType)); | |
| trace(" Device=%d (%s) %d.%d (%d:%d)\n", | |
| mixerlineW.Target.dwDeviceID,szPname, | |
| mixerlineW.Target.vDriverVersion >> 8, | |
| mixerlineW.Target.vDriverVersion & 0xff, | |
| mixerlineW.Target.wMid, mixerlineW.Target.wPid); | |
| } | |
| ns=mixerlineW.cConnections; | |
| for(s=0;s<ns;s++) { | |
| mixerlineW.cbStruct = sizeof(mixerlineW); | |
| mixerlineW.dwDestination=d; | |
| mixerlineW.dwSource=s; | |
| rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_SOURCE); | |
| ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER, | |
| "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): " | |
| "MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc==MMSYSERR_NODRIVER) | |
| trace(" No Driver\n"); | |
| else if (rc==MMSYSERR_NOERROR) { | |
| LPMIXERCONTROLW array; | |
| MIXERLINECONTROLSW controls; | |
| if (winetest_interactive) { | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName, | |
| MIXER_SHORT_NAME_CHARS,szShortName, | |
| MIXER_SHORT_NAME_CHARS,NULL,NULL); | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.szName, | |
| MIXER_LONG_NAME_CHARS,szName, | |
| MIXER_LONG_NAME_CHARS,NULL,NULL); | |
| WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname, | |
| MAXPNAMELEN,szPname, | |
| MAXPNAMELEN,NULL, NULL); | |
| trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n", | |
| s,szShortName,szName, | |
| mixerlineW.dwDestination,mixerlineW.dwSource); | |
| trace(" LineID=%08x Channels=%d " | |
| "Connections=%d Controls=%d\n", | |
| mixerlineW.dwLineID,mixerlineW.cChannels, | |
| mixerlineW.cConnections,mixerlineW.cControls); | |
| trace(" State=0x%08x(%s)\n", | |
| mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine)); | |
| trace(" ComponentType=%s\n", | |
| component_type(mixerlineW.dwComponentType)); | |
| trace(" Type=%s\n", | |
| target_type(mixerlineW.Target.dwType)); | |
| trace(" Device=%d (%s) %d.%d (%d:%d)\n", | |
| mixerlineW.Target.dwDeviceID,szPname, | |
| mixerlineW.Target.vDriverVersion >> 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(mix, 0, MIXER_GETLINECONTROLSF_ALL); | |
| ok(rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): " | |
| "MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| rc = mixerGetLineControlsW(mix, &controls, -1); | |
| ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM, | |
| "mixerGetLineControlsW(-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(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<mixerlineW.cControls;nc++) { | |
| if (winetest_interactive) { | |
| WideCharToMultiByte(CP_ACP,0,array[nc].szShortName, | |
| MIXER_SHORT_NAME_CHARS,szShortName, | |
| MIXER_SHORT_NAME_CHARS,NULL,NULL); | |
| WideCharToMultiByte(CP_ACP,0,array[nc].szName, | |
| MIXER_LONG_NAME_CHARS,szName, | |
| MIXER_LONG_NAME_CHARS,NULL,NULL); | |
| trace(" %d: \"%s\" (%s) ControlID=%d\n", nc, | |
| szShortName, szName, array[nc].dwControlID); | |
| trace(" ControlType=%s\n", | |
| control_type(array[nc].dwControlType)); | |
| trace(" Control=0x%08x(%s)\n", | |
| array[nc].fdwControl, | |
| control_flags(array[nc].fdwControl)); | |
| trace(" Items=%d Min=%d Max=%d Step=%d\n", | |
| array[nc].cMultipleItems, | |
| S1(array[nc].Bounds).dwMinimum, | |
| S1(array[nc].Bounds).dwMaximum, | |
| array[nc].Metrics.cSteps); | |
| } | |
| mixer_test_controlW(mix, &array[nc]); | |
| } | |
| } | |
| HeapFree(GetProcessHeap(),0,array); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| test_mixerClose((HMIXER)mix); | |
| } | |
| } | |
| static void mixer_testsA(void) | |
| { | |
| MIXERCAPSA capsA; | |
| MMRESULT rc; | |
| UINT ndev, d; | |
| trace("--- Testing ASCII functions ---\n"); | |
| ndev=mixerGetNumDevs(); | |
| trace("found %d Mixer devices\n",ndev); | |
| rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA)); | |
| ok(rc==MMSYSERR_BADDEVICEID, | |
| "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n", | |
| mmsys_error(rc)); | |
| for (d=0;d<ndev;d++) | |
| mixer_test_deviceA(d); | |
| } | |
| static void mixer_testsW(void) | |
| { | |
| MIXERCAPSW capsW; | |
| MMRESULT rc; | |
| UINT ndev, d; | |
| trace("--- Testing WCHAR functions ---\n"); | |
| ndev=mixerGetNumDevs(); | |
| trace("found %d Mixer devices\n",ndev); | |
| rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW)); | |
| ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED, | |
| "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED " | |
| "expected, got %s\n", mmsys_error(rc)); | |
| if (rc==MMSYSERR_NOTSUPPORTED) | |
| return; | |
| for (d=0;d<ndev;d++) | |
| mixer_test_deviceW(d); | |
| } | |
| static void test_mixerOpen(void) | |
| { | |
| HMIXER mix; | |
| HANDLE event; | |
| MMRESULT rc; | |
| UINT ndev, d; | |
| ndev = mixerGetNumDevs(); | |
| /* Test mixerOpen with invalid device ID values. */ | |
| rc = mixerOpen(&mix, ndev + 1, 0, 0, 0); | |
| ok(rc == MMSYSERR_BADDEVICEID, | |
| "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n", | |
| mmsys_error(rc)); | |
| rc = mixerOpen(&mix, -1, 0, 0, 0); | |
| ok(rc == MMSYSERR_BADDEVICEID || | |
| rc == MMSYSERR_INVALHANDLE, /* NT4/W2K */ | |
| "mixerOpen: MMSYSERR_BADDEVICEID or MMSYSERR_INVALHANDLE expected, got %s\n", | |
| mmsys_error(rc)); | |
| for (d = 0; d < ndev; d++) { | |
| /* Test mixerOpen with valid device ID values and invalid parameters. */ | |
| rc = mixerOpen(&mix, d, 0, 0, CALLBACK_FUNCTION); | |
| ok(rc == MMSYSERR_INVALFLAG | |
| || rc == MMSYSERR_NOTSUPPORTED, /* 98/ME */ | |
| "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n", | |
| mmsys_error(rc)); | |
| rc = mixerOpen(&mix, d, 0xdeadbeef, 0, CALLBACK_WINDOW); | |
| ok(rc == MMSYSERR_INVALPARAM || | |
| broken(rc == MMSYSERR_NOERROR /* 98 */), | |
| "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| /* Test mixerOpen with a NULL dwCallback and CALLBACK_WINDOW flag. */ | |
| rc = mixerOpen(&mix, d, 0, 0, CALLBACK_WINDOW); | |
| ok(rc == MMSYSERR_NOERROR, | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| rc = mixerOpen(&mix, d, 0, 0, CALLBACK_THREAD); | |
| ok(rc == MMSYSERR_NOERROR /* since w2k */ || | |
| rc == MMSYSERR_NOTSUPPORTED, /* 98 */ | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| rc = mixerOpen(&mix, d, 0, 0, CALLBACK_EVENT); | |
| ok(rc == MMSYSERR_NOERROR /* since w2k */ || | |
| rc == MMSYSERR_NOTSUPPORTED, /* 98 */ | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| event = CreateEventW(NULL, FALSE, FALSE, NULL); | |
| /* NOTSUPPORTED is not broken, but it enables the todo_wine marker. */ | |
| rc = mixerOpen(&mix, d, (DWORD_PTR)event, 0, CALLBACK_EVENT); | |
| todo_wine | |
| ok(rc == MMSYSERR_NOERROR /* since w2k */ || | |
| broken(rc == MMSYSERR_NOTSUPPORTED), /* 98 */ | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| /* Test mixerOpen with normal parameters. */ | |
| rc = mixerOpen(&mix, d, 0, 0, 0); | |
| ok(rc == MMSYSERR_NOERROR, | |
| "mixerOpen: MMSYSERR_NOERROR expected, got %s\n", | |
| mmsys_error(rc)); | |
| if (rc == MMSYSERR_NOERROR) | |
| test_mixerClose(mix); | |
| rc = WaitForSingleObject(event, 0); | |
| ok(rc == WAIT_TIMEOUT, "WaitEvent %d\n", rc); | |
| CloseHandle(event); | |
| } | |
| } | |
| START_TEST(mixer) | |
| { | |
| test_mixerOpen(); | |
| mixer_testsA(); | |
| mixer_testsW(); | |
| } |