riched20: Implement ITextRange::GetChar.
[wine/multimedia.git] / dlls / winmm / tests / mixer.c
blob982cf8bb1d8562b114e78d7e2207306ea8c391d9
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 for (d=0;d<capsA.cDestinations;d++) {
399 MIXERLINEA mixerlineA;
400 mixerlineA.cbStruct = 0;
401 mixerlineA.dwDestination=d;
402 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
403 ok(rc==MMSYSERR_INVALPARAM,
404 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
405 "MMSYSERR_INVALPARAM expected, got %s\n",
406 mmsys_error(rc));
408 mixerlineA.cbStruct = sizeof(mixerlineA);
409 mixerlineA.dwDestination=capsA.cDestinations;
410 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
411 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
412 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
413 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
414 mmsys_error(rc));
416 mixerlineA.cbStruct = sizeof(mixerlineA);
417 mixerlineA.dwDestination=d;
418 rc = mixerGetLineInfoA(mix, 0, MIXER_GETLINEINFOF_DESTINATION);
419 ok(rc==MMSYSERR_INVALPARAM,
420 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
421 "MMSYSERR_INVALPARAM expected, got %s\n",
422 mmsys_error(rc));
424 mixerlineA.cbStruct = sizeof(mixerlineA);
425 mixerlineA.dwDestination=d;
426 rc = mixerGetLineInfoA(mix, &mixerlineA, -1);
427 ok(rc==MMSYSERR_INVALFLAG,
428 "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n",
429 mmsys_error(rc));
431 mixerlineA.cbStruct = sizeof(mixerlineA);
432 mixerlineA.dwDestination=d;
433 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_DESTINATION);
434 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
435 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
436 "MMSYSERR_NOERROR expected, got %s\n",
437 mmsys_error(rc));
438 if (rc==MMSYSERR_NODRIVER)
439 trace(" No Driver\n");
440 else if (rc==MMSYSERR_NOERROR) {
441 if (winetest_interactive) {
442 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
443 d,mixerlineA.szShortName, mixerlineA.szName,
444 mixerlineA.dwDestination,mixerlineA.dwSource);
445 trace(" LineID=%08x Channels=%d "
446 "Connections=%d Controls=%d\n",
447 mixerlineA.dwLineID,mixerlineA.cChannels,
448 mixerlineA.cConnections,mixerlineA.cControls);
449 trace(" State=0x%08x(%s)\n",
450 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
451 trace(" ComponentType=%s\n",
452 component_type(mixerlineA.dwComponentType));
453 trace(" Type=%s\n",
454 target_type(mixerlineA.Target.dwType));
455 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
456 mixerlineA.Target.dwDeviceID,
457 mixerlineA.Target.szPname,
458 mixerlineA.Target.vDriverVersion >> 8,
459 mixerlineA.Target.vDriverVersion & 0xff,
460 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
462 ns=mixerlineA.cConnections;
463 for(s=0;s<ns;s++) {
464 mixerlineA.cbStruct = sizeof(mixerlineA);
465 mixerlineA.dwDestination=d;
466 mixerlineA.dwSource=s;
467 rc = mixerGetLineInfoA(mix, &mixerlineA, MIXER_GETLINEINFOF_SOURCE);
468 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
469 "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): "
470 "MMSYSERR_NOERROR expected, got %s\n",
471 mmsys_error(rc));
472 if (rc==MMSYSERR_NODRIVER)
473 trace(" No Driver\n");
474 else if (rc==MMSYSERR_NOERROR) {
475 LPMIXERCONTROLA array;
476 MIXERLINECONTROLSA controls;
477 if (winetest_interactive) {
478 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
479 s,mixerlineA.szShortName, mixerlineA.szName,
480 mixerlineA.dwDestination,mixerlineA.dwSource);
481 trace(" LineID=%08x Channels=%d "
482 "Connections=%d Controls=%d\n",
483 mixerlineA.dwLineID,mixerlineA.cChannels,
484 mixerlineA.cConnections,mixerlineA.cControls);
485 trace(" State=0x%08x(%s)\n",
486 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
487 trace(" ComponentType=%s\n",
488 component_type(mixerlineA.dwComponentType));
489 trace(" Type=%s\n",
490 target_type(mixerlineA.Target.dwType));
491 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
492 mixerlineA.Target.dwDeviceID,
493 mixerlineA.Target.szPname,
494 mixerlineA.Target.vDriverVersion >> 8,
495 mixerlineA.Target.vDriverVersion & 0xff,
496 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
498 if (mixerlineA.cControls) {
499 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
500 mixerlineA.cControls*sizeof(MIXERCONTROLA));
501 if (array) {
502 memset(&controls, 0, sizeof(controls));
504 rc = mixerGetLineControlsA(mix, 0, MIXER_GETLINECONTROLSF_ALL);
505 ok(rc==MMSYSERR_INVALPARAM,
506 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
507 "MMSYSERR_INVALPARAM expected, got %s\n",
508 mmsys_error(rc));
510 rc = mixerGetLineControlsA(mix, &controls, -1);
511 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
512 "mixerGetLineControlsA(-1): "
513 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
514 mmsys_error(rc));
516 controls.cbStruct = sizeof(MIXERLINECONTROLSA);
517 controls.cControls = mixerlineA.cControls;
518 controls.dwLineID = mixerlineA.dwLineID;
519 controls.pamxctrl = array;
520 controls.cbmxctrl = sizeof(MIXERCONTROLA);
522 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
523 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
525 rc = mixerGetLineControlsA(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
526 ok(rc==MMSYSERR_NOERROR,
527 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
528 "MMSYSERR_NOERROR expected, got %s\n",
529 mmsys_error(rc));
530 if (rc==MMSYSERR_NOERROR) {
531 for(nc=0;nc<mixerlineA.cControls;nc++) {
532 if (winetest_interactive) {
533 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
534 array[nc].szShortName,
535 array[nc].szName, array[nc].dwControlID);
536 trace(" ControlType=%s\n",
537 control_type(array[nc].dwControlType));
538 trace(" Control=0x%08x(%s)\n",
539 array[nc].fdwControl,
540 control_flags(array[nc].fdwControl));
541 trace(" Items=%d Min=%d Max=%d Step=%d\n",
542 array[nc].cMultipleItems,
543 S1(array[nc].Bounds).dwMinimum,
544 S1(array[nc].Bounds).dwMaximum,
545 array[nc].Metrics.cSteps);
548 mixer_test_controlA(mix, &array[nc]);
552 HeapFree(GetProcessHeap(),0,array);
559 test_mixerClose((HMIXER)mix);
563 static void mixer_test_controlW(HMIXEROBJ mix, MIXERCONTROLW *control)
565 MMRESULT rc;
567 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
568 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
569 MIXERCONTROLDETAILS details;
570 MIXERCONTROLDETAILS_UNSIGNED value;
572 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
573 details.dwControlID = control->dwControlID;
574 details.cChannels = 1;
575 U(details).cMultipleItems = 0;
576 details.paDetails = &value;
577 details.cbDetails = sizeof(value);
579 /* read the current control value */
580 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
581 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
582 "MMSYSERR_NOERROR expected, got %s\n",
583 mmsys_error(rc));
584 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
585 MIXERCONTROLDETAILS new_details;
586 MIXERCONTROLDETAILS_UNSIGNED new_value;
588 trace(" Value=%d\n",value.dwValue);
590 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
591 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
592 else
593 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
595 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
596 new_details.dwControlID = control->dwControlID;
597 new_details.cChannels = 1;
598 U(new_details).cMultipleItems = 0;
599 new_details.paDetails = &new_value;
600 new_details.cbDetails = sizeof(new_value);
602 /* change the control value by one step */
603 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
604 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
605 "MMSYSERR_NOERROR expected, got %s\n",
606 mmsys_error(rc));
607 if (rc==MMSYSERR_NOERROR) {
608 MIXERCONTROLDETAILS ret_details;
609 MIXERCONTROLDETAILS_UNSIGNED ret_value;
611 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
612 ret_details.dwControlID = control->dwControlID;
613 ret_details.cChannels = 1;
614 U(ret_details).cMultipleItems = 0;
615 ret_details.paDetails = &ret_value;
616 ret_details.cbDetails = sizeof(ret_value);
618 /* read back the new control value */
619 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
620 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
621 "MMSYSERR_NOERROR expected, got %s\n",
622 mmsys_error(rc));
623 if (rc==MMSYSERR_NOERROR) {
624 /* result may not match exactly because of rounding */
625 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
626 "Couldn't change value from %d to %d, returned %d\n",
627 value.dwValue,new_value.dwValue,ret_value.dwValue);
629 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
630 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
631 details.dwControlID = control->dwControlID;
632 details.cChannels = 1;
633 U(details).cMultipleItems = 0;
634 details.paDetails = &value;
635 details.cbDetails = sizeof(value);
637 /* restore original value */
638 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
639 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
640 "MMSYSERR_NOERROR expected, got %s\n",
641 mmsys_error(rc));
646 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
647 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
648 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
649 MIXERCONTROLDETAILS details;
650 MIXERCONTROLDETAILS_BOOLEAN value;
652 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
653 details.dwControlID = control->dwControlID;
654 details.cChannels = 1;
655 U(details).cMultipleItems = 0;
656 details.paDetails = &value;
657 details.cbDetails = sizeof(value);
659 rc = mixerGetControlDetailsW(mix, &details, MIXER_GETCONTROLDETAILSF_VALUE);
660 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
661 "MMSYSERR_NOERROR expected, got %s\n",
662 mmsys_error(rc));
663 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
664 MIXERCONTROLDETAILS new_details;
665 MIXERCONTROLDETAILS_BOOLEAN new_value;
667 trace(" Value=%d\n",value.fValue);
669 if (value.fValue == FALSE)
670 new_value.fValue = TRUE;
671 else
672 new_value.fValue = FALSE;
674 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
675 new_details.dwControlID = control->dwControlID;
676 new_details.cChannels = 1;
677 U(new_details).cMultipleItems = 0;
678 new_details.paDetails = &new_value;
679 new_details.cbDetails = sizeof(new_value);
681 /* change the control value by one step */
682 rc = mixerSetControlDetails(mix, &new_details, MIXER_SETCONTROLDETAILSF_VALUE);
683 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
684 "MMSYSERR_NOERROR expected, got %s\n",
685 mmsys_error(rc));
686 if (rc==MMSYSERR_NOERROR) {
687 MIXERCONTROLDETAILS ret_details;
688 MIXERCONTROLDETAILS_BOOLEAN ret_value;
690 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
691 ret_details.dwControlID = control->dwControlID;
692 ret_details.cChannels = 1;
693 U(ret_details).cMultipleItems = 0;
694 ret_details.paDetails = &ret_value;
695 ret_details.cbDetails = sizeof(ret_value);
697 /* read back the new control value */
698 rc = mixerGetControlDetailsW(mix, &ret_details, MIXER_GETCONTROLDETAILSF_VALUE);
699 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
700 "MMSYSERR_NOERROR expected, got %s\n",
701 mmsys_error(rc));
702 if (rc==MMSYSERR_NOERROR) {
703 /* result may not match exactly because of rounding */
704 ok(ret_value.fValue==new_value.fValue,
705 "Couldn't change value from %d to %d, returned %d\n",
706 value.fValue,new_value.fValue,ret_value.fValue);
708 if (ret_value.fValue==new_value.fValue) {
709 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
710 details.dwControlID = control->dwControlID;
711 details.cChannels = 1;
712 U(details).cMultipleItems = 0;
713 details.paDetails = &value;
714 details.cbDetails = sizeof(value);
716 /* restore original value */
717 rc = mixerSetControlDetails(mix, &details, MIXER_SETCONTROLDETAILSF_VALUE);
718 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
719 "MMSYSERR_NOERROR expected, got %s\n",
720 mmsys_error(rc));
725 } else {
726 /* FIXME */
730 static void mixer_test_deviceW(int device)
732 MIXERCAPSW capsW;
733 HMIXEROBJ mix;
734 MMRESULT rc;
735 DWORD d,s,ns,nc;
736 char szShortName[MIXER_SHORT_NAME_CHARS];
737 char szName[MIXER_LONG_NAME_CHARS];
738 char szPname[MAXPNAMELEN];
740 rc=mixerGetDevCapsW(device,0,sizeof(capsW));
741 ok(rc==MMSYSERR_INVALPARAM,
742 "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n",
743 mmsys_error(rc));
745 rc=mixerGetDevCapsW(device,&capsW,4);
746 ok(rc==MMSYSERR_NOERROR ||
747 rc==MMSYSERR_INVALPARAM, /* Vista and W2K8 */
748 "mixerGetDevCapsW: MMSYSERR_NOERROR or MMSYSERR_INVALPARAM expected, got %s\n",
749 mmsys_error(rc));
751 rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW));
752 ok(rc==MMSYSERR_NOERROR,
753 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
754 mmsys_error(rc));
756 WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname,
757 MAXPNAMELEN,NULL,NULL);
758 if (winetest_interactive) {
759 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device,
760 szPname, capsW.vDriverVersion >> 8,
761 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid,
762 capsW.cDestinations);
763 } else {
764 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
765 szPname, capsW.vDriverVersion >> 8,
766 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid);
770 rc = mixerOpen((HMIXER*)&mix, device, 0, 0, 0);
771 ok(rc==MMSYSERR_NOERROR,
772 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
773 if (rc==MMSYSERR_NOERROR) {
774 for (d=0;d<capsW.cDestinations;d++) {
775 MIXERLINEW mixerlineW;
776 mixerlineW.cbStruct = 0;
777 mixerlineW.dwDestination=d;
778 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
779 ok(rc==MMSYSERR_INVALPARAM,
780 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
781 "MMSYSERR_INVALPARAM expected, got %s\n",
782 mmsys_error(rc));
784 mixerlineW.cbStruct = sizeof(mixerlineW);
785 mixerlineW.dwDestination=capsW.cDestinations;
786 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
787 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
788 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
789 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
790 mmsys_error(rc));
792 mixerlineW.cbStruct = sizeof(mixerlineW);
793 mixerlineW.dwDestination=d;
794 rc = mixerGetLineInfoW(mix, 0, 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=d;
802 rc = mixerGetLineInfoW(mix, &mixerlineW, -1);
803 ok(rc==MMSYSERR_INVALFLAG,
804 "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n",
805 mmsys_error(rc));
807 mixerlineW.cbStruct = sizeof(mixerlineW);
808 mixerlineW.dwDestination=d;
809 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_DESTINATION);
810 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
811 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
812 "MMSYSERR_NOERROR expected, got %s\n",
813 mmsys_error(rc));
814 if (rc==MMSYSERR_NODRIVER)
815 trace(" No Driver\n");
816 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
817 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
818 MIXER_SHORT_NAME_CHARS,szShortName,
819 MIXER_SHORT_NAME_CHARS,NULL,NULL);
820 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
821 MIXER_LONG_NAME_CHARS,szName,
822 MIXER_LONG_NAME_CHARS,NULL,NULL);
823 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
824 MAXPNAMELEN,szPname,
825 MAXPNAMELEN,NULL, NULL);
826 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
827 d,szShortName,szName,
828 mixerlineW.dwDestination,mixerlineW.dwSource);
829 trace(" LineID=%08x Channels=%d "
830 "Connections=%d Controls=%d\n",
831 mixerlineW.dwLineID,mixerlineW.cChannels,
832 mixerlineW.cConnections,mixerlineW.cControls);
833 trace(" State=0x%08x(%s)\n",
834 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
835 trace(" ComponentType=%s\n",
836 component_type(mixerlineW.dwComponentType));
837 trace(" Type=%s\n",
838 target_type(mixerlineW.Target.dwType));
839 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
840 mixerlineW.Target.dwDeviceID,szPname,
841 mixerlineW.Target.vDriverVersion >> 8,
842 mixerlineW.Target.vDriverVersion & 0xff,
843 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
845 ns=mixerlineW.cConnections;
846 for(s=0;s<ns;s++) {
847 mixerlineW.cbStruct = sizeof(mixerlineW);
848 mixerlineW.dwDestination=d;
849 mixerlineW.dwSource=s;
850 rc = mixerGetLineInfoW(mix, &mixerlineW, MIXER_GETLINEINFOF_SOURCE);
851 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
852 "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): "
853 "MMSYSERR_NOERROR expected, got %s\n",
854 mmsys_error(rc));
855 if (rc==MMSYSERR_NODRIVER)
856 trace(" No Driver\n");
857 else if (rc==MMSYSERR_NOERROR) {
858 LPMIXERCONTROLW array;
859 MIXERLINECONTROLSW controls;
860 if (winetest_interactive) {
861 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
862 MIXER_SHORT_NAME_CHARS,szShortName,
863 MIXER_SHORT_NAME_CHARS,NULL,NULL);
864 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
865 MIXER_LONG_NAME_CHARS,szName,
866 MIXER_LONG_NAME_CHARS,NULL,NULL);
867 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
868 MAXPNAMELEN,szPname,
869 MAXPNAMELEN,NULL, NULL);
870 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
871 s,szShortName,szName,
872 mixerlineW.dwDestination,mixerlineW.dwSource);
873 trace(" LineID=%08x Channels=%d "
874 "Connections=%d Controls=%d\n",
875 mixerlineW.dwLineID,mixerlineW.cChannels,
876 mixerlineW.cConnections,mixerlineW.cControls);
877 trace(" State=0x%08x(%s)\n",
878 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
879 trace(" ComponentType=%s\n",
880 component_type(mixerlineW.dwComponentType));
881 trace(" Type=%s\n",
882 target_type(mixerlineW.Target.dwType));
883 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
884 mixerlineW.Target.dwDeviceID,szPname,
885 mixerlineW.Target.vDriverVersion >> 8,
886 mixerlineW.Target.vDriverVersion & 0xff,
887 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
889 if (mixerlineW.cControls) {
890 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
891 mixerlineW.cControls*sizeof(MIXERCONTROLW));
892 if (array) {
893 rc = mixerGetLineControlsW(mix, 0, MIXER_GETLINECONTROLSF_ALL);
894 ok(rc==MMSYSERR_INVALPARAM,
895 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
896 "MMSYSERR_INVALPARAM expected, got %s\n",
897 mmsys_error(rc));
898 rc = mixerGetLineControlsW(mix, &controls, -1);
899 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
900 "mixerGetLineControlsW(-1): "
901 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
902 mmsys_error(rc));
904 controls.cbStruct = sizeof(MIXERLINECONTROLSW);
905 controls.cControls = mixerlineW.cControls;
906 controls.dwLineID = mixerlineW.dwLineID;
907 controls.pamxctrl = array;
908 controls.cbmxctrl = sizeof(MIXERCONTROLW);
910 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
911 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
913 rc = mixerGetLineControlsW(mix, &controls, MIXER_GETLINECONTROLSF_ALL);
914 ok(rc==MMSYSERR_NOERROR,
915 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
916 "MMSYSERR_NOERROR expected, got %s\n",
917 mmsys_error(rc));
918 if (rc==MMSYSERR_NOERROR) {
919 for(nc=0;nc<mixerlineW.cControls;nc++) {
920 if (winetest_interactive) {
921 WideCharToMultiByte(CP_ACP,0,array[nc].szShortName,
922 MIXER_SHORT_NAME_CHARS,szShortName,
923 MIXER_SHORT_NAME_CHARS,NULL,NULL);
924 WideCharToMultiByte(CP_ACP,0,array[nc].szName,
925 MIXER_LONG_NAME_CHARS,szName,
926 MIXER_LONG_NAME_CHARS,NULL,NULL);
927 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
928 szShortName, szName, array[nc].dwControlID);
929 trace(" ControlType=%s\n",
930 control_type(array[nc].dwControlType));
931 trace(" Control=0x%08x(%s)\n",
932 array[nc].fdwControl,
933 control_flags(array[nc].fdwControl));
934 trace(" Items=%d Min=%d Max=%d Step=%d\n",
935 array[nc].cMultipleItems,
936 S1(array[nc].Bounds).dwMinimum,
937 S1(array[nc].Bounds).dwMaximum,
938 array[nc].Metrics.cSteps);
940 mixer_test_controlW(mix, &array[nc]);
944 HeapFree(GetProcessHeap(),0,array);
950 test_mixerClose((HMIXER)mix);
954 static void mixer_testsA(void)
956 MIXERCAPSA capsA;
957 MMRESULT rc;
958 UINT ndev, d;
960 trace("--- Testing ASCII functions ---\n");
962 ndev=mixerGetNumDevs();
963 trace("found %d Mixer devices\n",ndev);
965 rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
966 ok(rc==MMSYSERR_BADDEVICEID,
967 "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n",
968 mmsys_error(rc));
970 for (d=0;d<ndev;d++)
971 mixer_test_deviceA(d);
974 static void mixer_testsW(void)
976 MIXERCAPSW capsW;
977 MMRESULT rc;
978 UINT ndev, d;
980 trace("--- Testing WCHAR functions ---\n");
982 ndev=mixerGetNumDevs();
983 trace("found %d Mixer devices\n",ndev);
985 rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
986 ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED,
987 "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
988 "expected, got %s\n", mmsys_error(rc));
989 if (rc==MMSYSERR_NOTSUPPORTED)
990 return;
992 for (d=0;d<ndev;d++)
993 mixer_test_deviceW(d);
996 static void test_mixerOpen(void)
998 HMIXER mix;
999 HANDLE event;
1000 MMRESULT rc;
1001 UINT ndev, d;
1003 ndev = mixerGetNumDevs();
1005 /* Test mixerOpen with invalid device ID values. */
1006 rc = mixerOpen(&mix, ndev + 1, 0, 0, 0);
1007 ok(rc == MMSYSERR_BADDEVICEID,
1008 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
1009 mmsys_error(rc));
1011 rc = mixerOpen(&mix, -1, 0, 0, 0);
1012 ok(rc == MMSYSERR_BADDEVICEID ||
1013 rc == MMSYSERR_INVALHANDLE, /* NT4/W2K */
1014 "mixerOpen: MMSYSERR_BADDEVICEID or MMSYSERR_INVALHANDLE expected, got %s\n",
1015 mmsys_error(rc));
1017 for (d = 0; d < ndev; d++) {
1018 /* Test mixerOpen with valid device ID values and invalid parameters. */
1019 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_FUNCTION);
1020 ok(rc == MMSYSERR_INVALFLAG
1021 || rc == MMSYSERR_NOTSUPPORTED, /* 98/ME */
1022 "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n",
1023 mmsys_error(rc));
1025 rc = mixerOpen(&mix, d, 0xdeadbeef, 0, CALLBACK_WINDOW);
1026 ok(rc == MMSYSERR_INVALPARAM ||
1027 broken(rc == MMSYSERR_NOERROR /* 98 */),
1028 "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n",
1029 mmsys_error(rc));
1030 if (rc == MMSYSERR_NOERROR)
1031 test_mixerClose(mix);
1033 /* Test mixerOpen with a NULL dwCallback and CALLBACK_WINDOW flag. */
1034 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_WINDOW);
1035 ok(rc == MMSYSERR_NOERROR,
1036 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1037 mmsys_error(rc));
1038 if (rc == MMSYSERR_NOERROR)
1039 test_mixerClose(mix);
1041 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_THREAD);
1042 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1043 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1044 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1045 mmsys_error(rc));
1046 if (rc == MMSYSERR_NOERROR)
1047 test_mixerClose(mix);
1049 rc = mixerOpen(&mix, d, 0, 0, CALLBACK_EVENT);
1050 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1051 rc == MMSYSERR_NOTSUPPORTED, /* 98 */
1052 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1053 mmsys_error(rc));
1054 if (rc == MMSYSERR_NOERROR)
1055 test_mixerClose(mix);
1057 event = CreateEventW(NULL, FALSE, FALSE, NULL);
1059 /* NOTSUPPORTED is not broken, but it enables the todo_wine marker. */
1060 rc = mixerOpen(&mix, d, (DWORD_PTR)event, 0, CALLBACK_EVENT);
1061 todo_wine
1062 ok(rc == MMSYSERR_NOERROR /* since w2k */ ||
1063 broken(rc == MMSYSERR_NOTSUPPORTED), /* 98 */
1064 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1065 mmsys_error(rc));
1066 if (rc == MMSYSERR_NOERROR)
1067 test_mixerClose(mix);
1069 /* Test mixerOpen with normal parameters. */
1070 rc = mixerOpen(&mix, d, 0, 0, 0);
1071 ok(rc == MMSYSERR_NOERROR,
1072 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",
1073 mmsys_error(rc));
1075 if (rc == MMSYSERR_NOERROR)
1076 test_mixerClose(mix);
1078 rc = WaitForSingleObject(event, 0);
1079 ok(rc == WAIT_TIMEOUT, "WaitEvent %d\n", rc);
1080 CloseHandle(event);
1084 START_TEST(mixer)
1086 test_mixerOpen();
1087 mixer_testsA();
1088 mixer_testsW();