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
23 * add interactive tests
31 #include "wine/test.h"
37 #include "winmm_test.h"
39 static const char * line_flags(DWORD fdwLine)
41 static char flags[100];
44 if (fdwLine&MIXERLINE_LINEF_ACTIVE) {
45 strcat(flags,"MIXERLINE_LINEF_ACTIVE");
48 if (fdwLine&MIXERLINE_LINEF_DISCONNECTED) {
52 strcat(flags,"MIXERLINE_LINEF_DISCONNECTED");
56 if (fdwLine&MIXERLINE_LINEF_SOURCE) {
60 strcat(flags,"MIXERLINE_LINEF_SOURCE");
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);
95 static const char * target_type(DWORD dwType)
97 #define TYPE_TO_STR(x) case x: return #x
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);
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);
150 static const char * control_flags(DWORD fdwControl)
152 static char flags[100];
155 if (fdwControl&MIXERCONTROL_CONTROLF_UNIFORM) {
156 strcat(flags,"MIXERCONTROL_CONTROLF_UNIFORM");
159 if (fdwControl&MIXERCONTROL_CONTROLF_MULTIPLE) {
163 strcat(flags,"MIXERCONTROL_CONTROLF_MULTIPLE");
167 if (fdwControl&MIXERCONTROL_CONTROLF_DISABLED) {
171 strcat(flags,"MIXERCONTROL_CONTROLF_DISABLED");
177 static void mixer_test_controlA(HMIXER mix, LPMIXERCONTROLA control)
181 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
182 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
183 MIXERCONTROLDETAILS details;
184 MIXERCONTROLDETAILS_UNSIGNED value;
186 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
187 details.dwControlID = control->dwControlID;
188 details.cChannels = 1;
189 U(details).cMultipleItems = 0;
190 details.paDetails = &value;
191 details.cbDetails = sizeof(value);
193 /* read the current control value */
194 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
195 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
196 "MMSYSERR_NOERROR expected, got %s\n",
198 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
199 MIXERCONTROLDETAILS new_details;
200 MIXERCONTROLDETAILS_UNSIGNED new_value;
202 trace(" Value=%d\n",value.dwValue);
204 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
205 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
207 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
209 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
210 new_details.dwControlID = control->dwControlID;
211 new_details.cChannels = 1;
212 U(new_details).cMultipleItems = 0;
213 new_details.paDetails = &new_value;
214 new_details.cbDetails = sizeof(new_value);
216 /* change the control value by one step */
217 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
218 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
219 "MMSYSERR_NOERROR expected, got %s\n",
221 if (rc==MMSYSERR_NOERROR) {
222 MIXERCONTROLDETAILS ret_details;
223 MIXERCONTROLDETAILS_UNSIGNED ret_value;
225 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
226 ret_details.dwControlID = control->dwControlID;
227 ret_details.cChannels = 1;
228 U(ret_details).cMultipleItems = 0;
229 ret_details.paDetails = &ret_value;
230 ret_details.cbDetails = sizeof(ret_value);
232 /* read back the new control value */
233 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
234 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
235 "MMSYSERR_NOERROR expected, got %s\n",
237 if (rc==MMSYSERR_NOERROR) {
238 /* result may not match exactly because of rounding */
239 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
240 "Couldn't change value from %d to %d, returned %d\n",
241 value.dwValue,new_value.dwValue,ret_value.dwValue);
243 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
244 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
245 details.dwControlID = control->dwControlID;
246 details.cChannels = 1;
247 U(details).cMultipleItems = 0;
248 details.paDetails = &value;
249 details.cbDetails = sizeof(value);
251 /* restore original value */
252 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
253 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
254 "MMSYSERR_NOERROR expected, got %s\n",
260 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
261 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
262 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
263 MIXERCONTROLDETAILS details;
264 MIXERCONTROLDETAILS_BOOLEAN value;
266 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
267 details.dwControlID = control->dwControlID;
268 details.cChannels = 1;
269 U(details).cMultipleItems = 0;
270 details.paDetails = &value;
271 details.cbDetails = sizeof(value);
273 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
274 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
275 "MMSYSERR_NOERROR expected, got %s\n",
277 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
278 MIXERCONTROLDETAILS new_details;
279 MIXERCONTROLDETAILS_BOOLEAN new_value;
281 trace(" Value=%d\n",value.fValue);
283 if (value.fValue == FALSE)
284 new_value.fValue = TRUE;
286 new_value.fValue = FALSE;
288 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
289 new_details.dwControlID = control->dwControlID;
290 new_details.cChannels = 1;
291 U(new_details).cMultipleItems = 0;
292 new_details.paDetails = &new_value;
293 new_details.cbDetails = sizeof(new_value);
295 /* change the control value by one step */
296 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
297 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
298 "MMSYSERR_NOERROR expected, got %s\n",
300 if (rc==MMSYSERR_NOERROR) {
301 MIXERCONTROLDETAILS ret_details;
302 MIXERCONTROLDETAILS_BOOLEAN ret_value;
304 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
305 ret_details.dwControlID = control->dwControlID;
306 ret_details.cChannels = 1;
307 U(ret_details).cMultipleItems = 0;
308 ret_details.paDetails = &ret_value;
309 ret_details.cbDetails = sizeof(ret_value);
311 /* read back the new control value */
312 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
313 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
314 "MMSYSERR_NOERROR expected, got %s\n",
316 if (rc==MMSYSERR_NOERROR) {
317 /* result may not match exactly because of rounding */
318 ok(ret_value.fValue==new_value.fValue,
319 "Couldn't change value from %d to %d, returned %d\n",
320 value.fValue,new_value.fValue,ret_value.fValue);
322 if (ret_value.fValue==new_value.fValue) {
323 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
324 details.dwControlID = control->dwControlID;
325 details.cChannels = 1;
326 U(details).cMultipleItems = 0;
327 details.paDetails = &value;
328 details.cbDetails = sizeof(value);
330 /* restore original value */
331 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
332 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
333 "MMSYSERR_NOERROR expected, got %s\n",
344 static void mixer_test_deviceA(int device)
351 rc=mixerGetDevCapsA(device,0,sizeof(capsA));
352 ok(rc==MMSYSERR_INVALPARAM,
353 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
356 rc=mixerGetDevCapsA(device,&capsA,4);
357 ok(rc==MMSYSERR_NOERROR,
358 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
361 rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA));
362 ok(rc==MMSYSERR_NOERROR,
363 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
366 if (winetest_interactive) {
367 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%d\n", device,
368 capsA.szPname, capsA.vDriverVersion >> 8,
369 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid,
370 capsA.cDestinations);
372 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
373 capsA.szPname, capsA.vDriverVersion >> 8,
374 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid);
377 rc=mixerOpen(&mix, device, 0, 0, 0);
378 ok(rc==MMSYSERR_NOERROR,
379 "mixerOpen: MMSYSERR_NOERROR expected, got %s\n",mmsys_error(rc));
380 if (rc==MMSYSERR_NOERROR) {
381 rc=mixerOpen(&mix, device, 0, 0, CALLBACK_FUNCTION);
382 ok(rc==MMSYSERR_INVALFLAG,
383 "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n", mmsys_error(rc));
385 /* Shouldn't open without a valid HWND */
386 rc=mixerOpen(&mix, device, 0, 0, CALLBACK_WINDOW);
387 ok(rc==MMSYSERR_INVALPARAM,
388 "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc));
391 for (d=0;d<capsA.cDestinations;d++) {
392 MIXERLINEA mixerlineA;
393 mixerlineA.cbStruct = 0;
394 mixerlineA.dwDestination=d;
395 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
396 MIXER_GETLINEINFOF_DESTINATION);
397 ok(rc==MMSYSERR_INVALPARAM,
398 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
399 "MMSYSERR_INVALPARAM expected, got %s\n",
402 mixerlineA.cbStruct = sizeof(mixerlineA);
403 mixerlineA.dwDestination=capsA.cDestinations;
404 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
405 MIXER_GETLINEINFOF_DESTINATION);
406 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
407 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
408 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
411 mixerlineA.cbStruct = sizeof(mixerlineA);
412 mixerlineA.dwDestination=d;
413 rc=mixerGetLineInfoA((HMIXEROBJ)mix,0,
414 MIXER_GETLINEINFOF_DESTINATION);
415 ok(rc==MMSYSERR_INVALPARAM,
416 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
417 "MMSYSERR_INVALPARAM expected, got %s\n",
420 mixerlineA.cbStruct = sizeof(mixerlineA);
421 mixerlineA.dwDestination=d;
422 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,-1);
423 ok(rc==MMSYSERR_INVALFLAG,
424 "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n",
427 mixerlineA.cbStruct = sizeof(mixerlineA);
428 mixerlineA.dwDestination=d;
429 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
430 MIXER_GETLINEINFOF_DESTINATION);
431 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
432 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
433 "MMSYSERR_NOERROR expected, got %s\n",
435 if (rc==MMSYSERR_NODRIVER)
436 trace(" No Driver\n");
437 else if (rc==MMSYSERR_NOERROR) {
438 if (winetest_interactive) {
439 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
440 d,mixerlineA.szShortName, mixerlineA.szName,
441 mixerlineA.dwDestination,mixerlineA.dwSource);
442 trace(" LineID=%08x Channels=%d "
443 "Connections=%d Controls=%d\n",
444 mixerlineA.dwLineID,mixerlineA.cChannels,
445 mixerlineA.cConnections,mixerlineA.cControls);
446 trace(" State=0x%08x(%s)\n",
447 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
448 trace(" ComponentType=%s\n",
449 component_type(mixerlineA.dwComponentType));
451 target_type(mixerlineA.Target.dwType));
452 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
453 mixerlineA.Target.dwDeviceID,
454 mixerlineA.Target.szPname,
455 mixerlineA.Target.vDriverVersion >> 8,
456 mixerlineA.Target.vDriverVersion & 0xff,
457 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
459 ns=mixerlineA.cConnections;
461 mixerlineA.cbStruct = sizeof(mixerlineA);
462 mixerlineA.dwDestination=d;
463 mixerlineA.dwSource=s;
464 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
465 MIXER_GETLINEINFOF_SOURCE);
466 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
467 "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): "
468 "MMSYSERR_NOERROR expected, got %s\n",
470 if (rc==MMSYSERR_NODRIVER)
471 trace(" No Driver\n");
472 else if (rc==MMSYSERR_NOERROR) {
473 LPMIXERCONTROLA array;
474 MIXERLINECONTROLSA controls;
475 if (winetest_interactive) {
476 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
477 s,mixerlineA.szShortName, mixerlineA.szName,
478 mixerlineA.dwDestination,mixerlineA.dwSource);
479 trace(" LineID=%08x Channels=%d "
480 "Connections=%d Controls=%d\n",
481 mixerlineA.dwLineID,mixerlineA.cChannels,
482 mixerlineA.cConnections,mixerlineA.cControls);
483 trace(" State=0x%08x(%s)\n",
484 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
485 trace(" ComponentType=%s\n",
486 component_type(mixerlineA.dwComponentType));
488 target_type(mixerlineA.Target.dwType));
489 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
490 mixerlineA.Target.dwDeviceID,
491 mixerlineA.Target.szPname,
492 mixerlineA.Target.vDriverVersion >> 8,
493 mixerlineA.Target.vDriverVersion & 0xff,
494 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
496 if (mixerlineA.cControls) {
497 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
498 mixerlineA.cControls*sizeof(MIXERCONTROLA));
500 rc=mixerGetLineControlsA((HMIXEROBJ)mix,0,
501 MIXER_GETLINECONTROLSF_ALL);
502 ok(rc==MMSYSERR_INVALPARAM,
503 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
504 "MMSYSERR_INVALPARAM expected, got %s\n",
507 rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,-1);
508 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
509 "mixerGetLineControlsA(-1): "
510 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
513 controls.cbStruct = sizeof(MIXERLINECONTROLSA);
514 controls.cControls = mixerlineA.cControls;
515 controls.dwLineID = mixerlineA.dwLineID;
516 controls.pamxctrl = array;
517 controls.cbmxctrl = sizeof(MIXERCONTROLA);
519 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
520 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
522 rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,
523 MIXER_GETLINECONTROLSF_ALL);
524 ok(rc==MMSYSERR_NOERROR,
525 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
526 "MMSYSERR_NOERROR expected, got %s\n",
528 if (rc==MMSYSERR_NOERROR) {
529 for(nc=0;nc<mixerlineA.cControls;nc++) {
530 if (winetest_interactive) {
531 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
532 array[nc].szShortName,
533 array[nc].szName, array[nc].dwControlID);
534 trace(" ControlType=%s\n",
535 control_type(array[nc].dwControlType));
536 trace(" Control=0x%08x(%s)\n",
537 array[nc].fdwControl,
538 control_flags(array[nc].fdwControl));
539 trace(" Items=%d Min=%d Max=%d Step=%d\n",
540 array[nc].cMultipleItems,
541 S1(array[nc].Bounds).dwMinimum,
542 S1(array[nc].Bounds).dwMaximum,
543 array[nc].Metrics.cSteps);
546 mixer_test_controlA(mix, &array[nc]);
550 HeapFree(GetProcessHeap(),0,array);
558 ok(rc==MMSYSERR_NOERROR,
559 "mixerClose: MMSYSERR_BADDEVICEID expected, got %s\n",
564 static void mixer_test_controlW(HMIXER mix, LPMIXERCONTROLW control)
568 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
569 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
570 MIXERCONTROLDETAILS details;
571 MIXERCONTROLDETAILS_UNSIGNED value;
573 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
574 details.dwControlID = control->dwControlID;
575 details.cChannels = 1;
576 U(details).cMultipleItems = 0;
577 details.paDetails = &value;
578 details.cbDetails = sizeof(value);
580 /* read the current control value */
581 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
582 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
583 "MMSYSERR_NOERROR expected, got %s\n",
585 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
586 MIXERCONTROLDETAILS new_details;
587 MIXERCONTROLDETAILS_UNSIGNED new_value;
589 trace(" Value=%d\n",value.dwValue);
591 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
592 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
594 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
596 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
597 new_details.dwControlID = control->dwControlID;
598 new_details.cChannels = 1;
599 U(new_details).cMultipleItems = 0;
600 new_details.paDetails = &new_value;
601 new_details.cbDetails = sizeof(new_value);
603 /* change the control value by one step */
604 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
605 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
606 "MMSYSERR_NOERROR expected, got %s\n",
608 if (rc==MMSYSERR_NOERROR) {
609 MIXERCONTROLDETAILS ret_details;
610 MIXERCONTROLDETAILS_UNSIGNED ret_value;
612 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
613 ret_details.dwControlID = control->dwControlID;
614 ret_details.cChannels = 1;
615 U(ret_details).cMultipleItems = 0;
616 ret_details.paDetails = &ret_value;
617 ret_details.cbDetails = sizeof(ret_value);
619 /* read back the new control value */
620 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
621 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
622 "MMSYSERR_NOERROR expected, got %s\n",
624 if (rc==MMSYSERR_NOERROR) {
625 /* result may not match exactly because of rounding */
626 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
627 "Couldn't change value from %d to %d, returned %d\n",
628 value.dwValue,new_value.dwValue,ret_value.dwValue);
630 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
631 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
632 details.dwControlID = control->dwControlID;
633 details.cChannels = 1;
634 U(details).cMultipleItems = 0;
635 details.paDetails = &value;
636 details.cbDetails = sizeof(value);
638 /* restore original value */
639 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
640 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
641 "MMSYSERR_NOERROR expected, got %s\n",
647 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
648 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
649 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
650 MIXERCONTROLDETAILS details;
651 MIXERCONTROLDETAILS_BOOLEAN value;
653 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
654 details.dwControlID = control->dwControlID;
655 details.cChannels = 1;
656 U(details).cMultipleItems = 0;
657 details.paDetails = &value;
658 details.cbDetails = sizeof(value);
660 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
661 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
662 "MMSYSERR_NOERROR expected, got %s\n",
664 if (rc==MMSYSERR_NOERROR && winetest_interactive) {
665 MIXERCONTROLDETAILS new_details;
666 MIXERCONTROLDETAILS_BOOLEAN new_value;
668 trace(" Value=%d\n",value.fValue);
670 if (value.fValue == FALSE)
671 new_value.fValue = TRUE;
673 new_value.fValue = FALSE;
675 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
676 new_details.dwControlID = control->dwControlID;
677 new_details.cChannels = 1;
678 U(new_details).cMultipleItems = 0;
679 new_details.paDetails = &new_value;
680 new_details.cbDetails = sizeof(new_value);
682 /* change the control value by one step */
683 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
684 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
685 "MMSYSERR_NOERROR expected, got %s\n",
687 if (rc==MMSYSERR_NOERROR) {
688 MIXERCONTROLDETAILS ret_details;
689 MIXERCONTROLDETAILS_BOOLEAN ret_value;
691 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
692 ret_details.dwControlID = control->dwControlID;
693 ret_details.cChannels = 1;
694 U(ret_details).cMultipleItems = 0;
695 ret_details.paDetails = &ret_value;
696 ret_details.cbDetails = sizeof(ret_value);
698 /* read back the new control value */
699 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
700 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
701 "MMSYSERR_NOERROR expected, got %s\n",
703 if (rc==MMSYSERR_NOERROR) {
704 /* result may not match exactly because of rounding */
705 ok(ret_value.fValue==new_value.fValue,
706 "Couldn't change value from %d to %d, returned %d\n",
707 value.fValue,new_value.fValue,ret_value.fValue);
709 if (ret_value.fValue==new_value.fValue) {
710 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
711 details.dwControlID = control->dwControlID;
712 details.cChannels = 1;
713 U(details).cMultipleItems = 0;
714 details.paDetails = &value;
715 details.cbDetails = sizeof(value);
717 /* restore original value */
718 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
719 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
720 "MMSYSERR_NOERROR expected, got %s\n",
731 static void mixer_test_deviceW(int device)
737 char szShortName[MIXER_SHORT_NAME_CHARS];
738 char szName[MIXER_LONG_NAME_CHARS];
739 char szPname[MAXPNAMELEN];
741 rc=mixerGetDevCapsW(device,0,sizeof(capsW));
742 ok(rc==MMSYSERR_INVALPARAM,
743 "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n",
746 rc=mixerGetDevCapsW(device,&capsW,4);
747 ok(rc==MMSYSERR_NOERROR,
748 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
751 rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW));
752 ok(rc==MMSYSERR_NOERROR,
753 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
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);
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(&mix, device, 0, 0, 0);
771 ok(rc==MMSYSERR_NOERROR,
772 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",mmsys_error(rc));
773 if (rc==MMSYSERR_NOERROR) {
774 rc=mixerOpen(&mix, device, 0, 0, CALLBACK_FUNCTION);
775 ok(rc==MMSYSERR_INVALFLAG,
776 "mixerOpen: MMSYSERR_INVALFLAG expected, got %s\n", mmsys_error(rc));
778 /* Shouldn't open without a valid HWND */
779 rc=mixerOpen(&mix, device, 0, 0, CALLBACK_WINDOW);
780 ok(rc==MMSYSERR_INVALPARAM,
781 "mixerOpen: MMSYSERR_INVALPARAM expected, got %s\n", mmsys_error(rc));
783 for (d=0;d<capsW.cDestinations;d++) {
784 MIXERLINEW mixerlineW;
785 mixerlineW.cbStruct = 0;
786 mixerlineW.dwDestination=d;
787 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
788 MIXER_GETLINEINFOF_DESTINATION);
789 ok(rc==MMSYSERR_INVALPARAM,
790 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
791 "MMSYSERR_INVALPARAM expected, got %s\n",
794 mixerlineW.cbStruct = sizeof(mixerlineW);
795 mixerlineW.dwDestination=capsW.cDestinations;
796 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
797 MIXER_GETLINEINFOF_DESTINATION);
798 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
799 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
800 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
803 mixerlineW.cbStruct = sizeof(mixerlineW);
804 mixerlineW.dwDestination=d;
805 rc=mixerGetLineInfoW((HMIXEROBJ)mix,0,
806 MIXER_GETLINEINFOF_DESTINATION);
807 ok(rc==MMSYSERR_INVALPARAM,
808 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
809 "MMSYSERR_INVALPARAM expected, got %s\n",
812 mixerlineW.cbStruct = sizeof(mixerlineW);
813 mixerlineW.dwDestination=d;
814 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,-1);
815 ok(rc==MMSYSERR_INVALFLAG,
816 "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n",
819 mixerlineW.cbStruct = sizeof(mixerlineW);
820 mixerlineW.dwDestination=d;
821 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
822 MIXER_GETLINEINFOF_DESTINATION);
823 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
824 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
825 "MMSYSERR_NOERROR expected, got %s\n",
827 if (rc==MMSYSERR_NODRIVER)
828 trace(" No Driver\n");
829 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
830 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
831 MIXER_SHORT_NAME_CHARS,szShortName,
832 MIXER_SHORT_NAME_CHARS,NULL,NULL);
833 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
834 MIXER_LONG_NAME_CHARS,szName,
835 MIXER_LONG_NAME_CHARS,NULL,NULL);
836 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
838 MAXPNAMELEN,NULL, NULL);
839 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
840 d,szShortName,szName,
841 mixerlineW.dwDestination,mixerlineW.dwSource);
842 trace(" LineID=%08x Channels=%d "
843 "Connections=%d Controls=%d\n",
844 mixerlineW.dwLineID,mixerlineW.cChannels,
845 mixerlineW.cConnections,mixerlineW.cControls);
846 trace(" State=0x%08x(%s)\n",
847 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
848 trace(" ComponentType=%s\n",
849 component_type(mixerlineW.dwComponentType));
851 target_type(mixerlineW.Target.dwType));
852 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
853 mixerlineW.Target.dwDeviceID,szPname,
854 mixerlineW.Target.vDriverVersion >> 8,
855 mixerlineW.Target.vDriverVersion & 0xff,
856 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
858 ns=mixerlineW.cConnections;
860 mixerlineW.cbStruct = sizeof(mixerlineW);
861 mixerlineW.dwDestination=d;
862 mixerlineW.dwSource=s;
863 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
864 MIXER_GETLINEINFOF_SOURCE);
865 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
866 "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): "
867 "MMSYSERR_NOERROR expected, got %s\n",
869 if (rc==MMSYSERR_NODRIVER)
870 trace(" No Driver\n");
871 else if (rc==MMSYSERR_NOERROR) {
872 LPMIXERCONTROLW array;
873 MIXERLINECONTROLSW controls;
874 if (winetest_interactive) {
875 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
876 MIXER_SHORT_NAME_CHARS,szShortName,
877 MIXER_SHORT_NAME_CHARS,NULL,NULL);
878 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
879 MIXER_LONG_NAME_CHARS,szName,
880 MIXER_LONG_NAME_CHARS,NULL,NULL);
881 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
883 MAXPNAMELEN,NULL, NULL);
884 trace(" %d: \"%s\" (%s) Destination=%d Source=%d\n",
885 s,szShortName,szName,
886 mixerlineW.dwDestination,mixerlineW.dwSource);
887 trace(" LineID=%08x Channels=%d "
888 "Connections=%d Controls=%d\n",
889 mixerlineW.dwLineID,mixerlineW.cChannels,
890 mixerlineW.cConnections,mixerlineW.cControls);
891 trace(" State=0x%08x(%s)\n",
892 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
893 trace(" ComponentType=%s\n",
894 component_type(mixerlineW.dwComponentType));
896 target_type(mixerlineW.Target.dwType));
897 trace(" Device=%d (%s) %d.%d (%d:%d)\n",
898 mixerlineW.Target.dwDeviceID,szPname,
899 mixerlineW.Target.vDriverVersion >> 8,
900 mixerlineW.Target.vDriverVersion & 0xff,
901 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
903 if (mixerlineW.cControls) {
904 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
905 mixerlineW.cControls*sizeof(MIXERCONTROLW));
907 rc=mixerGetLineControlsW((HMIXEROBJ)mix,0,
908 MIXER_GETLINECONTROLSF_ALL);
909 ok(rc==MMSYSERR_INVALPARAM,
910 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
911 "MMSYSERR_INVALPARAM expected, got %s\n",
913 rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls,
915 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
916 "mixerGetLineControlsA(-1): "
917 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
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((HMIXEROBJ)mix,&controls,
930 MIXER_GETLINECONTROLSF_ALL);
931 ok(rc==MMSYSERR_NOERROR,
932 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
933 "MMSYSERR_NOERROR expected, got %s\n",
935 if (rc==MMSYSERR_NOERROR) {
936 for(nc=0;nc<mixerlineW.cControls;nc++) {
937 if (winetest_interactive) {
938 WideCharToMultiByte(CP_ACP,0,array[nc].szShortName,
939 MIXER_SHORT_NAME_CHARS,szShortName,
940 MIXER_SHORT_NAME_CHARS,NULL,NULL);
941 WideCharToMultiByte(CP_ACP,0,array[nc].szName,
942 MIXER_LONG_NAME_CHARS,szName,
943 MIXER_LONG_NAME_CHARS,NULL,NULL);
944 trace(" %d: \"%s\" (%s) ControlID=%d\n", nc,
945 szShortName, szName, array[nc].dwControlID);
946 trace(" ControlType=%s\n",
947 control_type(array[nc].dwControlType));
948 trace(" Control=0x%08x(%s)\n",
949 array[nc].fdwControl,
950 control_flags(array[nc].fdwControl));
951 trace(" Items=%d Min=%d Max=%d Step=%d\n",
952 array[nc].cMultipleItems,
953 S1(array[nc].Bounds).dwMinimum,
954 S1(array[nc].Bounds).dwMaximum,
955 array[nc].Metrics.cSteps);
957 mixer_test_controlW(mix, &array[nc]);
961 HeapFree(GetProcessHeap(),0,array);
968 ok(rc==MMSYSERR_NOERROR,
969 "mixerClose: MMSYSERR_BADDEVICEID expected, got %s\n",
974 static void mixer_testsA(void)
981 trace("--- Testing ASCII functions ---\n");
983 ndev=mixerGetNumDevs();
984 trace("found %d Mixer devices\n",ndev);
986 rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
987 ok(rc==MMSYSERR_BADDEVICEID,
988 "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n",
991 rc=mixerOpen(&mix, ndev+1, 0, 0, 0);
992 ok(rc==MMSYSERR_BADDEVICEID,
993 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
997 mixer_test_deviceA(d);
1000 static void mixer_testsW(void)
1007 trace("--- Testing WCHAR functions ---\n");
1009 ndev=mixerGetNumDevs();
1010 trace("found %d Mixer devices\n",ndev);
1012 rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
1013 ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED,
1014 "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
1015 "expected, got %s\n", mmsys_error(rc));
1016 if (rc==MMSYSERR_NOTSUPPORTED)
1019 rc=mixerOpen(&mix, ndev+1, 0, 0, 0);
1020 ok(rc==MMSYSERR_BADDEVICEID,
1021 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
1024 for (d=0;d<ndev;d++)
1025 mixer_test_deviceW(d);