gdi32/tests: Mark tests failing randomly on Windows as flaky.
[wine.git] / dlls / winmm / tests / mixer.c
blob5ab0d4a698db8236f7dc2b1b0f71418126993a03
1 /*
2 * Test mixer
4 * Copyright (c) 2004 Robert Reif
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * To Do:
23 * add interactive tests
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <math.h>
31 #include "wine/test.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "mmsystem.h"
37 #include "winmm_test.h"
39 static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
41 unsigned int diff = x > y ? x - y : y - x;
42 return diff <= max_diff;
45 static const char * line_flags(DWORD fdwLine)
47 static char flags[100];
48 BOOL first=TRUE;
49 flags[0]=0;
50 if (fdwLine&MIXERLINE_LINEF_ACTIVE) {
51 strcat(flags,"MIXERLINE_LINEF_ACTIVE");
52 first=FALSE;
54 if (fdwLine&MIXERLINE_LINEF_DISCONNECTED) {
55 if (!first)
56 strcat(flags, "|");
58 strcat(flags,"MIXERLINE_LINEF_DISCONNECTED");
59 first=FALSE;
62 if (fdwLine&MIXERLINE_LINEF_SOURCE) {
63 if (!first)
64 strcat(flags, "|");
66 strcat(flags,"MIXERLINE_LINEF_SOURCE");
69 return flags;
72 static const char * component_type(DWORD dwComponentType)
74 #define TYPE_TO_STR(x) case x: return #x
75 switch (dwComponentType) {
76 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_UNDEFINED);
77 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_DIGITAL);
78 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_LINE);
79 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_MONITOR);
80 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
81 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_HEADPHONES);
82 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_TELEPHONE);
83 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
84 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_VOICEIN);
85 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED);
86 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_DIGITAL);
87 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_LINE);
88 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE);
89 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER);
90 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC);
91 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE);
92 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER);
93 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT);
94 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY);
95 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_ANALOG);
97 #undef TYPE_TO_STR
98 return "UNKNOWN";
101 static const char * target_type(DWORD dwType)
103 #define TYPE_TO_STR(x) case x: return #x
104 switch (dwType) {
105 TYPE_TO_STR(MIXERLINE_TARGETTYPE_UNDEFINED);
106 TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEOUT);
107 TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEIN);
108 TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIOUT);
109 TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIIN);
110 TYPE_TO_STR(MIXERLINE_TARGETTYPE_AUX);
112 #undef TYPE_TO_STR
113 return "UNKNOWN";
116 static const char * control_type(DWORD dwControlType)
118 #define TYPE_TO_STR(x) case x: return #x
119 switch (dwControlType) {
120 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM);
121 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER);
122 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER);
123 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER);
124 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER);
125 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN);
126 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF);
127 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE);
128 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO);
129 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS);
130 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH);
131 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST);
132 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON);
133 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS);
134 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED);
135 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED);
136 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT);
137 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER);
138 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN);
139 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN);
140 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER);
141 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME);
142 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS);
143 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE);
144 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER);
145 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT);
146 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX);
147 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT);
148 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER);
149 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME);
150 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME);
152 #undef TYPE_TO_STR
153 return "UNKNOWN";
156 static const char * control_flags(DWORD fdwControl)
158 static char flags[100];
159 BOOL first=TRUE;
160 flags[0]=0;
161 if (fdwControl&MIXERCONTROL_CONTROLF_UNIFORM) {
162 strcat(flags,"MIXERCONTROL_CONTROLF_UNIFORM");
163 first=FALSE;
165 if (fdwControl&MIXERCONTROL_CONTROLF_MULTIPLE) {
166 if (!first)
167 strcat(flags, "|");
169 strcat(flags,"MIXERCONTROL_CONTROLF_MULTIPLE");
170 first=FALSE;
173 if (fdwControl&MIXERCONTROL_CONTROLF_DISABLED) {
174 if (!first)
175 strcat(flags, "|");
177 strcat(flags,"MIXERCONTROL_CONTROLF_DISABLED");
180 return flags;
183 static void test_mixerClose(HMIXER mix)
185 MMRESULT rc;
187 rc = mixerClose(mix);
188 ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_INVALHANDLE,
189 "mixerClose: MMSYSERR_NOERROR or MMSYSERR_INVALHANDLE expected, got %s\n",
190 mmsys_error(rc));
193 static void mixer_test_controlA(HMIXEROBJ mix, MIXERCONTROLA *control)
195 MMRESULT rc;
197 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
198 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
199 MIXERCONTROLDETAILS details;
200 MIXERCONTROLDETAILS_UNSIGNED value;
202 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
203 details.dwControlID = control->dwControlID;
204 details.cChannels = 1;
205 U(details).cMultipleItems = 0;
206 details.cbDetails = sizeof(value);
208 /* test NULL paDetails */
209 details.paDetails = NULL;
210 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
211 ok(rc==MMSYSERR_INVALPARAM,
212 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
213 mmsys_error(rc));
215 /* read the current control value */
216 details.paDetails = &value;
217 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
218 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
219 "MMSYSERR_NOERROR expected, got %s\n",
220 mmsys_error(rc));
221 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
222 MIXERCONTROLDETAILS new_details;
223 MIXERCONTROLDETAILS_UNSIGNED new_value;
225 trace(" Value=%ld\n",value.dwValue);
227 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
228 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
229 else
230 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
232 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
233 new_details.dwControlID = control->dwControlID;
234 new_details.cChannels = 1;
235 U(new_details).cMultipleItems = 0;
236 new_details.paDetails = &new_value;
237 new_details.cbDetails = sizeof(new_value);
239 /* change the control value by one step */
240 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
241 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
242 "MMSYSERR_NOERROR expected, got %s\n",
243 mmsys_error(rc));
244 if (rc==MMSYSERR_NOERROR) {
245 MIXERCONTROLDETAILS ret_details;
246 MIXERCONTROLDETAILS_UNSIGNED ret_value;
248 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
249 ret_details.dwControlID = control->dwControlID;
250 ret_details.cChannels = 1;
251 U(ret_details).cMultipleItems = 0;
252 ret_details.paDetails = &ret_value;
253 ret_details.cbDetails = sizeof(ret_value);
255 /* read back the new control value */
256 rc = mixerGetControlDetailsA(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
257 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
258 "MMSYSERR_NOERROR expected, got %s\n",
259 mmsys_error(rc));
260 if (rc==MMSYSERR_NOERROR) {
261 /* result may not match exactly because of rounding */
262 ok(compare_uint(ret_value.dwValue, new_value.dwValue, 1),
263 "Couldn't change value from %ld to %ld, returned %ld\n",
264 value.dwValue,new_value.dwValue,ret_value.dwValue);
266 if (compare_uint(ret_value.dwValue, new_value.dwValue, 1)) {
267 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
268 details.dwControlID = control->dwControlID;
269 details.cChannels = 1;
270 U(details).cMultipleItems = 0;
271 details.paDetails = &value;
272 details.cbDetails = sizeof(value);
274 /* restore original value */
275 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
276 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
277 "MMSYSERR_NOERROR expected, got %s\n",
278 mmsys_error(rc));
283 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
284 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
285 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
286 MIXERCONTROLDETAILS details;
287 MIXERCONTROLDETAILS_BOOLEAN value;
289 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
290 details.dwControlID = control->dwControlID;
291 details.cChannels = 1;
292 U(details).cMultipleItems = 0;
293 details.paDetails = &value;
294 details.cbDetails = sizeof(value);
296 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
297 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
298 "MMSYSERR_NOERROR expected, got %s\n",
299 mmsys_error(rc));
300 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
301 MIXERCONTROLDETAILS new_details;
302 MIXERCONTROLDETAILS_BOOLEAN new_value;
304 trace(" Value=%ld\n",value.fValue);
306 if (value.fValue == FALSE)
307 new_value.fValue = TRUE;
308 else
309 new_value.fValue = FALSE;
311 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
312 new_details.dwControlID = control->dwControlID;
313 new_details.cChannels = 1;
314 U(new_details).cMultipleItems = 0;
315 new_details.paDetails = &new_value;
316 new_details.cbDetails = sizeof(new_value);
318 /* change the control value by one step */
319 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
320 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
321 "MMSYSERR_NOERROR expected, got %s\n",
322 mmsys_error(rc));
323 if (rc==MMSYSERR_NOERROR) {
324 MIXERCONTROLDETAILS ret_details;
325 MIXERCONTROLDETAILS_BOOLEAN ret_value;
327 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
328 ret_details.dwControlID = control->dwControlID;
329 ret_details.cChannels = 1;
330 U(ret_details).cMultipleItems = 0;
331 ret_details.paDetails = &ret_value;
332 ret_details.cbDetails = sizeof(ret_value);
334 /* read back the new control value */
335 rc = mixerGetControlDetailsA(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
336 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
337 "MMSYSERR_NOERROR expected, got %s\n",
338 mmsys_error(rc));
339 if (rc==MMSYSERR_NOERROR) {
340 /* result may not match exactly because of rounding */
341 ok(ret_value.fValue==new_value.fValue,
342 "Couldn't change value from %ld to %ld, returned %ld\n",
343 value.fValue,new_value.fValue,ret_value.fValue);
345 if (ret_value.fValue==new_value.fValue) {
346 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
347 details.dwControlID = control->dwControlID;
348 details.cChannels = 1;
349 U(details).cMultipleItems = 0;
350 details.paDetails = &value;
351 details.cbDetails = sizeof(value);
353 /* restore original value */
354 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
355 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
356 "MMSYSERR_NOERROR expected, got %s\n",
357 mmsys_error(rc));
362 } else {
363 /* FIXME */
367 static void mixer_test_deviceA(int device)
369 MIXERCAPSA capsA;
370 HMIXEROBJ mix;
371 MMRESULT rc;
372 DWORD d,s,ns,nc;
374 rc=mixerGetDevCapsA(device,0,sizeof(capsA));
375 ok(rc==MMSYSERR_INVALPARAM,
376 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
377 mmsys_error(rc));
379 rc=mixerGetDevCapsA(device,&capsA,4);
380 ok(rc==MMSYSERR_NOERROR,
381 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
382 mmsys_error(rc));
384 rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA));
385 ok(rc==MMSYSERR_NOERROR,
386 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
387 mmsys_error(rc));
389 if (winetest_interactive) {
390 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%ld\n", device,
391 capsA.szPname, capsA.vDriverVersion >> 8,
392 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid,
393 capsA.cDestinations);
394 } else {
395 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
396 capsA.szPname, capsA.vDriverVersion >> 8,
397 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid);
400 rc = mixerOpen((HMIXER*)&mix, device, 0, 0, 0);
401 ok(rc==MMSYSERR_NOERROR,
402 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
403 if (rc==MMSYSERR_NOERROR) {
404 MIXERCAPSA capsA2;
406 rc=mixerGetDevCapsA((UINT_PTR)mix,&capsA2,sizeof(capsA2));
407 ok(rc==MMSYSERR_NOERROR,
408 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
409 mmsys_error(rc));
410 ok(!strcmp(capsA2.szPname, capsA.szPname), "Got wrong device caps\n");
412 for (d=0;d<capsA.cDestinations;d++) {
413 MIXERLINEA mixerlineA;
414 mixerlineA.cbStruct = 0;
415 mixerlineA.dwDestination=d;
416 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
417 ok(rc==MMSYSERR_INVALPARAM,
418 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
419 "MMSYSERR_INVALPARAM expected, got %s\n",
420 mmsys_error(rc));
422 mixerlineA.cbStruct = sizeof(mixerlineA);
423 mixerlineA.dwDestination=capsA.cDestinations;
424 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
425 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
426 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
427 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
428 mmsys_error(rc));
430 mixerlineA.cbStruct = sizeof(mixerlineA);
431 mixerlineA.dwDestination=d;
432 rc = mixerGetLineInfoA(mix, 0, MIXER_GETLINEINFOF_DESTINATION);
433 ok(rc==MMSYSERR_INVALPARAM,
434 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
435 "MMSYSERR_INVALPARAM expected, got %s\n",
436 mmsys_error(rc));
438 mixerlineA.cbStruct = sizeof(mixerlineA);
439 mixerlineA.dwDestination=d;
440 rc = mixerGetLineInfoA(mix, &mixerlineA, -1);
441 ok(rc==MMSYSERR_INVALFLAG,
442 "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n",
443 mmsys_error(rc));
445 mixerlineA.cbStruct = sizeof(mixerlineA);
446 mixerlineA.dwDestination=d;
447 mixerlineA.dwUser = (ULONG_PTR)0xdeadbeef;
448 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
449 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
450 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
451 "MMSYSERR_NOERROR expected, got %s\n",
452 mmsys_error(rc));
453 ok(mixerlineA.dwUser == 0, "dwUser was not reset\n");
454 if (rc==MMSYSERR_NODRIVER)
455 trace(" No Driver\n");
456 else if (rc==MMSYSERR_NOERROR) {
457 if (winetest_interactive) {
458 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
459 d,mixerlineA.szShortName, mixerlineA.szName,
460 mixerlineA.dwDestination,mixerlineA.dwSource);
461 trace(" LineID=%08lx Channels=%ld "
462 "Connections=%ld Controls=%ld\n",
463 mixerlineA.dwLineID,mixerlineA.cChannels,
464 mixerlineA.cConnections,mixerlineA.cControls);
465 trace(" State=0x%08lx(%s)\n",
466 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
467 trace(" ComponentType=%s\n",
468 component_type(mixerlineA.dwComponentType));
469 trace(" Type=%s\n",
470 target_type(mixerlineA.Target.dwType));
471 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
472 mixerlineA.Target.dwDeviceID,
473 mixerlineA.Target.szPname,
474 mixerlineA.Target.vDriverVersion >> 8,
475 mixerlineA.Target.vDriverVersion & 0xff,
476 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
478 ns=mixerlineA.cConnections;
479 for(s=0;s<ns;s++) {
480 mixerlineA.cbStruct = sizeof(mixerlineA);
481 mixerlineA.dwDestination=d;
482 mixerlineA.dwSource=s;
483 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_SOURCE);
484 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
485 "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): "
486 "MMSYSERR_NOERROR expected, got %s\n",
487 mmsys_error(rc));
488 if (rc==MMSYSERR_NODRIVER)
489 trace(" No Driver\n");
490 else if (rc==MMSYSERR_NOERROR) {
491 LPMIXERCONTROLA array;
492 MIXERLINECONTROLSA controls;
493 if (winetest_interactive) {
494 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
495 s,mixerlineA.szShortName, mixerlineA.szName,
496 mixerlineA.dwDestination,mixerlineA.dwSource);
497 trace(" LineID=%08lx Channels=%ld "
498 "Connections=%ld Controls=%ld\n",
499 mixerlineA.dwLineID,mixerlineA.cChannels,
500 mixerlineA.cConnections,mixerlineA.cControls);
501 trace(" State=0x%08lx(%s)\n",
502 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
503 trace(" ComponentType=%s\n",
504 component_type(mixerlineA.dwComponentType));
505 trace(" Type=%s\n",
506 target_type(mixerlineA.Target.dwType));
507 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
508 mixerlineA.Target.dwDeviceID,
509 mixerlineA.Target.szPname,
510 mixerlineA.Target.vDriverVersion >> 8,
511 mixerlineA.Target.vDriverVersion & 0xff,
512 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
514 if (mixerlineA.cControls) {
515 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
516 mixerlineA.cControls*sizeof(MIXERCONTROLA));
517 if (array) {
518 memset(&controls, 0, sizeof(controls));
520 rc = mixerGetLineControlsA(mix, 0, MIXER_GETLINECONTROLSF_ALL);
521 ok(rc==MMSYSERR_INVALPARAM,
522 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
523 "MMSYSERR_INVALPARAM expected, got %s\n",
524 mmsys_error(rc));
526 rc = mixerGetLineControlsA(mix, &controls, -1);
527 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
528 "mixerGetLineControlsA(-1): "
529 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
530 mmsys_error(rc));
532 controls.cbStruct = sizeof(MIXERLINECONTROLSA);
533 controls.cControls = mixerlineA.cControls;
534 controls.dwLineID = mixerlineA.dwLineID;
535 controls.pamxctrl = array;
536 controls.cbmxctrl = sizeof(MIXERCONTROLA);
538 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
539 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
541 rc = mixerGetLineControlsA(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
542 ok(rc==MMSYSERR_NOERROR,
543 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
544 "MMSYSERR_NOERROR expected, got %s\n",
545 mmsys_error(rc));
546 if (rc==MMSYSERR_NOERROR) {
547 for(nc=0;nc<mixerlineA.cControls;nc++) {
548 if (winetest_interactive) {
549 trace(" %ld: \"%s\" (%s) ControlID=%ld\n", nc,
550 array[nc].szShortName,
551 array[nc].szName, array[nc].dwControlID);
552 trace(" ControlType=%s\n",
553 control_type(array[nc].dwControlType));
554 trace(" Control=0x%08lx(%s)\n",
555 array[nc].fdwControl,
556 control_flags(array[nc].fdwControl));
557 trace(" Items=%ld Min=%ld Max=%ld Step=%ld\n",
558 array[nc].cMultipleItems,
559 S1(array[nc].Bounds).dwMinimum,
560 S1(array[nc].Bounds).dwMaximum,
561 array[nc].Metrics.cSteps);
564 mixer_test_controlA(mix, &array[nc]);
568 HeapFree(GetProcessHeap(),0,array);
575 test_mixerClose((HMIXER)mix);
579 static void mixer_test_controlW(HMIXEROBJ mix, MIXERCONTROLW *control)
581 MMRESULT rc;
583 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
584 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
585 MIXERCONTROLDETAILS details;
586 MIXERCONTROLDETAILS_UNSIGNED value;
588 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
589 details.dwControlID = control->dwControlID;
590 details.cChannels = 1;
591 U(details).cMultipleItems = 0;
592 details.paDetails = &value;
593 details.cbDetails = sizeof(value);
595 /* read the current control value */
596 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
597 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
598 "MMSYSERR_NOERROR expected, got %s\n",
599 mmsys_error(rc));
600 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
601 MIXERCONTROLDETAILS new_details;
602 MIXERCONTROLDETAILS_UNSIGNED new_value;
604 trace(" Value=%ld\n",value.dwValue);
606 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
607 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
608 else
609 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
611 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
612 new_details.dwControlID = control->dwControlID;
613 new_details.cChannels = 1;
614 U(new_details).cMultipleItems = 0;
615 new_details.paDetails = &new_value;
616 new_details.cbDetails = sizeof(new_value);
618 /* change the control value by one step */
619 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
620 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
621 "MMSYSERR_NOERROR expected, got %s\n",
622 mmsys_error(rc));
623 if (rc==MMSYSERR_NOERROR) {
624 MIXERCONTROLDETAILS ret_details;
625 MIXERCONTROLDETAILS_UNSIGNED ret_value;
627 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
628 ret_details.dwControlID = control->dwControlID;
629 ret_details.cChannels = 1;
630 U(ret_details).cMultipleItems = 0;
631 ret_details.paDetails = &ret_value;
632 ret_details.cbDetails = sizeof(ret_value);
634 /* read back the new control value */
635 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
636 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
637 "MMSYSERR_NOERROR expected, got %s\n",
638 mmsys_error(rc));
639 if (rc==MMSYSERR_NOERROR) {
640 /* result may not match exactly because of rounding */
641 ok(compare_uint(ret_value.dwValue, new_value.dwValue, 1),
642 "Couldn't change value from %ld to %ld, returned %ld\n",
643 value.dwValue,new_value.dwValue,ret_value.dwValue);
645 if (compare_uint(ret_value.dwValue, new_value.dwValue, 1)) {
646 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
647 details.dwControlID = control->dwControlID;
648 details.cChannels = 1;
649 U(details).cMultipleItems = 0;
650 details.paDetails = &value;
651 details.cbDetails = sizeof(value);
653 /* restore original value */
654 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
655 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
656 "MMSYSERR_NOERROR expected, got %s\n",
657 mmsys_error(rc));
662 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
663 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
664 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
665 MIXERCONTROLDETAILS details;
666 MIXERCONTROLDETAILS_BOOLEAN value;
668 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
669 details.dwControlID = control->dwControlID;
670 details.cChannels = 1;
671 U(details).cMultipleItems = 0;
672 details.paDetails = &value;
673 details.cbDetails = sizeof(value);
675 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
676 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
677 "MMSYSERR_NOERROR expected, got %s\n",
678 mmsys_error(rc));
679 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
680 MIXERCONTROLDETAILS new_details;
681 MIXERCONTROLDETAILS_BOOLEAN new_value;
683 trace(" Value=%ld\n",value.fValue);
685 if (value.fValue == FALSE)
686 new_value.fValue = TRUE;
687 else
688 new_value.fValue = FALSE;
690 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
691 new_details.dwControlID = control->dwControlID;
692 new_details.cChannels = 1;
693 U(new_details).cMultipleItems = 0;
694 new_details.paDetails = &new_value;
695 new_details.cbDetails = sizeof(new_value);
697 /* change the control value by one step */
698 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
699 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
700 "MMSYSERR_NOERROR expected, got %s\n",
701 mmsys_error(rc));
702 if (rc==MMSYSERR_NOERROR) {
703 MIXERCONTROLDETAILS ret_details;
704 MIXERCONTROLDETAILS_BOOLEAN ret_value;
706 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
707 ret_details.dwControlID = control->dwControlID;
708 ret_details.cChannels = 1;
709 U(ret_details).cMultipleItems = 0;
710 ret_details.paDetails = &ret_value;
711 ret_details.cbDetails = sizeof(ret_value);
713 /* read back the new control value */
714 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
715 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
716 "MMSYSERR_NOERROR expected, got %s\n",
717 mmsys_error(rc));
718 if (rc==MMSYSERR_NOERROR) {
719 /* result may not match exactly because of rounding */
720 ok(ret_value.fValue==new_value.fValue,
721 "Couldn't change value from %ld to %ld, returned %ld\n",
722 value.fValue,new_value.fValue,ret_value.fValue);
724 if (ret_value.fValue==new_value.fValue) {
725 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
726 details.dwControlID = control->dwControlID;
727 details.cChannels = 1;
728 U(details).cMultipleItems = 0;
729 details.paDetails = &value;
730 details.cbDetails = sizeof(value);
732 /* restore original value */
733 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
734 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
735 "MMSYSERR_NOERROR expected, got %s\n",
736 mmsys_error(rc));
741 } else {
742 /* FIXME */
746 static void mixer_test_deviceW(int device)
748 MIXERCAPSW capsW;
749 HMIXEROBJ mix;
750 MMRESULT rc;
751 DWORD d,s,ns,nc;
752 char szShortName[MIXER_SHORT_NAME_CHARS];
753 char szName[MIXER_LONG_NAME_CHARS];
754 char szPname[MAXPNAMELEN];
756 rc=mixerGetDevCapsW(device,0,sizeof(capsW));
757 ok(rc==MMSYSERR_INVALPARAM,
758 "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n",
759 mmsys_error(rc));
761 rc=mixerGetDevCapsW(device,&capsW,4);
762 ok(rc==MMSYSERR_NOERROR ||
763 rc==MMSYSERR_INVALPARAM, /* Vista and W2K8 */
764 "mixerGetDevCapsW: MMSYSERR_NOERROR or MMSYSERR_INVALPARAM expected, got %s\n",
765 mmsys_error(rc));
767 rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW));
768 ok(rc==MMSYSERR_NOERROR,
769 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
770 mmsys_error(rc));
772 WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname,
773 MAXPNAMELEN,NULL,NULL);
774 if (winetest_interactive) {
775 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%ld\n", device,
776 szPname, capsW.vDriverVersion >> 8,
777 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid,
778 capsW.cDestinations);
779 } else {
780 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
781 szPname, capsW.vDriverVersion >> 8,
782 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid);
786 rc = mixerOpen((HMIXER*)&mix, device, 0, 0, 0);
787 ok(rc==MMSYSERR_NOERROR,
788 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
789 if (rc==MMSYSERR_NOERROR) {
790 MIXERCAPSW capsW2;
792 rc=mixerGetDevCapsW((UINT_PTR)mix,&capsW2,sizeof(capsW2));
793 ok(rc==MMSYSERR_NOERROR,
794 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
795 mmsys_error(rc));
796 ok(!lstrcmpW(capsW2.szPname, capsW.szPname), "Got wrong device caps\n");
798 for (d=0;d<capsW.cDestinations;d++) {
799 MIXERLINEW mixerlineW;
800 mixerlineW.cbStruct = 0;
801 mixerlineW.dwDestination=d;
802 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
803 ok(rc==MMSYSERR_INVALPARAM,
804 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
805 "MMSYSERR_INVALPARAM expected, got %s\n",
806 mmsys_error(rc));
808 mixerlineW.cbStruct = sizeof(mixerlineW);
809 mixerlineW.dwDestination=capsW.cDestinations;
810 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
811 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
812 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
813 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
814 mmsys_error(rc));
816 mixerlineW.cbStruct = sizeof(mixerlineW);
817 mixerlineW.dwDestination=d;
818 rc = mixerGetLineInfoW(mix, 0, MIXER_GETLINEINFOF_DESTINATION);
819 ok(rc==MMSYSERR_INVALPARAM,
820 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
821 "MMSYSERR_INVALPARAM expected, got %s\n",
822 mmsys_error(rc));
824 mixerlineW.cbStruct = sizeof(mixerlineW);
825 mixerlineW.dwDestination=d;
826 rc = mixerGetLineInfoW(mix, &mixerlineW, -1);
827 ok(rc==MMSYSERR_INVALFLAG,
828 "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n",
829 mmsys_error(rc));
831 mixerlineW.cbStruct = sizeof(mixerlineW);
832 mixerlineW.dwDestination=d;
833 mixerlineW.dwUser = (ULONG_PTR)0xdeadbeef;
834 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
835 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
836 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
837 "MMSYSERR_NOERROR expected, got %s\n",
838 mmsys_error(rc));
839 ok(mixerlineW.dwUser == 0, "dwUser was not reset\n");
840 if (rc==MMSYSERR_NODRIVER)
841 trace(" No Driver\n");
842 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
843 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
844 MIXER_SHORT_NAME_CHARS,szShortName,
845 MIXER_SHORT_NAME_CHARS,NULL,NULL);
846 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
847 MIXER_LONG_NAME_CHARS,szName,
848 MIXER_LONG_NAME_CHARS,NULL,NULL);
849 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
850 MAXPNAMELEN,szPname,
851 MAXPNAMELEN,NULL, NULL);
852 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
853 d,szShortName,szName,
854 mixerlineW.dwDestination,mixerlineW.dwSource);
855 trace(" LineID=%08lx Channels=%ld "
856 "Connections=%ld Controls=%ld\n",
857 mixerlineW.dwLineID,mixerlineW.cChannels,
858 mixerlineW.cConnections,mixerlineW.cControls);
859 trace(" State=0x%08lx(%s)\n",
860 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
861 trace(" ComponentType=%s\n",
862 component_type(mixerlineW.dwComponentType));
863 trace(" Type=%s\n",
864 target_type(mixerlineW.Target.dwType));
865 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
866 mixerlineW.Target.dwDeviceID,szPname,
867 mixerlineW.Target.vDriverVersion >> 8,
868 mixerlineW.Target.vDriverVersion & 0xff,
869 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
871 ns=mixerlineW.cConnections;
872 for(s=0;s<ns;s++) {
873 mixerlineW.cbStruct = sizeof(mixerlineW);
874 mixerlineW.dwDestination=d;
875 mixerlineW.dwSource=s;
876 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_SOURCE);
877 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
878 "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): "
879 "MMSYSERR_NOERROR expected, got %s\n",
880 mmsys_error(rc));
881 if (rc==MMSYSERR_NODRIVER)
882 trace(" No Driver\n");
883 else if (rc==MMSYSERR_NOERROR) {
884 LPMIXERCONTROLW array;
885 MIXERLINECONTROLSW controls;
886 if (winetest_interactive) {
887 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
888 MIXER_SHORT_NAME_CHARS,szShortName,
889 MIXER_SHORT_NAME_CHARS,NULL,NULL);
890 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
891 MIXER_LONG_NAME_CHARS,szName,
892 MIXER_LONG_NAME_CHARS,NULL,NULL);
893 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
894 MAXPNAMELEN,szPname,
895 MAXPNAMELEN,NULL, NULL);
896 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
897 s,szShortName,szName,
898 mixerlineW.dwDestination,mixerlineW.dwSource);
899 trace(" LineID=%08lx Channels=%ld "
900 "Connections=%ld Controls=%ld\n",
901 mixerlineW.dwLineID,mixerlineW.cChannels,
902 mixerlineW.cConnections,mixerlineW.cControls);
903 trace(" State=0x%08lx(%s)\n",
904 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
905 trace(" ComponentType=%s\n",
906 component_type(mixerlineW.dwComponentType));
907 trace(" Type=%s\n",
908 target_type(mixerlineW.Target.dwType));
909 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
910 mixerlineW.Target.dwDeviceID,szPname,
911 mixerlineW.Target.vDriverVersion >> 8,
912 mixerlineW.Target.vDriverVersion & 0xff,
913 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
915 if (mixerlineW.cControls) {
916 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
917 mixerlineW.cControls*sizeof(MIXERCONTROLW));
918 if (array) {
919 rc = mixerGetLineControlsW(mix, 0, MIXER_GETLINECONTROLSF_ALL);
920 ok(rc==MMSYSERR_INVALPARAM,
921 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
922 "MMSYSERR_INVALPARAM expected, got %s\n",
923 mmsys_error(rc));
924 rc = mixerGetLineControlsW(mix, &controls, -1);
925 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
926 "mixerGetLineControlsW(-1): "
927 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
928 mmsys_error(rc));
930 controls.cbStruct = sizeof(MIXERLINECONTROLSW);
931 controls.cControls = mixerlineW.cControls;
932 controls.dwLineID = mixerlineW.dwLineID;
933 controls.pamxctrl = array;
934 controls.cbmxctrl = sizeof(MIXERCONTROLW);
936 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
937 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
939 rc = mixerGetLineControlsW(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
940 ok(rc==MMSYSERR_NOERROR,
941 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
942 "MMSYSERR_NOERROR expected, got %s\n",
943 mmsys_error(rc));
944 if (rc==MMSYSERR_NOERROR) {
945 for(nc=0;nc<mixerlineW.cControls;nc++) {
946 if (winetest_interactive) {
947 WideCharToMultiByte(CP_ACP,0,array[nc].szShortName,
948 MIXER_SHORT_NAME_CHARS,szShortName,
949 MIXER_SHORT_NAME_CHARS,NULL,NULL);
950 WideCharToMultiByte(CP_ACP,0,array[nc].szName,
951 MIXER_LONG_NAME_CHARS,szName,
952 MIXER_LONG_NAME_CHARS,NULL,NULL);
953 trace(" %ld: \"%s\" (%s) ControlID=%ld\n", nc,
954 szShortName, szName, array[nc].dwControlID);
955 trace(" ControlType=%s\n",
956 control_type(array[nc].dwControlType));
957 trace(" Control=0x%08lx(%s)\n",
958 array[nc].fdwControl,
959 control_flags(array[nc].fdwControl));
960 trace(" Items=%ld Min=%ld Max=%ld Step=%ld\n",
961 array[nc].cMultipleItems,
962 S1(array[nc].Bounds).dwMinimum,
963 S1(array[nc].Bounds).dwMaximum,
964 array[nc].Metrics.cSteps);
966 mixer_test_controlW(mix, &array[nc]);
970 HeapFree(GetProcessHeap(),0,array);
976 test_mixerClose((HMIXER)mix);
980 static void mixer_testsA(void)
982 MIXERCAPSA capsA;
983 MMRESULT rc;
984 UINT ndev, d;
986 trace("--- Testing ANSI functions ---\n");
988 ndev=mixerGetNumDevs();
989 trace("found %d Mixer devices\n",ndev);
991 rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
992 ok(rc==MMSYSERR_BADDEVICEID,
993 "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n",
994 mmsys_error(rc));
996 for (d=0;d<ndev;d++)
997 mixer_test_deviceA(d);
1000 static void mixer_testsW(void)
1002 MIXERCAPSW capsW;
1003 MMRESULT rc;
1004 UINT ndev, d;
1006 trace("--- Testing WCHAR functions ---\n");
1008 ndev=mixerGetNumDevs();
1009 trace("found %d Mixer devices\n",ndev);
1011 rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
1012 ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED,
1013 "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
1014 "expected, got %s\n", mmsys_error(rc));
1015 if (rc==MMSYSERR_NOTSUPPORTED)
1016 return;
1018 for (d=0;d<ndev;d++)
1019 mixer_test_deviceW(d);
1022 static void test_mixerOpen(void)
1024 HMIXER mix;
1025 HANDLE event;
1026 MMRESULT rc;
1027 UINT ndev, d;
1029 ndev = mixerGetNumDevs();
1031 /* Test mixerOpen with invalid device ID values. */
1032 rc = mixerOpen(&mix, ndev + 1, 0, 0, 0);
1033 ok(rc == MMSYSERR_BADDEVICEID,
1034 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
1035 mmsys_error(rc));
1037 rc = mixerOpen(&mix, -1, 0, 0, 0);
1038 ok(rc == MMSYSERR_BADDEVICEID ||
1039 rc == MMSYSERR_INVALHANDLE, /* NT4/W2K */
1040 "mixerOpen: MMSYSERR_BADDEVICEID or MMSYSERR_INVALHANDLE expected, got %s\n",
1041 mmsys_error(rc));
1043 for (d = 0; d < ndev; d++) {
1044 /* Test mixerOpen with valid device ID values and invalid parameters. */
1045 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_FUNCTION);
1046 ok(rc == MMSYSERR_INVALFLAG
1047 || rc == MMSYSERR_NOTSUPPORTED, /* 98/ME */
1048 "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n",
1049 mmsys_error(rc));
1051 rc = mixerOpen(&mix, d, 0xdeadbeef, 0, CALLBACK_WINDOW);
1052 ok(rc == MMSYSERR_INVALPARAM ||
1053 broken(rc == MMSYSERR_NOERROR /* 98 */),
1054 "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n",
1055 mmsys_error(rc));
1056 if (rc == MMSYSERR_NOERROR)
1057 test_mixerClose(mix);
1059 /* Test mixerOpen with a NULL dwCallback and CALLBACK_WINDOW flag. */
1060 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_WINDOW);
1061 ok(rc == MMSYSERR_NOERROR,
1062 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1063 mmsys_error(rc));
1064 if (rc == MMSYSERR_NOERROR)
1065 test_mixerClose(mix);
1067 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_THREAD);
1068 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1069 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1070 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1071 mmsys_error(rc));
1072 if (rc == MMSYSERR_NOERROR)
1073 test_mixerClose(mix);
1075 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_EVENT);
1076 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1077 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1078 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1079 mmsys_error(rc));
1080 if (rc == MMSYSERR_NOERROR)
1081 test_mixerClose(mix);
1083 event = CreateEventW(NULL, FALSE, FALSE, NULL);
1085 /* NOTSUPPORTED is not broken, but it enables the todo_wine marker. */
1086 rc = mixerOpen(&mix, d, (DWORD_PTR)event, 0, CALLBACK_EVENT);
1087 todo_wine
1088 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1089 broken(rc == MMSYSERR_NOTSUPPORTED), /* 98 */
1090 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1091 mmsys_error(rc));
1092 if (rc == MMSYSERR_NOERROR)
1093 test_mixerClose(mix);
1095 /* Test mixerOpen with normal parameters. */
1096 rc = mixerOpen(&mix, d, 0, 0, 0);
1097 ok(rc == MMSYSERR_NOERROR,
1098 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1099 mmsys_error(rc));
1101 if (rc == MMSYSERR_NOERROR)
1102 test_mixerClose(mix);
1104 rc = WaitForSingleObject(event, 0);
1105 ok(rc == WAIT_TIMEOUT, "WaitEvent %d\n", rc);
1106 CloseHandle(event);
1110 START_TEST(mixer)
1112 test_mixerOpen();
1113 mixer_testsA();
1114 mixer_testsW();