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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) {
199 MIXERCONTROLDETAILS new_details;
200 MIXERCONTROLDETAILS_UNSIGNED new_value;
202 if (winetest_interactive)
203 trace(" Value=%ld\n",value.dwValue);
205 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
206 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
208 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
210 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
211 new_details.dwControlID = control->dwControlID;
212 new_details.cChannels = 1;
213 U(new_details).cMultipleItems = 0;
214 new_details.paDetails = &new_value;
215 new_details.cbDetails = sizeof(new_value);
217 /* change the control value by one step */
218 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
219 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
220 "MMSYSERR_NOERROR expected, got %s\n",
222 if (rc==MMSYSERR_NOERROR) {
223 MIXERCONTROLDETAILS ret_details;
224 MIXERCONTROLDETAILS_UNSIGNED ret_value;
226 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
227 ret_details.dwControlID = control->dwControlID;
228 ret_details.cChannels = 1;
229 U(ret_details).cMultipleItems = 0;
230 ret_details.paDetails = &ret_value;
231 ret_details.cbDetails = sizeof(ret_value);
233 /* read back the new control value */
234 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
235 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
236 "MMSYSERR_NOERROR expected, got %s\n",
238 if (rc==MMSYSERR_NOERROR) {
239 /* result may not match exactly because of rounding */
240 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
241 "Couldn't change value from %ld to %ld, returned %ld\n",
242 value.dwValue,new_value.dwValue,ret_value.dwValue);
244 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
245 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
246 details.dwControlID = control->dwControlID;
247 details.cChannels = 1;
248 U(details).cMultipleItems = 0;
249 details.paDetails = &value;
250 details.cbDetails = sizeof(value);
252 /* restore original value */
253 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
254 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
255 "MMSYSERR_NOERROR expected, got %s\n",
261 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
262 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
263 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
264 MIXERCONTROLDETAILS details;
265 MIXERCONTROLDETAILS_BOOLEAN value;
267 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
268 details.dwControlID = control->dwControlID;
269 details.cChannels = 1;
270 U(details).cMultipleItems = 0;
271 details.paDetails = &value;
272 details.cbDetails = sizeof(value);
274 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
275 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
276 "MMSYSERR_NOERROR expected, got %s\n",
278 if (rc==MMSYSERR_NOERROR) {
279 MIXERCONTROLDETAILS new_details;
280 MIXERCONTROLDETAILS_BOOLEAN new_value;
282 if (winetest_interactive)
283 trace(" Value=%ld\n",value.fValue);
285 if (value.fValue == FALSE)
286 new_value.fValue = TRUE;
288 new_value.fValue = FALSE;
290 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
291 new_details.dwControlID = control->dwControlID;
292 new_details.cChannels = 1;
293 U(new_details).cMultipleItems = 0;
294 new_details.paDetails = &new_value;
295 new_details.cbDetails = sizeof(new_value);
297 /* change the control value by one step */
298 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
299 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
300 "MMSYSERR_NOERROR expected, got %s\n",
302 if (rc==MMSYSERR_NOERROR) {
303 MIXERCONTROLDETAILS ret_details;
304 MIXERCONTROLDETAILS_BOOLEAN ret_value;
306 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
307 ret_details.dwControlID = control->dwControlID;
308 ret_details.cChannels = 1;
309 U(ret_details).cMultipleItems = 0;
310 ret_details.paDetails = &ret_value;
311 ret_details.cbDetails = sizeof(ret_value);
313 /* read back the new control value */
314 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
315 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
316 "MMSYSERR_NOERROR expected, got %s\n",
318 if (rc==MMSYSERR_NOERROR) {
319 /* result may not match exactly because of rounding */
320 ok(ret_value.fValue==new_value.fValue,
321 "Couldn't change value from %ld to %ld, returned %ld\n",
322 value.fValue,new_value.fValue,ret_value.fValue);
324 if (ret_value.fValue==new_value.fValue) {
325 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
326 details.dwControlID = control->dwControlID;
327 details.cChannels = 1;
328 U(details).cMultipleItems = 0;
329 details.paDetails = &value;
330 details.cbDetails = sizeof(value);
332 /* restore original value */
333 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
334 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
335 "MMSYSERR_NOERROR expected, got %s\n",
346 static void mixer_test_deviceA(int device)
353 rc=mixerGetDevCapsA(device,0,sizeof(capsA));
354 ok(rc==MMSYSERR_INVALPARAM,
355 "mixerGetDevCapsA: MMSYSERR_INVALPARAM expected, got %s\n",
358 rc=mixerGetDevCapsA(device,&capsA,4);
359 ok(rc==MMSYSERR_NOERROR,
360 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
363 rc=mixerGetDevCapsA(device,&capsA,sizeof(capsA));
364 ok(rc==MMSYSERR_NOERROR,
365 "mixerGetDevCapsA: MMSYSERR_NOERROR expected, got %s\n",
368 if (winetest_interactive) {
369 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%ld\n", device,
370 capsA.szPname, capsA.vDriverVersion >> 8,
371 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid,
372 capsA.cDestinations);
374 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
375 capsA.szPname, capsA.vDriverVersion >> 8,
376 capsA.vDriverVersion & 0xff,capsA.wMid,capsA.wPid);
379 rc=mixerOpen(&mix, device, 0, 0, 0);
380 ok(rc==MMSYSERR_NOERROR,
381 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",mmsys_error(rc));
382 if (rc==MMSYSERR_NOERROR) {
383 for (d=0;d<capsA.cDestinations;d++) {
384 MIXERLINEA mixerlineA;
385 mixerlineA.cbStruct = 0;
386 mixerlineA.dwDestination=d;
387 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
388 MIXER_GETLINEINFOF_DESTINATION);
389 ok(rc==MMSYSERR_INVALPARAM,
390 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
391 "MMSYSERR_INVALPARAM expected, got %s\n",
394 mixerlineA.cbStruct = sizeof(mixerlineA);
395 mixerlineA.dwDestination=capsA.cDestinations;
396 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
397 MIXER_GETLINEINFOF_DESTINATION);
398 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
399 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
400 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
403 mixerlineA.cbStruct = sizeof(mixerlineA);
404 mixerlineA.dwDestination=d;
405 rc=mixerGetLineInfoA((HMIXEROBJ)mix,0,
406 MIXER_GETLINEINFOF_DESTINATION);
407 ok(rc==MMSYSERR_INVALPARAM,
408 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
409 "MMSYSERR_INVALPARAM expected, got %s\n",
412 mixerlineA.cbStruct = sizeof(mixerlineA);
413 mixerlineA.dwDestination=d;
414 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,-1);
415 ok(rc==MMSYSERR_INVALFLAG,
416 "mixerGetLineInfoA(-1): MMSYSERR_INVALFLAG expected, got %s\n",
419 mixerlineA.cbStruct = sizeof(mixerlineA);
420 mixerlineA.dwDestination=d;
421 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
422 MIXER_GETLINEINFOF_DESTINATION);
423 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
424 "mixerGetLineInfoA(MIXER_GETLINEINFOF_DESTINATION): "
425 "MMSYSERR_NOERROR expected, got %s\n",
427 if (rc==MMSYSERR_NODRIVER)
428 trace(" No Driver\n");
429 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
430 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
431 d,mixerlineA.szShortName, mixerlineA.szName,
432 mixerlineA.dwDestination,mixerlineA.dwSource);
433 trace(" LineID=%08lx Channels=%ld "
434 "Connections=%ld Controls=%ld\n",
435 mixerlineA.dwLineID,mixerlineA.cChannels,
436 mixerlineA.cConnections,mixerlineA.cControls);
437 trace(" State=0x%08lx(%s)\n",
438 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
439 trace(" ComponentType=%s\n",
440 component_type(mixerlineA.dwComponentType));
442 target_type(mixerlineA.Target.dwType));
443 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
444 mixerlineA.Target.dwDeviceID,
445 mixerlineA.Target.szPname,
446 mixerlineA.Target.vDriverVersion >> 8,
447 mixerlineA.Target.vDriverVersion & 0xff,
448 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
450 ns=mixerlineA.cConnections;
452 mixerlineA.cbStruct = sizeof(mixerlineA);
453 mixerlineA.dwDestination=d;
454 mixerlineA.dwSource=s;
455 rc=mixerGetLineInfoA((HMIXEROBJ)mix,&mixerlineA,
456 MIXER_GETLINEINFOF_SOURCE);
457 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
458 "mixerGetLineInfoA(MIXER_GETLINEINFOF_SOURCE): "
459 "MMSYSERR_NOERROR expected, got %s\n",
461 if (rc==MMSYSERR_NODRIVER)
462 trace(" No Driver\n");
463 else if (rc==MMSYSERR_NOERROR) {
464 LPMIXERCONTROLA array;
465 MIXERLINECONTROLSA controls;
466 if (winetest_interactive) {
467 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
468 s,mixerlineA.szShortName, mixerlineA.szName,
469 mixerlineA.dwDestination,mixerlineA.dwSource);
470 trace(" LineID=%08lx Channels=%ld "
471 "Connections=%ld Controls=%ld\n",
472 mixerlineA.dwLineID,mixerlineA.cChannels,
473 mixerlineA.cConnections,mixerlineA.cControls);
474 trace(" State=0x%08lx(%s)\n",
475 mixerlineA.fdwLine,line_flags(mixerlineA.fdwLine));
476 trace(" ComponentType=%s\n",
477 component_type(mixerlineA.dwComponentType));
479 target_type(mixerlineA.Target.dwType));
480 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
481 mixerlineA.Target.dwDeviceID,
482 mixerlineA.Target.szPname,
483 mixerlineA.Target.vDriverVersion >> 8,
484 mixerlineA.Target.vDriverVersion & 0xff,
485 mixerlineA.Target.wMid, mixerlineA.Target.wPid);
487 if (mixerlineA.cControls) {
488 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
489 mixerlineA.cControls*sizeof(MIXERCONTROLA));
491 rc=mixerGetLineControlsA((HMIXEROBJ)mix,0,
492 MIXER_GETLINECONTROLSF_ALL);
493 ok(rc==MMSYSERR_INVALPARAM,
494 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
495 "MMSYSERR_INVALPARAM expected, got %s\n",
498 rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,-1);
499 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
500 "mixerGetLineControlsA(-1): "
501 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
504 controls.cbStruct = sizeof(MIXERLINECONTROLSA);
505 controls.cControls = mixerlineA.cControls;
506 controls.dwLineID = mixerlineA.dwLineID;
507 controls.pamxctrl = array;
508 controls.cbmxctrl = sizeof(MIXERCONTROLA);
510 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
511 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
513 rc=mixerGetLineControlsA((HMIXEROBJ)mix,&controls,
514 MIXER_GETLINECONTROLSF_ALL);
515 ok(rc==MMSYSERR_NOERROR,
516 "mixerGetLineControlsA(MIXER_GETLINECONTROLSF_ALL): "
517 "MMSYSERR_NOERROR expected, got %s\n",
519 if (rc==MMSYSERR_NOERROR) {
520 for(nc=0;nc<mixerlineA.cControls;nc++) {
521 if (winetest_interactive) {
522 trace(" %ld: \"%s\" (%s) ControlID=%ld\n", nc,
523 array[nc].szShortName,
524 array[nc].szName, array[nc].dwControlID);
525 trace(" ControlType=%s\n",
526 control_type(array[nc].dwControlType));
527 trace(" Control=0x%08lx(%s)\n",
528 array[nc].fdwControl,
529 control_flags(array[nc].fdwControl));
530 trace(" Items=%ld Min=%ld Max=%ld Step=%ld\n",
531 array[nc].cMultipleItems,
532 S1(array[nc].Bounds).dwMinimum,
533 S1(array[nc].Bounds).dwMaximum,
534 array[nc].Metrics.cSteps);
537 mixer_test_controlA(mix, &array[nc]);
541 HeapFree(GetProcessHeap(),0,array);
548 ok(rc==MMSYSERR_NOERROR,
549 "mixerClose: MMSYSERR_BADDEVICEID expected, got %s\n",
554 static void mixer_test_controlW(HMIXER mix, LPMIXERCONTROLW control)
558 if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME) ||
559 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_UNSIGNED)) {
560 MIXERCONTROLDETAILS details;
561 MIXERCONTROLDETAILS_UNSIGNED value;
563 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
564 details.dwControlID = control->dwControlID;
565 details.cChannels = 1;
566 U(details).cMultipleItems = 0;
567 details.paDetails = &value;
568 details.cbDetails = sizeof(value);
570 /* read the current control value */
571 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
572 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
573 "MMSYSERR_NOERROR expected, got %s\n",
575 if (rc==MMSYSERR_NOERROR) {
576 MIXERCONTROLDETAILS new_details;
577 MIXERCONTROLDETAILS_UNSIGNED new_value;
579 if (winetest_interactive)
580 trace(" Value=%ld\n",value.dwValue);
582 if (value.dwValue + control->Metrics.cSteps < S1(control->Bounds).dwMaximum)
583 new_value.dwValue = value.dwValue + control->Metrics.cSteps;
585 new_value.dwValue = value.dwValue - control->Metrics.cSteps;
587 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
588 new_details.dwControlID = control->dwControlID;
589 new_details.cChannels = 1;
590 U(new_details).cMultipleItems = 0;
591 new_details.paDetails = &new_value;
592 new_details.cbDetails = sizeof(new_value);
594 /* change the control value by one step */
595 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
596 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
597 "MMSYSERR_NOERROR expected, got %s\n",
599 if (rc==MMSYSERR_NOERROR) {
600 MIXERCONTROLDETAILS ret_details;
601 MIXERCONTROLDETAILS_UNSIGNED ret_value;
603 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
604 ret_details.dwControlID = control->dwControlID;
605 ret_details.cChannels = 1;
606 U(ret_details).cMultipleItems = 0;
607 ret_details.paDetails = &ret_value;
608 ret_details.cbDetails = sizeof(ret_value);
610 /* read back the new control value */
611 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
612 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
613 "MMSYSERR_NOERROR expected, got %s\n",
615 if (rc==MMSYSERR_NOERROR) {
616 /* result may not match exactly because of rounding */
617 ok(abs(ret_value.dwValue-new_value.dwValue)<=1,
618 "Couldn't change value from %ld to %ld, returned %ld\n",
619 value.dwValue,new_value.dwValue,ret_value.dwValue);
621 if (abs(ret_value.dwValue-new_value.dwValue)<=1) {
622 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
623 details.dwControlID = control->dwControlID;
624 details.cChannels = 1;
625 U(details).cMultipleItems = 0;
626 details.paDetails = &value;
627 details.cbDetails = sizeof(value);
629 /* restore original value */
630 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
631 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
632 "MMSYSERR_NOERROR expected, got %s\n",
638 } else if ((control->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) ||
639 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN) ||
640 (control->dwControlType == MIXERCONTROL_CONTROLTYPE_BUTTON)) {
641 MIXERCONTROLDETAILS details;
642 MIXERCONTROLDETAILS_BOOLEAN value;
644 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
645 details.dwControlID = control->dwControlID;
646 details.cChannels = 1;
647 U(details).cMultipleItems = 0;
648 details.paDetails = &value;
649 details.cbDetails = sizeof(value);
651 rc=mixerGetControlDetails((HMIXEROBJ)mix,&details,MIXER_GETCONTROLDETAILSF_VALUE);
652 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
653 "MMSYSERR_NOERROR expected, got %s\n",
655 if (rc==MMSYSERR_NOERROR) {
656 MIXERCONTROLDETAILS new_details;
657 MIXERCONTROLDETAILS_BOOLEAN new_value;
659 if (winetest_interactive)
660 trace(" Value=%ld\n",value.fValue);
662 if (value.fValue == FALSE)
663 new_value.fValue = TRUE;
665 new_value.fValue = FALSE;
667 new_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
668 new_details.dwControlID = control->dwControlID;
669 new_details.cChannels = 1;
670 U(new_details).cMultipleItems = 0;
671 new_details.paDetails = &new_value;
672 new_details.cbDetails = sizeof(new_value);
674 /* change the control value by one step */
675 rc=mixerSetControlDetails((HMIXEROBJ)mix,&new_details,MIXER_SETCONTROLDETAILSF_VALUE);
676 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
677 "MMSYSERR_NOERROR expected, got %s\n",
679 if (rc==MMSYSERR_NOERROR) {
680 MIXERCONTROLDETAILS ret_details;
681 MIXERCONTROLDETAILS_BOOLEAN ret_value;
683 ret_details.cbStruct = sizeof(MIXERCONTROLDETAILS);
684 ret_details.dwControlID = control->dwControlID;
685 ret_details.cChannels = 1;
686 U(ret_details).cMultipleItems = 0;
687 ret_details.paDetails = &ret_value;
688 ret_details.cbDetails = sizeof(ret_value);
690 /* read back the new control value */
691 rc=mixerGetControlDetails((HMIXEROBJ)mix,&ret_details,MIXER_GETCONTROLDETAILSF_VALUE);
692 ok(rc==MMSYSERR_NOERROR,"mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE): "
693 "MMSYSERR_NOERROR expected, got %s\n",
695 if (rc==MMSYSERR_NOERROR) {
696 /* result may not match exactly because of rounding */
697 ok(ret_value.fValue==new_value.fValue,
698 "Couldn't change value from %ld to %ld, returned %ld\n",
699 value.fValue,new_value.fValue,ret_value.fValue);
701 if (ret_value.fValue==new_value.fValue) {
702 details.cbStruct = sizeof(MIXERCONTROLDETAILS);
703 details.dwControlID = control->dwControlID;
704 details.cChannels = 1;
705 U(details).cMultipleItems = 0;
706 details.paDetails = &value;
707 details.cbDetails = sizeof(value);
709 /* restore original value */
710 rc=mixerSetControlDetails((HMIXEROBJ)mix,&details,MIXER_SETCONTROLDETAILSF_VALUE);
711 ok(rc==MMSYSERR_NOERROR,"mixerSetControlDetails(MIXER_SETCONTROLDETAILSF_VALUE): "
712 "MMSYSERR_NOERROR expected, got %s\n",
723 static void mixer_test_deviceW(int device)
729 char szShortName[MIXER_SHORT_NAME_CHARS];
730 char szName[MIXER_LONG_NAME_CHARS];
731 char szPname[MAXPNAMELEN];
733 rc=mixerGetDevCapsW(device,0,sizeof(capsW));
734 ok(rc==MMSYSERR_INVALPARAM,
735 "mixerGetDevCapsW: MMSYSERR_INVALPARAM expected, got %s\n",
738 rc=mixerGetDevCapsW(device,&capsW,4);
739 ok(rc==MMSYSERR_NOERROR,
740 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
743 rc=mixerGetDevCapsW(device,&capsW,sizeof(capsW));
744 ok(rc==MMSYSERR_NOERROR,
745 "mixerGetDevCapsW: MMSYSERR_NOERROR expected, got %s\n",
748 WideCharToMultiByte(CP_ACP,0,capsW.szPname, MAXPNAMELEN,szPname,
749 MAXPNAMELEN,NULL,NULL);
750 if (winetest_interactive) {
751 trace(" %d: \"%s\" %d.%d (%d:%d) destinations=%ld\n", device,
752 szPname, capsW.vDriverVersion >> 8,
753 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid,
754 capsW.cDestinations);
756 trace(" %d: \"%s\" %d.%d (%d:%d)\n", device,
757 szPname, capsW.vDriverVersion >> 8,
758 capsW.vDriverVersion & 0xff,capsW.wMid,capsW.wPid);
760 rc=mixerOpen(&mix, device, 0, 0, 0);
761 ok(rc==MMSYSERR_NOERROR,
762 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",mmsys_error(rc));
763 if (rc==MMSYSERR_NOERROR) {
764 for (d=0;d<capsW.cDestinations;d++) {
765 MIXERLINEW mixerlineW;
766 mixerlineW.cbStruct = 0;
767 mixerlineW.dwDestination=d;
768 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
769 MIXER_GETLINEINFOF_DESTINATION);
770 ok(rc==MMSYSERR_INVALPARAM,
771 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
772 "MMSYSERR_INVALPARAM expected, got %s\n",
775 mixerlineW.cbStruct = sizeof(mixerlineW);
776 mixerlineW.dwDestination=capsW.cDestinations;
777 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
778 MIXER_GETLINEINFOF_DESTINATION);
779 ok(rc==MMSYSERR_INVALPARAM||rc==MIXERR_INVALLINE,
780 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
781 "MMSYSERR_INVALPARAM or MIXERR_INVALLINE expected, got %s\n",
784 mixerlineW.cbStruct = sizeof(mixerlineW);
785 mixerlineW.dwDestination=d;
786 rc=mixerGetLineInfoW((HMIXEROBJ)mix,0,
787 MIXER_GETLINEINFOF_DESTINATION);
788 ok(rc==MMSYSERR_INVALPARAM,
789 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
790 "MMSYSERR_INVALPARAM expected, got %s\n",
793 mixerlineW.cbStruct = sizeof(mixerlineW);
794 mixerlineW.dwDestination=d;
795 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,-1);
796 ok(rc==MMSYSERR_INVALFLAG,
797 "mixerGetLineInfoW(-1): MMSYSERR_INVALFLAG expected, got %s\n",
800 mixerlineW.cbStruct = sizeof(mixerlineW);
801 mixerlineW.dwDestination=d;
802 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
803 MIXER_GETLINEINFOF_DESTINATION);
804 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
805 "mixerGetLineInfoW(MIXER_GETLINEINFOF_DESTINATION): "
806 "MMSYSERR_NOERROR expected, got %s\n",
808 if (rc==MMSYSERR_NODRIVER)
809 trace(" No Driver\n");
810 else if (rc==MMSYSERR_NOERROR && winetest_interactive) {
811 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
812 MIXER_SHORT_NAME_CHARS,szShortName,
813 MIXER_SHORT_NAME_CHARS,NULL,NULL);
814 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
815 MIXER_LONG_NAME_CHARS,szName,
816 MIXER_LONG_NAME_CHARS,NULL,NULL);
817 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
819 MAXPNAMELEN,NULL, NULL);
820 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
821 d,szShortName,szName,
822 mixerlineW.dwDestination,mixerlineW.dwSource);
823 trace(" LineID=%08lx Channels=%ld "
824 "Connections=%ld Controls=%ld\n",
825 mixerlineW.dwLineID,mixerlineW.cChannels,
826 mixerlineW.cConnections,mixerlineW.cControls);
827 trace(" State=0x%08lx(%s)\n",
828 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
829 trace(" ComponentType=%s\n",
830 component_type(mixerlineW.dwComponentType));
832 target_type(mixerlineW.Target.dwType));
833 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
834 mixerlineW.Target.dwDeviceID,szPname,
835 mixerlineW.Target.vDriverVersion >> 8,
836 mixerlineW.Target.vDriverVersion & 0xff,
837 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
839 ns=mixerlineW.cConnections;
841 mixerlineW.cbStruct = sizeof(mixerlineW);
842 mixerlineW.dwDestination=d;
843 mixerlineW.dwSource=s;
844 rc=mixerGetLineInfoW((HMIXEROBJ)mix,&mixerlineW,
845 MIXER_GETLINEINFOF_SOURCE);
846 ok(rc==MMSYSERR_NOERROR||rc==MMSYSERR_NODRIVER,
847 "mixerGetLineInfoW(MIXER_GETLINEINFOF_SOURCE): "
848 "MMSYSERR_NOERROR expected, got %s\n",
850 if (rc==MMSYSERR_NODRIVER)
851 trace(" No Driver\n");
852 else if (rc==MMSYSERR_NOERROR) {
853 LPMIXERCONTROLW array;
854 MIXERLINECONTROLSW controls;
855 if (winetest_interactive) {
856 WideCharToMultiByte(CP_ACP,0,mixerlineW.szShortName,
857 MIXER_SHORT_NAME_CHARS,szShortName,
858 MIXER_SHORT_NAME_CHARS,NULL,NULL);
859 WideCharToMultiByte(CP_ACP,0,mixerlineW.szName,
860 MIXER_LONG_NAME_CHARS,szName,
861 MIXER_LONG_NAME_CHARS,NULL,NULL);
862 WideCharToMultiByte(CP_ACP,0,mixerlineW.Target.szPname,
864 MAXPNAMELEN,NULL, NULL);
865 trace(" %ld: \"%s\" (%s) Destination=%ld Source=%ld\n",
866 s,szShortName,szName,
867 mixerlineW.dwDestination,mixerlineW.dwSource);
868 trace(" LineID=%08lx Channels=%ld "
869 "Connections=%ld Controls=%ld\n",
870 mixerlineW.dwLineID,mixerlineW.cChannels,
871 mixerlineW.cConnections,mixerlineW.cControls);
872 trace(" State=0x%08lx(%s)\n",
873 mixerlineW.fdwLine,line_flags(mixerlineW.fdwLine));
874 trace(" ComponentType=%s\n",
875 component_type(mixerlineW.dwComponentType));
877 target_type(mixerlineW.Target.dwType));
878 trace(" Device=%ld (%s) %d.%d (%d:%d)\n",
879 mixerlineW.Target.dwDeviceID,szPname,
880 mixerlineW.Target.vDriverVersion >> 8,
881 mixerlineW.Target.vDriverVersion & 0xff,
882 mixerlineW.Target.wMid, mixerlineW.Target.wPid);
884 if (mixerlineW.cControls) {
885 array=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
886 mixerlineW.cControls*sizeof(MIXERCONTROLW));
888 rc=mixerGetLineControlsW((HMIXEROBJ)mix,0,
889 MIXER_GETLINECONTROLSF_ALL);
890 ok(rc==MMSYSERR_INVALPARAM,
891 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
892 "MMSYSERR_INVALPARAM expected, got %s\n",
894 rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls,
896 ok(rc==MMSYSERR_INVALFLAG||rc==MMSYSERR_INVALPARAM,
897 "mixerGetLineControlsA(-1): "
898 "MMSYSERR_INVALFLAG or MMSYSERR_INVALPARAM expected, got %s\n",
901 controls.cbStruct = sizeof(MIXERLINECONTROLSW);
902 controls.cControls = mixerlineW.cControls;
903 controls.dwLineID = mixerlineW.dwLineID;
904 controls.pamxctrl = array;
905 controls.cbmxctrl = sizeof(MIXERCONTROLW);
907 /* FIXME: do MIXER_GETLINECONTROLSF_ONEBYID
908 * and MIXER_GETLINECONTROLSF_ONEBYTYPE
910 rc=mixerGetLineControlsW((HMIXEROBJ)mix,&controls,
911 MIXER_GETLINECONTROLSF_ALL);
912 ok(rc==MMSYSERR_NOERROR,
913 "mixerGetLineControlsW(MIXER_GETLINECONTROLSF_ALL): "
914 "MMSYSERR_NOERROR expected, got %s\n",
916 if (rc==MMSYSERR_NOERROR) {
917 for(nc=0;nc<mixerlineW.cControls;nc++) {
918 if (winetest_interactive) {
919 WideCharToMultiByte(CP_ACP,0,array[nc].szShortName,
920 MIXER_SHORT_NAME_CHARS,szShortName,
921 MIXER_SHORT_NAME_CHARS,NULL,NULL);
922 WideCharToMultiByte(CP_ACP,0,array[nc].szName,
923 MIXER_LONG_NAME_CHARS,szName,
924 MIXER_LONG_NAME_CHARS,NULL,NULL);
925 trace(" %ld: \"%s\" (%s) ControlID=%ld\n", nc,
926 szShortName, szName, array[nc].dwControlID);
927 trace(" ControlType=%s\n",
928 control_type(array[nc].dwControlType));
929 trace(" Control=0x%08lx(%s)\n",
930 array[nc].fdwControl,
931 control_flags(array[nc].fdwControl));
932 trace(" Items=%ld Min=%ld Max=%ld Step=%ld\n",
933 array[nc].cMultipleItems,
934 S1(array[nc].Bounds).dwMinimum,
935 S1(array[nc].Bounds).dwMaximum,
936 array[nc].Metrics.cSteps);
938 mixer_test_controlW(mix, &array[nc]);
942 HeapFree(GetProcessHeap(),0,array);
949 ok(rc==MMSYSERR_NOERROR,
950 "mixerClose: MMSYSERR_BADDEVICEID expected, got %s\n",
955 static void mixer_testsA(void)
962 trace("--- Testing ASCII functions ---\n");
964 ndev=mixerGetNumDevs();
965 trace("found %d Mixer devices\n",ndev);
967 rc=mixerGetDevCapsA(ndev+1,&capsA,sizeof(capsA));
968 ok(rc==MMSYSERR_BADDEVICEID,
969 "mixerGetDevCapsA: MMSYSERR_BADDEVICEID expected, got %s\n",
972 rc=mixerOpen(&mix, ndev+1, 0, 0, 0);
973 ok(rc==MMSYSERR_BADDEVICEID,
974 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
978 mixer_test_deviceA(d);
981 static void mixer_testsW(void)
988 trace("--- Testing WCHAR functions ---\n");
990 ndev=mixerGetNumDevs();
991 trace("found %d Mixer devices\n",ndev);
993 rc=mixerGetDevCapsW(ndev+1,&capsW,sizeof(capsW));
994 ok(rc==MMSYSERR_BADDEVICEID||rc==MMSYSERR_NOTSUPPORTED,
995 "mixerGetDevCapsW: MMSYSERR_BADDEVICEID or MMSYSERR_NOTSUPPORTED "
996 "expected, got %s\n", mmsys_error(rc));
997 if (rc==MMSYSERR_NOTSUPPORTED)
1000 rc=mixerOpen(&mix, ndev+1, 0, 0, 0);
1001 ok(rc==MMSYSERR_BADDEVICEID,
1002 "mixerOpen: MMSYSERR_BADDEVICEID expected, got %s\n",
1005 for (d=0;d<ndev;d++)
1006 mixer_test_deviceW(d);