TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / winmm / tests / mixer.c
blob82eb338a035459e7c2ff90e3408a515c4a2c4727
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 const char * line_flags(DWORD fdwLine)
41 static char flags[100];
42 BOOL first=TRUE;
43 flags[0]=0;
44 if (fdwLine&MIXERLINE_LINEF_ACTIVE) {
45 strcat(flags,"MIXERLINE_LINEF_ACTIVE");
46 first=FALSE;
48 if (fdwLine&MIXERLINE_LINEF_DISCONNECTED) {
49 if (!first)
50 strcat(flags, "|");
52 strcat(flags,"MIXERLINE_LINEF_DISCONNECTED");
53 first=FALSE;
56 if (fdwLine&MIXERLINE_LINEF_SOURCE) {
57 if (!first)
58 strcat(flags, "|");
60 strcat(flags,"MIXERLINE_LINEF_SOURCE");
63 return flags;
66 static const char * component_type(DWORD dwComponentType)
68 #define TYPE_TO_STR(x) case x: return #x
69 switch (dwComponentType) {
70 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_UNDEFINED);
71 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_DIGITAL);
72 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_LINE);
73 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_MONITOR);
74 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS);
75 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_HEADPHONES);
76 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_TELEPHONE);
77 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
78 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_DST_VOICEIN);
79 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED);
80 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_DIGITAL);
81 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_LINE);
82 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE);
83 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER);
84 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC);
85 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE);
86 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER);
87 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT);
88 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY);
89 TYPE_TO_STR(MIXERLINE_COMPONENTTYPE_SRC_ANALOG);
91 #undef TYPE_TO_STR
92 return "UNKNOWN";
95 static const char * target_type(DWORD dwType)
97 #define TYPE_TO_STR(x) case x: return #x
98 switch (dwType) {
99 TYPE_TO_STR(MIXERLINE_TARGETTYPE_UNDEFINED);
100 TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEOUT);
101 TYPE_TO_STR(MIXERLINE_TARGETTYPE_WAVEIN);
102 TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIOUT);
103 TYPE_TO_STR(MIXERLINE_TARGETTYPE_MIDIIN);
104 TYPE_TO_STR(MIXERLINE_TARGETTYPE_AUX);
106 #undef TYPE_TO_STR
107 return "UNKNOWN";
110 static const char * control_type(DWORD dwControlType)
112 #define TYPE_TO_STR(x) case x: return #x
113 switch (dwControlType) {
114 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_CUSTOM);
115 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEANMETER);
116 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNEDMETER);
117 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PEAKMETER);
118 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER);
119 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BOOLEAN);
120 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_ONOFF);
121 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUTE);
122 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MONO);
123 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_LOUDNESS);
124 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_STEREOENH);
125 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS_BOOST);
126 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BUTTON);
127 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_DECIBELS);
128 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SIGNED);
129 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_UNSIGNED);
130 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PERCENT);
131 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SLIDER);
132 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_PAN);
133 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_QSOUNDPAN);
134 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_FADER);
135 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_VOLUME);
136 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_BASS);
137 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_TREBLE);
138 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_EQUALIZER);
139 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_SINGLESELECT);
140 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MUX);
141 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT);
142 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MIXER);
143 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MICROTIME);
144 TYPE_TO_STR(MIXERCONTROL_CONTROLTYPE_MILLITIME);
146 #undef TYPE_TO_STR
147 return "UNKNOWN";
150 static const char * control_flags(DWORD fdwControl)
152 static char flags[100];
153 BOOL first=TRUE;
154 flags[0]=0;
155 if (fdwControl&MIXERCONTROL_CONTROLF_UNIFORM) {
156 strcat(flags,"MIXERCONTROL_CONTROLF_UNIFORM");
157 first=FALSE;
159 if (fdwControl&MIXERCONTROL_CONTROLF_MULTIPLE) {
160 if (!first)
161 strcat(flags, "|");
163 strcat(flags,"MIXERCONTROL_CONTROLF_MULTIPLE");
164 first=FALSE;
167 if (fdwControl&MIXERCONTROL_CONTROLF_DISABLED) {
168 if (!first)
169 strcat(flags, "|");
171 strcat(flags,"MIXERCONTROL_CONTROLF_DISABLED");
174 return flags;
177 static void test_mixerClose(HMIXER mix)
179 MMRESULT rc;
181 rc = mixerClose(mix);
182 ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_INVALHANDLE,
183 "mixerClose: MMSYSERR_NOERROR or MMSYSERR_INVALHANDLE expected, got %s\n",
184 mmsys_error(rc));
187 static void mixer_test_controlA(HMIXEROBJ mix, MIXERCONTROLA *control)
189 MMRESULT rc;
191 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
192 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
193 MIXERCONTROLDETAILS details;
194 MIXERCONTROLDETAILS_UNSIGNED value;
196 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
197 details.dwControlID = control->dwControlID;
198 details.cChannels = 1;
199 U(details).cMultipleItems = 0;
200 details.cbDetails = sizeof(value);
202 /* test NULL paDetails */
203 details.paDetails = NULL;
204 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
205 ok(rc==MMSYSERR_INVALPARAM,
206 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
207 mmsys_error(rc));
209 /* read the current control value */
210 details.paDetails = &value;
211 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
212 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
213 "MMSYSERR_NOERROR expected, got %s\n",
214 mmsys_error(rc));
215 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
216 MIXERCONTROLDETAILS new_details;
217 MIXERCONTROLDETAILS_UNSIGNED new_value;
219 trace(" Value=%d\n",value.dwValue);
221 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
222 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
223 else
224 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
226 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
227 new_details.dwControlID = control->dwControlID;
228 new_details.cChannels = 1;
229 U(new_details).cMultipleItems = 0;
230 new_details.paDetails = &new_value;
231 new_details.cbDetails = sizeof(new_value);
233 /* change the control value by one step */
234 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
235 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
236 "MMSYSERR_NOERROR expected, got %s\n",
237 mmsys_error(rc));
238 if (rc==MMSYSERR_NOERROR) {
239 MIXERCONTROLDETAILS ret_details;
240 MIXERCONTROLDETAILS_UNSIGNED ret_value;
242 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
243 ret_details.dwControlID = control->dwControlID;
244 ret_details.cChannels = 1;
245 U(ret_details).cMultipleItems = 0;
246 ret_details.paDetails = &ret_value;
247 ret_details.cbDetails = sizeof(ret_value);
249 /* read back the new control value */
250 rc = mixerGetControlDetailsA(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
251 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
252 "MMSYSERR_NOERROR expected, got %s\n",
253 mmsys_error(rc));
254 if (rc==MMSYSERR_NOERROR) {
255 /* result may not match exactly because of rounding */
256 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
257 "Couldn't change value from %d to %d, returned %d\n",
258 value.dwValue,new_value.dwValue,ret_value.dwValue);
260 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
261 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
262 details.dwControlID = control->dwControlID;
263 details.cChannels = 1;
264 U(details).cMultipleItems = 0;
265 details.paDetails = &value;
266 details.cbDetails = sizeof(value);
268 /* restore original value */
269 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
270 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
271 "MMSYSERR_NOERROR expected, got %s\n",
272 mmsys_error(rc));
277 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
278 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
279 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
280 MIXERCONTROLDETAILS details;
281 MIXERCONTROLDETAILS_BOOLEAN value;
283 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
284 details.dwControlID = control->dwControlID;
285 details.cChannels = 1;
286 U(details).cMultipleItems = 0;
287 details.paDetails = &value;
288 details.cbDetails = sizeof(value);
290 rc = mixerGetControlDetailsA(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
291 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
292 "MMSYSERR_NOERROR expected, got %s\n",
293 mmsys_error(rc));
294 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
295 MIXERCONTROLDETAILS new_details;
296 MIXERCONTROLDETAILS_BOOLEAN new_value;
298 trace(" Value=%d\n",value.fValue);
300 if (value.fValue == FALSE)
301 new_value.fValue = TRUE;
302 else
303 new_value.fValue = FALSE;
305 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
306 new_details.dwControlID = control->dwControlID;
307 new_details.cChannels = 1;
308 U(new_details).cMultipleItems = 0;
309 new_details.paDetails = &new_value;
310 new_details.cbDetails = sizeof(new_value);
312 /* change the control value by one step */
313 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
314 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
315 "MMSYSERR_NOERROR expected, got %s\n",
316 mmsys_error(rc));
317 if (rc==MMSYSERR_NOERROR) {
318 MIXERCONTROLDETAILS ret_details;
319 MIXERCONTROLDETAILS_BOOLEAN ret_value;
321 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
322 ret_details.dwControlID = control->dwControlID;
323 ret_details.cChannels = 1;
324 U(ret_details).cMultipleItems = 0;
325 ret_details.paDetails = &ret_value;
326 ret_details.cbDetails = sizeof(ret_value);
328 /* read back the new control value */
329 rc = mixerGetControlDetailsA(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
330 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
331 "MMSYSERR_NOERROR expected, got %s\n",
332 mmsys_error(rc));
333 if (rc==MMSYSERR_NOERROR) {
334 /* result may not match exactly because of rounding */
335 ok(ret_value.fValue==new_value.fValue,
336 "Couldn't change value from %d to %d, returned %d\n",
337 value.fValue,new_value.fValue,ret_value.fValue);
339 if (ret_value.fValue==new_value.fValue) {
340 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
341 details.dwControlID = control->dwControlID;
342 details.cChannels = 1;
343 U(details).cMultipleItems = 0;
344 details.paDetails = &value;
345 details.cbDetails = sizeof(value);
347 /* restore original value */
348 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
349 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
350 "MMSYSERR_NOERROR expected, got %s\n",
351 mmsys_error(rc));
356 } else {
357 /* FIXME */
361 static void mixer_test_deviceA(int device)
363 MIXERCAPSA capsA;
364 HMIXEROBJ mix;
365 MMRESULT rc;
366 DWORD d,s,ns,nc;
368 rc=mixerGetDevCapsA(device,0,sizeof(capsA));
369 ok(rc==MMSYSERR_INVALPARAM,
370 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
371 mmsys_error(rc));
373 rc=mixerGetDevCapsA(device,&capsA,4);
374 ok(rc==MMSYSERR_NOERROR,
375 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
376 mmsys_error(rc));
378 rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA));
379 ok(rc==MMSYSERR_NOERROR,
380 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
381 mmsys_error(rc));
383 if (winetest_interactive) {
384 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device,
385 capsA.szPname, capsA.vDriverVersion >> 8,
386 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid,
387 capsA.cDestinations);
388 } else {
389 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
390 capsA.szPname, capsA.vDriverVersion >> 8,
391 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid);
394 rc = mixerOpen((HMIXER*)&mix, device, 0, 0, 0);
395 ok(rc==MMSYSERR_NOERROR,
396 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
397 if (rc==MMSYSERR_NOERROR) {
398 MIXERCAPSA capsA2;
400 rc=mixerGetDevCapsA((UINT_PTR)mix,&capsA2,sizeof(capsA2));
401 ok(rc==MMSYSERR_NOERROR,
402 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
403 mmsys_error(rc));
404 ok(!strcmp(capsA2.szPname, capsA.szPname), "Got wrong device caps\n");
406 for (d=0;d<capsA.cDestinations;d++) {
407 MIXERLINEA mixerlineA;
408 mixerlineA.cbStruct = 0;
409 mixerlineA.dwDestination=d;
410 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
411 ok(rc==MMSYSERR_INVALPARAM,
412 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
413 "MMSYSERR_INVALPARAM expected, got %s\n",
414 mmsys_error(rc));
416 mixerlineA.cbStruct = sizeof(mixerlineA);
417 mixerlineA.dwDestination=capsA.cDestinations;
418 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
419 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
420 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
421 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
422 mmsys_error(rc));
424 mixerlineA.cbStruct = sizeof(mixerlineA);
425 mixerlineA.dwDestination=d;
426 rc = mixerGetLineInfoA(mix, 0, MIXER_GETLINEINFOF_DESTINATION);
427 ok(rc==MMSYSERR_INVALPARAM,
428 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
429 "MMSYSERR_INVALPARAM expected, got %s\n",
430 mmsys_error(rc));
432 mixerlineA.cbStruct = sizeof(mixerlineA);
433 mixerlineA.dwDestination=d;
434 rc = mixerGetLineInfoA(mix, &mixerlineA, -1);
435 ok(rc==MMSYSERR_INVALFLAG,
436 "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n",
437 mmsys_error(rc));
439 mixerlineA.cbStruct = sizeof(mixerlineA);
440 mixerlineA.dwDestination=d;
441 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
442 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
443 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
444 "MMSYSERR_NOERROR expected, got %s\n",
445 mmsys_error(rc));
446 if (rc==MMSYSERR_NODRIVER)
447 trace(" No Driver\n");
448 else if (rc==MMSYSERR_NOERROR) {
449 if (winetest_interactive) {
450 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
451 d,mixerlineA.szShortName, mixerlineA.szName,
452 mixerlineA.dwDestination,mixerlineA.dwSource);
453 trace(" LineID=%08x Channels=%d "
454 "Connections=%d Controls=%d\n",
455 mixerlineA.dwLineID,mixerlineA.cChannels,
456 mixerlineA.cConnections,mixerlineA.cControls);
457 trace(" State=0x%08x(%s)\n",
458 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
459 trace(" ComponentType=%s\n",
460 component_type(mixerlineA.dwComponentType));
461 trace(" Type=%s\n",
462 target_type(mixerlineA.Target.dwType));
463 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
464 mixerlineA.Target.dwDeviceID,
465 mixerlineA.Target.szPname,
466 mixerlineA.Target.vDriverVersion >> 8,
467 mixerlineA.Target.vDriverVersion & 0xff,
468 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
470 ns=mixerlineA.cConnections;
471 for(s=0;s<ns;s++) {
472 mixerlineA.cbStruct = sizeof(mixerlineA);
473 mixerlineA.dwDestination=d;
474 mixerlineA.dwSource=s;
475 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_SOURCE);
476 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
477 "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): "
478 "MMSYSERR_NOERROR expected, got %s\n",
479 mmsys_error(rc));
480 if (rc==MMSYSERR_NODRIVER)
481 trace(" No Driver\n");
482 else if (rc==MMSYSERR_NOERROR) {
483 LPMIXERCONTROLA array;
484 MIXERLINECONTROLSA controls;
485 if (winetest_interactive) {
486 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
487 s,mixerlineA.szShortName, mixerlineA.szName,
488 mixerlineA.dwDestination,mixerlineA.dwSource);
489 trace(" LineID=%08x Channels=%d "
490 "Connections=%d Controls=%d\n",
491 mixerlineA.dwLineID,mixerlineA.cChannels,
492 mixerlineA.cConnections,mixerlineA.cControls);
493 trace(" State=0x%08x(%s)\n",
494 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
495 trace(" ComponentType=%s\n",
496 component_type(mixerlineA.dwComponentType));
497 trace(" Type=%s\n",
498 target_type(mixerlineA.Target.dwType));
499 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
500 mixerlineA.Target.dwDeviceID,
501 mixerlineA.Target.szPname,
502 mixerlineA.Target.vDriverVersion >> 8,
503 mixerlineA.Target.vDriverVersion & 0xff,
504 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
506 if (mixerlineA.cControls) {
507 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
508 mixerlineA.cControls*sizeof(MIXERCONTROLA));
509 if (array) {
510 memset(&controls, 0, sizeof(controls));
512 rc = mixerGetLineControlsA(mix, 0, MIXER_GETLINECONTROLSF_ALL);
513 ok(rc==MMSYSERR_INVALPARAM,
514 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
515 "MMSYSERR_INVALPARAM expected, got %s\n",
516 mmsys_error(rc));
518 rc = mixerGetLineControlsA(mix, &controls, -1);
519 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
520 "mixerGetLineControlsA(-1): "
521 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
522 mmsys_error(rc));
524 controls.cbStruct = sizeof(MIXERLINECONTROLSA);
525 controls.cControls = mixerlineA.cControls;
526 controls.dwLineID = mixerlineA.dwLineID;
527 controls.pamxctrl = array;
528 controls.cbmxctrl = sizeof(MIXERCONTROLA);
530 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
531 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
533 rc = mixerGetLineControlsA(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
534 ok(rc==MMSYSERR_NOERROR,
535 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
536 "MMSYSERR_NOERROR expected, got %s\n",
537 mmsys_error(rc));
538 if (rc==MMSYSERR_NOERROR) {
539 for(nc=0;nc<mixerlineA.cControls;nc++) {
540 if (winetest_interactive) {
541 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
542 array[nc].szShortName,
543 array[nc].szName, array[nc].dwControlID);
544 trace(" ControlType=%s\n",
545 control_type(array[nc].dwControlType));
546 trace(" Control=0x%08x(%s)\n",
547 array[nc].fdwControl,
548 control_flags(array[nc].fdwControl));
549 trace(" Items=%d Min=%d Max=%d Step=%d\n",
550 array[nc].cMultipleItems,
551 S1(array[nc].Bounds).dwMinimum,
552 S1(array[nc].Bounds).dwMaximum,
553 array[nc].Metrics.cSteps);
556 mixer_test_controlA(mix, &array[nc]);
560 HeapFree(GetProcessHeap(),0,array);
567 test_mixerClose((HMIXER)mix);
571 static void mixer_test_controlW(HMIXEROBJ mix, MIXERCONTROLW *control)
573 MMRESULT rc;
575 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
576 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
577 MIXERCONTROLDETAILS details;
578 MIXERCONTROLDETAILS_UNSIGNED value;
580 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
581 details.dwControlID = control->dwControlID;
582 details.cChannels = 1;
583 U(details).cMultipleItems = 0;
584 details.paDetails = &value;
585 details.cbDetails = sizeof(value);
587 /* read the current control value */
588 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
589 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
590 "MMSYSERR_NOERROR expected, got %s\n",
591 mmsys_error(rc));
592 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
593 MIXERCONTROLDETAILS new_details;
594 MIXERCONTROLDETAILS_UNSIGNED new_value;
596 trace(" Value=%d\n",value.dwValue);
598 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
599 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
600 else
601 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
603 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
604 new_details.dwControlID = control->dwControlID;
605 new_details.cChannels = 1;
606 U(new_details).cMultipleItems = 0;
607 new_details.paDetails = &new_value;
608 new_details.cbDetails = sizeof(new_value);
610 /* change the control value by one step */
611 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
612 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
613 "MMSYSERR_NOERROR expected, got %s\n",
614 mmsys_error(rc));
615 if (rc==MMSYSERR_NOERROR) {
616 MIXERCONTROLDETAILS ret_details;
617 MIXERCONTROLDETAILS_UNSIGNED ret_value;
619 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
620 ret_details.dwControlID = control->dwControlID;
621 ret_details.cChannels = 1;
622 U(ret_details).cMultipleItems = 0;
623 ret_details.paDetails = &ret_value;
624 ret_details.cbDetails = sizeof(ret_value);
626 /* read back the new control value */
627 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
628 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
629 "MMSYSERR_NOERROR expected, got %s\n",
630 mmsys_error(rc));
631 if (rc==MMSYSERR_NOERROR) {
632 /* result may not match exactly because of rounding */
633 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
634 "Couldn't change value from %d to %d, returned %d\n",
635 value.dwValue,new_value.dwValue,ret_value.dwValue);
637 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
638 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
639 details.dwControlID = control->dwControlID;
640 details.cChannels = 1;
641 U(details).cMultipleItems = 0;
642 details.paDetails = &value;
643 details.cbDetails = sizeof(value);
645 /* restore original value */
646 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
647 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
648 "MMSYSERR_NOERROR expected, got %s\n",
649 mmsys_error(rc));
654 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
655 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
656 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
657 MIXERCONTROLDETAILS details;
658 MIXERCONTROLDETAILS_BOOLEAN value;
660 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
661 details.dwControlID = control->dwControlID;
662 details.cChannels = 1;
663 U(details).cMultipleItems = 0;
664 details.paDetails = &value;
665 details.cbDetails = sizeof(value);
667 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
668 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
669 "MMSYSERR_NOERROR expected, got %s\n",
670 mmsys_error(rc));
671 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
672 MIXERCONTROLDETAILS new_details;
673 MIXERCONTROLDETAILS_BOOLEAN new_value;
675 trace(" Value=%d\n",value.fValue);
677 if (value.fValue == FALSE)
678 new_value.fValue = TRUE;
679 else
680 new_value.fValue = FALSE;
682 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
683 new_details.dwControlID = control->dwControlID;
684 new_details.cChannels = 1;
685 U(new_details).cMultipleItems = 0;
686 new_details.paDetails = &new_value;
687 new_details.cbDetails = sizeof(new_value);
689 /* change the control value by one step */
690 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
691 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
692 "MMSYSERR_NOERROR expected, got %s\n",
693 mmsys_error(rc));
694 if (rc==MMSYSERR_NOERROR) {
695 MIXERCONTROLDETAILS ret_details;
696 MIXERCONTROLDETAILS_BOOLEAN ret_value;
698 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
699 ret_details.dwControlID = control->dwControlID;
700 ret_details.cChannels = 1;
701 U(ret_details).cMultipleItems = 0;
702 ret_details.paDetails = &ret_value;
703 ret_details.cbDetails = sizeof(ret_value);
705 /* read back the new control value */
706 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
707 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
708 "MMSYSERR_NOERROR expected, got %s\n",
709 mmsys_error(rc));
710 if (rc==MMSYSERR_NOERROR) {
711 /* result may not match exactly because of rounding */
712 ok(ret_value.fValue==new_value.fValue,
713 "Couldn't change value from %d to %d, returned %d\n",
714 value.fValue,new_value.fValue,ret_value.fValue);
716 if (ret_value.fValue==new_value.fValue) {
717 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
718 details.dwControlID = control->dwControlID;
719 details.cChannels = 1;
720 U(details).cMultipleItems = 0;
721 details.paDetails = &value;
722 details.cbDetails = sizeof(value);
724 /* restore original value */
725 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
726 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
727 "MMSYSERR_NOERROR expected, got %s\n",
728 mmsys_error(rc));
733 } else {
734 /* FIXME */
738 static void mixer_test_deviceW(int device)
740 MIXERCAPSW capsW;
741 HMIXEROBJ mix;
742 MMRESULT rc;
743 DWORD d,s,ns,nc;
744 char szShortName[MIXER_SHORT_NAME_CHARS];
745 char szName[MIXER_LONG_NAME_CHARS];
746 char szPname[MAXPNAMELEN];
748 rc=mixerGetDevCapsW(device,0,sizeof(capsW));
749 ok(rc==MMSYSERR_INVALPARAM,
750 "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n",
751 mmsys_error(rc));
753 rc=mixerGetDevCapsW(device,&capsW,4);
754 ok(rc==MMSYSERR_NOERROR ||
755 rc==MMSYSERR_INVALPARAM, /* Vista and W2K8 */
756 "mixerGetDevCapsW: MMSYSERR_NOERROR or MMSYSERR_INVALPARAM expected, got %s\n",
757 mmsys_error(rc));
759 rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW));
760 ok(rc==MMSYSERR_NOERROR,
761 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
762 mmsys_error(rc));
764 WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname,
765 MAXPNAMELEN,NULL,NULL);
766 if (winetest_interactive) {
767 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device,
768 szPname, capsW.vDriverVersion >> 8,
769 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid,
770 capsW.cDestinations);
771 } else {
772 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
773 szPname, capsW.vDriverVersion >> 8,
774 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid);
778 rc = mixerOpen((HMIXER*)&mix, device, 0, 0, 0);
779 ok(rc==MMSYSERR_NOERROR,
780 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
781 if (rc==MMSYSERR_NOERROR) {
782 MIXERCAPSW capsW2;
784 rc=mixerGetDevCapsW((UINT_PTR)mix,&capsW2,sizeof(capsW2));
785 ok(rc==MMSYSERR_NOERROR,
786 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
787 mmsys_error(rc));
788 ok(!lstrcmpW(capsW2.szPname, capsW.szPname), "Got wrong device caps\n");
790 for (d=0;d<capsW.cDestinations;d++) {
791 MIXERLINEW mixerlineW;
792 mixerlineW.cbStruct = 0;
793 mixerlineW.dwDestination=d;
794 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
795 ok(rc==MMSYSERR_INVALPARAM,
796 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
797 "MMSYSERR_INVALPARAM expected, got %s\n",
798 mmsys_error(rc));
800 mixerlineW.cbStruct = sizeof(mixerlineW);
801 mixerlineW.dwDestination=capsW.cDestinations;
802 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
803 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
804 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
805 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
806 mmsys_error(rc));
808 mixerlineW.cbStruct = sizeof(mixerlineW);
809 mixerlineW.dwDestination=d;
810 rc = mixerGetLineInfoW(mix, 0, MIXER_GETLINEINFOF_DESTINATION);
811 ok(rc==MMSYSERR_INVALPARAM,
812 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
813 "MMSYSERR_INVALPARAM expected, got %s\n",
814 mmsys_error(rc));
816 mixerlineW.cbStruct = sizeof(mixerlineW);
817 mixerlineW.dwDestination=d;
818 rc = mixerGetLineInfoW(mix, &mixerlineW, -1);
819 ok(rc==MMSYSERR_INVALFLAG,
820 "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n",
821 mmsys_error(rc));
823 mixerlineW.cbStruct = sizeof(mixerlineW);
824 mixerlineW.dwDestination=d;
825 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
826 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
827 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
828 "MMSYSERR_NOERROR expected, got %s\n",
829 mmsys_error(rc));
830 if (rc==MMSYSERR_NODRIVER)
831 trace(" No Driver\n");
832 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
833 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
834 MIXER_SHORT_NAME_CHARS,szShortName,
835 MIXER_SHORT_NAME_CHARS,NULL,NULL);
836 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
837 MIXER_LONG_NAME_CHARS,szName,
838 MIXER_LONG_NAME_CHARS,NULL,NULL);
839 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
840 MAXPNAMELEN,szPname,
841 MAXPNAMELEN,NULL, NULL);
842 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
843 d,szShortName,szName,
844 mixerlineW.dwDestination,mixerlineW.dwSource);
845 trace(" LineID=%08x Channels=%d "
846 "Connections=%d Controls=%d\n",
847 mixerlineW.dwLineID,mixerlineW.cChannels,
848 mixerlineW.cConnections,mixerlineW.cControls);
849 trace(" State=0x%08x(%s)\n",
850 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
851 trace(" ComponentType=%s\n",
852 component_type(mixerlineW.dwComponentType));
853 trace(" Type=%s\n",
854 target_type(mixerlineW.Target.dwType));
855 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
856 mixerlineW.Target.dwDeviceID,szPname,
857 mixerlineW.Target.vDriverVersion >> 8,
858 mixerlineW.Target.vDriverVersion & 0xff,
859 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
861 ns=mixerlineW.cConnections;
862 for(s=0;s<ns;s++) {
863 mixerlineW.cbStruct = sizeof(mixerlineW);
864 mixerlineW.dwDestination=d;
865 mixerlineW.dwSource=s;
866 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_SOURCE);
867 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
868 "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): "
869 "MMSYSERR_NOERROR expected, got %s\n",
870 mmsys_error(rc));
871 if (rc==MMSYSERR_NODRIVER)
872 trace(" No Driver\n");
873 else if (rc==MMSYSERR_NOERROR) {
874 LPMIXERCONTROLW array;
875 MIXERLINECONTROLSW controls;
876 if (winetest_interactive) {
877 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
878 MIXER_SHORT_NAME_CHARS,szShortName,
879 MIXER_SHORT_NAME_CHARS,NULL,NULL);
880 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
881 MIXER_LONG_NAME_CHARS,szName,
882 MIXER_LONG_NAME_CHARS,NULL,NULL);
883 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
884 MAXPNAMELEN,szPname,
885 MAXPNAMELEN,NULL, NULL);
886 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
887 s,szShortName,szName,
888 mixerlineW.dwDestination,mixerlineW.dwSource);
889 trace(" LineID=%08x Channels=%d "
890 "Connections=%d Controls=%d\n",
891 mixerlineW.dwLineID,mixerlineW.cChannels,
892 mixerlineW.cConnections,mixerlineW.cControls);
893 trace(" State=0x%08x(%s)\n",
894 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
895 trace(" ComponentType=%s\n",
896 component_type(mixerlineW.dwComponentType));
897 trace(" Type=%s\n",
898 target_type(mixerlineW.Target.dwType));
899 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
900 mixerlineW.Target.dwDeviceID,szPname,
901 mixerlineW.Target.vDriverVersion >> 8,
902 mixerlineW.Target.vDriverVersion & 0xff,
903 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
905 if (mixerlineW.cControls) {
906 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
907 mixerlineW.cControls*sizeof(MIXERCONTROLW));
908 if (array) {
909 rc = mixerGetLineControlsW(mix, 0, MIXER_GETLINECONTROLSF_ALL);
910 ok(rc==MMSYSERR_INVALPARAM,
911 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
912 "MMSYSERR_INVALPARAM expected, got %s\n",
913 mmsys_error(rc));
914 rc = mixerGetLineControlsW(mix, &controls, -1);
915 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
916 "mixerGetLineControlsW(-1): "
917 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
918 mmsys_error(rc));
920 controls.cbStruct = sizeof(MIXERLINECONTROLSW);
921 controls.cControls = mixerlineW.cControls;
922 controls.dwLineID = mixerlineW.dwLineID;
923 controls.pamxctrl = array;
924 controls.cbmxctrl = sizeof(MIXERCONTROLW);
926 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
927 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
929 rc = mixerGetLineControlsW(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
930 ok(rc==MMSYSERR_NOERROR,
931 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
932 "MMSYSERR_NOERROR expected, got %s\n",
933 mmsys_error(rc));
934 if (rc==MMSYSERR_NOERROR) {
935 for(nc=0;nc<mixerlineW.cControls;nc++) {
936 if (winetest_interactive) {
937 WideCharToMultiByte(CP_ACP,0,array[nc].szShortName,
938 MIXER_SHORT_NAME_CHARS,szShortName,
939 MIXER_SHORT_NAME_CHARS,NULL,NULL);
940 WideCharToMultiByte(CP_ACP,0,array[nc].szName,
941 MIXER_LONG_NAME_CHARS,szName,
942 MIXER_LONG_NAME_CHARS,NULL,NULL);
943 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
944 szShortName, szName, array[nc].dwControlID);
945 trace(" ControlType=%s\n",
946 control_type(array[nc].dwControlType));
947 trace(" Control=0x%08x(%s)\n",
948 array[nc].fdwControl,
949 control_flags(array[nc].fdwControl));
950 trace(" Items=%d Min=%d Max=%d Step=%d\n",
951 array[nc].cMultipleItems,
952 S1(array[nc].Bounds).dwMinimum,
953 S1(array[nc].Bounds).dwMaximum,
954 array[nc].Metrics.cSteps);
956 mixer_test_controlW(mix, &array[nc]);
960 HeapFree(GetProcessHeap(),0,array);
966 test_mixerClose((HMIXER)mix);
970 static void mixer_testsA(void)
972 MIXERCAPSA capsA;
973 MMRESULT rc;
974 UINT ndev, d;
976 trace("--- Testing ASCII functions ---\n");
978 ndev=mixerGetNumDevs();
979 trace("found %d Mixer devices\n",ndev);
981 rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
982 ok(rc==MMSYSERR_BADDEVICEID,
983 "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n",
984 mmsys_error(rc));
986 for (d=0;d<ndev;d++)
987 mixer_test_deviceA(d);
990 static void mixer_testsW(void)
992 MIXERCAPSW capsW;
993 MMRESULT rc;
994 UINT ndev, d;
996 trace("--- Testing WCHAR functions ---\n");
998 ndev=mixerGetNumDevs();
999 trace("found %d Mixer devices\n",ndev);
1001 rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
1002 ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED,
1003 "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
1004 "expected, got %s\n", mmsys_error(rc));
1005 if (rc==MMSYSERR_NOTSUPPORTED)
1006 return;
1008 for (d=0;d<ndev;d++)
1009 mixer_test_deviceW(d);
1012 static void test_mixerOpen(void)
1014 HMIXER mix;
1015 HANDLE event;
1016 MMRESULT rc;
1017 UINT ndev, d;
1019 ndev = mixerGetNumDevs();
1021 /* Test mixerOpen with invalid device ID values. */
1022 rc = mixerOpen(&mix, ndev + 1, 0, 0, 0);
1023 ok(rc == MMSYSERR_BADDEVICEID,
1024 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
1025 mmsys_error(rc));
1027 rc = mixerOpen(&mix, -1, 0, 0, 0);
1028 ok(rc == MMSYSERR_BADDEVICEID ||
1029 rc == MMSYSERR_INVALHANDLE, /* NT4/W2K */
1030 "mixerOpen: MMSYSERR_BADDEVICEID or MMSYSERR_INVALHANDLE expected, got %s\n",
1031 mmsys_error(rc));
1033 for (d = 0; d < ndev; d++) {
1034 /* Test mixerOpen with valid device ID values and invalid parameters. */
1035 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_FUNCTION);
1036 ok(rc == MMSYSERR_INVALFLAG
1037 || rc == MMSYSERR_NOTSUPPORTED, /* 98/ME */
1038 "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n",
1039 mmsys_error(rc));
1041 rc = mixerOpen(&mix, d, 0xdeadbeef, 0, CALLBACK_WINDOW);
1042 ok(rc == MMSYSERR_INVALPARAM ||
1043 broken(rc == MMSYSERR_NOERROR /* 98 */),
1044 "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n",
1045 mmsys_error(rc));
1046 if (rc == MMSYSERR_NOERROR)
1047 test_mixerClose(mix);
1049 /* Test mixerOpen with a NULL dwCallback and CALLBACK_WINDOW flag. */
1050 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_WINDOW);
1051 ok(rc == MMSYSERR_NOERROR,
1052 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1053 mmsys_error(rc));
1054 if (rc == MMSYSERR_NOERROR)
1055 test_mixerClose(mix);
1057 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_THREAD);
1058 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1059 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1060 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1061 mmsys_error(rc));
1062 if (rc == MMSYSERR_NOERROR)
1063 test_mixerClose(mix);
1065 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_EVENT);
1066 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1067 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1068 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1069 mmsys_error(rc));
1070 if (rc == MMSYSERR_NOERROR)
1071 test_mixerClose(mix);
1073 event = CreateEventW(NULL, FALSE, FALSE, NULL);
1075 /* NOTSUPPORTED is not broken, but it enables the todo_wine marker. */
1076 rc = mixerOpen(&mix, d, (DWORD_PTR)event, 0, CALLBACK_EVENT);
1077 todo_wine
1078 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1079 broken(rc == MMSYSERR_NOTSUPPORTED), /* 98 */
1080 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1081 mmsys_error(rc));
1082 if (rc == MMSYSERR_NOERROR)
1083 test_mixerClose(mix);
1085 /* Test mixerOpen with normal parameters. */
1086 rc = mixerOpen(&mix, d, 0, 0, 0);
1087 ok(rc == MMSYSERR_NOERROR,
1088 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1089 mmsys_error(rc));
1091 if (rc == MMSYSERR_NOERROR)
1092 test_mixerClose(mix);
1094 rc = WaitForSingleObject(event, 0);
1095 ok(rc == WAIT_TIMEOUT, "WaitEvent %d\n", rc);
1096 CloseHandle(event);
1100 START_TEST(mixer)
1102 test_mixerOpen();
1103 mixer_testsA();
1104 mixer_testsW();