1 /*
2 * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27 #define USE_ERROR
28 //#define USE_TRACE
29
30 #ifndef WIN32_EXTRA_LEAN
31 #define WIN32_EXTRA_LEAN
32 #endif
33 #ifndef WIN32_LEAN_AND_MEAN
34 #define WIN32_LEAN_AND_MEAN
35 #endif
36
37 #include <windows.h>
38 #include <mmsystem.h>
39 #include "Ports.h"
40
41 /* include to prevent charset problem */
42 #include "PLATFORM_API_WinOS_Charset_Util.h"
43
44 #if USE_PORTS == TRUE
45
46 typedef struct tag_PortControlID PortControlID;
47
48 typedef struct tag_PortInfo {
49 // Windows API stuff
50 HMIXER handle;
51 INT32 mixerIndex;
52 int dstLineCount; // how many MIXERLINE structs in dstMixerLine
53 MIXERLINE* dstLines;
54 int srcLineCount; // how many MIXERLINE structs in srcMixerLine
55 MIXERLINE* srcLines; // contains all the Source Lines of dstLines
56 // Java Sound mapping
57 int targetPortCount; // one port per dstLine (playback)
58 int sourcePortCount; // only WAVEIN; one port maps to one srcLine
59 LPMIXERLINE* ports; // points into dstLines and dstLines. Starts with Target Ports (Playback)
60 int maxControlCount; // upper bound of number of controls
61 int usedControlIDs; // number of items already filled in controlIDs
62 PortControlID* controlIDs; // the control IDs themselves
63 int usedMuxData;
64 MIXERCONTROLDETAILS_BOOLEAN* muxData;
65 } PortInfo;
66
67 #define PORT_CONTROL_TYPE_BOOLEAN 1
68 #define PORT_CONTROL_TYPE_SIGNED 2
69 #define PORT_CONTROL_TYPE_UNSIGNED 3
70 //#define PORT_CONTROL_TYPE_UNSIGNED_DB 4
71 #define PORT_CONTROL_TYPE_FAKE_VOLUME 5
72 #define PORT_CONTROL_TYPE_FAKE_BALANCE 6
73 #define PORT_CONTROL_TYPE_MUX 5
74 #define PORT_CONTROL_TYPE_MIXER 6
75
76 typedef struct tag_PortControlID {
77 PortInfo* portInfo;
78 INT32 controlType; // one of PORT_CONTROL_TYPE_XX
79 INT32 min;
80 INT32 max;
81 MIXERCONTROLDETAILS details;
82 union {
83 MIXERCONTROLDETAILS_BOOLEAN boolValue;
84 MIXERCONTROLDETAILS_SIGNED signedValue;
85 MIXERCONTROLDETAILS_UNSIGNED unsignedValue[2];
86 INT32 muxIndex;
87 };
88 } PortControlID;
89
90
91 int getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls);
92
PORT_GetPortMixerCount()93 INT32 PORT_GetPortMixerCount() {
94 return (INT32) mixerGetNumDevs();
95 }
96
97 #ifdef USE_TRACE
98
getLineFlags(DWORD flags)99 char* getLineFlags(DWORD flags) {
100 static char ret[100];
101 ret[0]=0;
102 if (flags & MIXERLINE_LINEF_ACTIVE) {
103 strcat(ret, "ACTIVE ");
104 flags ^= MIXERLINE_LINEF_ACTIVE;
105 }
106 if (flags & MIXERLINE_LINEF_DISCONNECTED) {
107 strcat(ret, "DISCONNECTED ");
108 flags ^= MIXERLINE_LINEF_DISCONNECTED;
109 }
110 if (flags & MIXERLINE_LINEF_SOURCE) {
111 strcat(ret, "SOURCE ");
112 flags ^= MIXERLINE_LINEF_SOURCE;
113 }
114 if (flags!=0) {
115 UINT_PTR r = (UINT_PTR) ret;
116 r += strlen(ret);
117 sprintf((char*) r, "%d", flags);
118 }
119 return ret;
120 }
121
getComponentType(int componentType)122 char* getComponentType(int componentType) {
123 switch (componentType) {
124 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return "DST_HEADPHONES";
125 case MIXERLINE_COMPONENTTYPE_DST_LINE: return "DST_LINE";
126 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return "DST_SPEAKERS";
127 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return "DST_DIGITAL";
128 case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return "DST_MONITOR";
129 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return "DST_TELEPHONE";
130 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return "DST_UNDEFINED";
131 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return "DST_VOICEIN";
132 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return "DST_WAVEIN";
133
134 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return "SRC_COMPACTDISC";
135 case MIXERLINE_COMPONENTTYPE_SRC_LINE: return "SRC_LINE";
136 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return "SRC_MICROPHONE";
137 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return "SRC_ANALOG";
138 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return "SRC_AUXILIARY";
139 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return "SRC_DIGITAL";
140 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return "SRC_PCSPEAKER";
141 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return "SRC_SYNTHESIZER";
142 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return "SRC_TELEPHONE";
143 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return "SRC_UNDEFINED";
144 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return "SRC_WAVEOUT";
145 }
146 return "";
147 }
148
printMixerLine(MIXERLINE * mixerLine)149 void printMixerLine(MIXERLINE* mixerLine) {
150 TRACE2("MIXERLINE destination=%d, source=%d, ", mixerLine->dwDestination, mixerLine->dwSource);
151 TRACE3("channels=%d, connections=%d, controls=%d, ", mixerLine->cChannels, mixerLine->cConnections, mixerLine->cControls);
152 TRACE3("\"%s\", fdwLine=%s, componentType=%s\n", mixerLine->szName, getLineFlags(mixerLine->fdwLine), getComponentType(mixerLine->dwComponentType));
153 }
154
getControlClass(int controlType)155 char* getControlClass(int controlType) {
156 switch (controlType & MIXERCONTROL_CT_CLASS_MASK) {
157 case MIXERCONTROL_CT_CLASS_CUSTOM : return "CLASS_CUSTOM";
158 case MIXERCONTROL_CT_CLASS_FADER : return "CLASS_FADER ";
159 case MIXERCONTROL_CT_CLASS_LIST : return "CLASS_LIST ";
160 case MIXERCONTROL_CT_CLASS_METER : return "CLASS_METER ";
161 case MIXERCONTROL_CT_CLASS_NUMBER : return "CLASS_NUMBER";
162 case MIXERCONTROL_CT_CLASS_SLIDER : return "CLASS_SLIDER";
163 case MIXERCONTROL_CT_CLASS_SWITCH : return "CLASS_SWITCH";
164 case MIXERCONTROL_CT_CLASS_TIME : return "CLASS_TIME ";
165 }
166 return "unknown class";
167 }
168
getControlType(int controlType)169 char* getControlType(int controlType) {
170 switch (controlType) {
171 case MIXERCONTROL_CONTROLTYPE_CUSTOM : return "CUSTOM ";
172 case MIXERCONTROL_CONTROLTYPE_BASS : return "BASS ";
173 case MIXERCONTROL_CONTROLTYPE_EQUALIZER : return "EQUALIZER ";
174 case MIXERCONTROL_CONTROLTYPE_FADER : return "FADER ";
175 case MIXERCONTROL_CONTROLTYPE_TREBLE : return "TREBLE ";
176 case MIXERCONTROL_CONTROLTYPE_VOLUME : return "VOLUME ";
177 case MIXERCONTROL_CONTROLTYPE_MIXER : return "MIXER ";
178 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT : return "MULTIPLESELECT ";
179 case MIXERCONTROL_CONTROLTYPE_MUX : return "MUX ";
180 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT : return "SINGLESELECT ";
181 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER : return "BOOLEANMETER ";
182 case MIXERCONTROL_CONTROLTYPE_PEAKMETER : return "PEAKMETER ";
183 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER : return "SIGNEDMETER ";
184 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER : return "UNSIGNEDMETER ";
185 case MIXERCONTROL_CONTROLTYPE_DECIBELS : return "DECIBELS ";
186 case MIXERCONTROL_CONTROLTYPE_PERCENT : return "PERCENT ";
187 case MIXERCONTROL_CONTROLTYPE_SIGNED : return "SIGNED ";
188 case MIXERCONTROL_CONTROLTYPE_UNSIGNED : return "UNSIGNED ";
189 case MIXERCONTROL_CONTROLTYPE_PAN : return "PAN ";
190 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN : return "QSOUNDPAN ";
191 case MIXERCONTROL_CONTROLTYPE_SLIDER : return "SLIDER ";
192 case MIXERCONTROL_CONTROLTYPE_BOOLEAN : return "BOOLEAN ";
193 case MIXERCONTROL_CONTROLTYPE_BUTTON : return "BUTTON ";
194 case MIXERCONTROL_CONTROLTYPE_LOUDNESS : return "LOUDNESS ";
195 case MIXERCONTROL_CONTROLTYPE_MONO : return "MONO ";
196 case MIXERCONTROL_CONTROLTYPE_MUTE : return "MUTE ";
197 case MIXERCONTROL_CONTROLTYPE_ONOFF : return "ONOFF ";
198 case MIXERCONTROL_CONTROLTYPE_STEREOENH : return "STEREOENH ";
199 case MIXERCONTROL_CONTROLTYPE_MICROTIME : return "MICROTIME ";
200 case MIXERCONTROL_CONTROLTYPE_MILLITIME : return "MILLITIME ";
201 }
202 return "unknown";
203 }
204
getControlState(DWORD controlState)205 char* getControlState(DWORD controlState) {
206 static char ret[100];
207 ret[0]=0;
208 if (controlState & MIXERCONTROL_CONTROLF_DISABLED) {
209 strcat(ret, "DISABLED ");
210 controlState ^= MIXERCONTROL_CONTROLF_DISABLED;
211 }
212 if (controlState & MIXERCONTROL_CONTROLF_MULTIPLE) {
213 strcat(ret, "MULTIPLE ");
214 controlState ^= MIXERCONTROL_CONTROLF_MULTIPLE;
215 }
216 if (controlState & MIXERCONTROL_CONTROLF_UNIFORM) {
217 strcat(ret, "UNIFORM ");
218 controlState ^= MIXERCONTROL_CONTROLF_UNIFORM;
219 }
220 if (controlState!=0) {
221 UINT_PTR r = (UINT_PTR) ret;
222 r += strlen(ret);
223 sprintf((char*) r, "%d", controlState);
224 }
225 return ret;
226 }
227
printControl(MIXERCONTROL * control)228 void printControl(MIXERCONTROL* control) {
229 TRACE3(" %s: dwControlType=%s/%s, ", control->szName, getControlClass(control->dwControlType), getControlType(control->dwControlType));
230 TRACE3("multpleItems=%d, state=%d, %s\n", control->cMultipleItems, control->fdwControl, getControlState(control->fdwControl));
231 }
232
printMixerLineControls(HMIXER handle,MIXERLINE * mixerLine)233 void printMixerLineControls(HMIXER handle, MIXERLINE* mixerLine) {
234 MIXERLINECONTROLS controls;
235 DWORD i;
236 TRACE1(" Controls for %s:\n", mixerLine->szName);
237 if (getControlInfo(handle, mixerLine, &controls)) {
238 for (i = 0; i < controls.cControls; i++) {
239 printControl(&controls.pamxctrl[i]);
240 }
241 if (controls.pamxctrl) {
242 free(controls.pamxctrl);
243 controls.pamxctrl = NULL;
244 }
245 }
246 }
247
printInfo(PortInfo * info)248 void printInfo(PortInfo* info) {
249 TRACE5(" PortInfo %p: handle=%p, mixerIndex=%d, dstLineCount=%d, dstLines=%p, ", info, (void*) info->handle, info->mixerIndex, info->dstLineCount, info->dstLines);
250 TRACE5("srcLineCount=%d, srcLines=%p, targetPortCount=%d, sourcePortCount=%d, ports=%p, ", info->srcLineCount, info->srcLines, info->targetPortCount, info->sourcePortCount, info->ports);
251 TRACE3("maxControlCount=%d, usedControlIDs=%d, controlIDs=%p \n", info->maxControlCount, info->usedControlIDs, info->controlIDs);
252 TRACE2("usedMuxData=%d, muxData=%p, controlIDs=%p \n", info->usedMuxData, info->muxData);
253 }
254
255 #endif // USE_TRACE
256
257 // internal utility functions
258
getMixerLineByDestination(HMIXER handle,DWORD dstIndex,MIXERLINE * mixerLine)259 int getMixerLineByDestination(HMIXER handle, DWORD dstIndex, MIXERLINE* mixerLine) {
260 mixerLine->cbStruct = sizeof(MIXERLINE);
261 mixerLine->dwDestination = dstIndex;
262 if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
263 MIXER_GETLINEINFOF_DESTINATION | MIXER_OBJECTF_HMIXER
264 ) == MMSYSERR_NOERROR) {
265 return TRUE;
266 }
267 mixerLine->cControls = 0;
268 mixerLine->cConnections = 0;
269 return FALSE;
270 }
271
getMixerLineByType(HMIXER handle,DWORD linetype,MIXERLINE * mixerLine)272 int getMixerLineByType(HMIXER handle, DWORD linetype, MIXERLINE* mixerLine) {
273 mixerLine->cbStruct = sizeof(MIXERLINE);
274 mixerLine->dwComponentType = linetype;
275 if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
276 MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_HMIXER
277 ) == MMSYSERR_NOERROR) {
278 return TRUE;
279 }
280 mixerLine->cControls = 0;
281 mixerLine->cConnections = 0;
282 return FALSE;
283 }
284
getMixerLineBySource(HMIXER handle,DWORD dstIndex,DWORD srcIndex,MIXERLINE * mixerLine)285 int getMixerLineBySource(HMIXER handle, DWORD dstIndex, DWORD srcIndex, MIXERLINE* mixerLine) {
286 mixerLine->cbStruct = sizeof(MIXERLINE);
287 mixerLine->dwDestination = dstIndex;
288 mixerLine->dwSource = srcIndex;
289 if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
290 MIXER_GETLINEINFOF_SOURCE | MIXER_OBJECTF_HMIXER
291 ) == MMSYSERR_NOERROR) {
292 return TRUE;
293 }
294 mixerLine->cControls = 0;
295 mixerLine->cConnections = 0;
296 return FALSE;
297 }
298
getControlInfo(HMIXER handle,MIXERLINE * line,MIXERLINECONTROLS * controls)299 int getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) {
300 int ret = FALSE;
301
302 //TRACE2(">getControlInfo for line %s with %d controls\n", line->szName, line->cControls);
303 controls->pamxctrl = NULL;
304 if (line->cControls > 0) {
305 // line points to the requested line.
306 // Reserve memory for the control infos
307 controls->cbStruct = sizeof(MIXERLINECONTROLS);
308 controls->dwLineID = line->dwLineID;
309 controls->cControls = line->cControls;
310 controls->cbmxctrl = sizeof(MIXERCONTROL);
311 controls->pamxctrl = (MIXERCONTROL*) malloc(sizeof(MIXERCONTROL) * line->cControls);
312 if (controls->pamxctrl) {
313 //TRACE0(" calling mixerGetLineControls\n");
314 ret = mixerGetLineControls((HMIXEROBJ) handle, controls,
315 MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR;
316 }
317 }
318 if (!ret) {
319 if (controls->pamxctrl) {
320 free(controls->pamxctrl);
321 controls->pamxctrl = NULL;
322 }
323 }
324 //TRACE0("<getControlInfo \n");
325 return ret;
326 }
327
328 // returns TRUE if there are more than MIXER/MUX controls in this line
329 // if controls is non-NULL, it will be filled with the info
lineHasControls(HMIXER handle,MIXERLINE * line,MIXERLINECONTROLS * controls)330 int lineHasControls(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) {
331 MIXERLINECONTROLS localControls;
332 int ret = FALSE;
333 UINT i;
334
335 localControls.pamxctrl = NULL;
336 if (controls == NULL) {
337 controls = &localControls;
338 }
339 if (getControlInfo(handle, line, controls)) {
340 for (i = 0; !ret && (i < controls->cControls); i++) {
341 switch (controls->pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) {
342 case MIXERCONTROL_CT_CLASS_FADER : // fall through
343 case MIXERCONTROL_CT_CLASS_SLIDER : // fall through
344 case MIXERCONTROL_CT_CLASS_SWITCH : ret = TRUE;
345 }
346 }
347 }
348 if (localControls.pamxctrl) {
349 free(localControls.pamxctrl);
350 localControls.pamxctrl = NULL;
351 }
352 return ret;
353 }
354
355
356 ///// implemented functions of Ports.h
357
PORT_GetPortMixerDescription(INT32 mixerIndex,PortMixerDescription * description)358 INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
359 MIXERCAPSW mixerCaps;
360 if (mixerGetDevCapsW(mixerIndex, &mixerCaps, sizeof(MIXERCAPSW)) == MMSYSERR_NOERROR) {
361 UnicodeToUTF8AndCopy(description->name, mixerCaps.szPname, PORT_STRING_LENGTH);
362 sprintf(description->version, "%d.%d", (mixerCaps.vDriverVersion & 0xFF00) >> 8, mixerCaps.vDriverVersion & 0xFF);
363 strncpy(description->description, "Port Mixer", PORT_STRING_LENGTH-1);
364 return TRUE;
365 }
366 return FALSE;
367 }
368
getDestinationCount(HMIXER handle)369 int getDestinationCount(HMIXER handle) {
370 int ret = 0;
371 MIXERCAPSW mixerCaps;
372
373 if (mixerGetDevCapsW((UINT_PTR) handle, &mixerCaps, sizeof(MIXERCAPSW)) == MMSYSERR_NOERROR) {
374 ret = mixerCaps.cDestinations;
375 }
376 return ret;
377 }
378
PORT_Open(INT32 mixerIndex)379 void* PORT_Open(INT32 mixerIndex) {
380 PortInfo* info = NULL;
381 MMRESULT mmres;
382 HMIXER handle;
383 MIXERLINE* waveInLine;
384 int success = FALSE;
385 int src, dst, srcIndex, waveInHasControls;
386 int dstCount;
387
388 TRACE0("PORT_Open\n");
389 mmres = mixerOpen((LPHMIXER) &handle, mixerIndex, 0, 0, MIXER_OBJECTF_MIXER);
390 if (mmres != MMSYSERR_NOERROR) {
391 return NULL;
392 }
393
394 info = (PortInfo*) malloc(sizeof(PortInfo));
395 if (info != NULL) {
396 success = TRUE;
397 memset(info, 0, sizeof(PortInfo));
398 info->handle = handle;
399 info->mixerIndex = mixerIndex;
400 waveInLine = NULL;
401 waveInHasControls = FALSE;
402 // number of destinations
403 dstCount = getDestinationCount(handle);
404 if (dstCount) {
405 info->dstLines = (MIXERLINE*) malloc(dstCount * sizeof(MIXERLINE));
406 success = (info->dstLines != NULL);
407 }
408 if (success && info->dstLines) {
409 // go through all destinations and fill the structures in PortInfo
410 for (dst = 0; dst < dstCount; dst++) {
411 if (getMixerLineByDestination(handle, dst, &info->dstLines[info->dstLineCount])) {
412 info->srcLineCount += info->dstLines[info->dstLineCount].cConnections;
413 if (info->dstLines[info->dstLineCount].dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN && !waveInLine) {
414 waveInLine = &info->dstLines[info->dstLineCount];
415 info->sourcePortCount = waveInLine->cConnections;
416 if (lineHasControls(handle, waveInLine, NULL)) {
417 // add a single port for all the controls that do not show in the MUX/MIXER controls
418 info->sourcePortCount++;
419 waveInHasControls = TRUE;
420 }
421 } else {
422 info->targetPortCount++;
423 }
424 info->dstLineCount++;
425 }
426 }
427 }
428 if (info->srcLineCount) {
429 info->srcLines = (MIXERLINE*) malloc(info->srcLineCount * sizeof(MIXERLINE));
430 success = (info->srcLines != NULL);
431 }
432 if (success && info->srcLines) {
433 // go through all destinations and fill the source line structures in PortInfo
434 srcIndex = 0;
435 for (dst = 0; dst < info->dstLineCount; dst++) {
436 // remember the srcIndex for mapping the srcLines to this destination line
437 info->dstLines[dst].dwUser = srcIndex;
438 for (src = 0; src < (int) info->dstLines[dst].cConnections; src++) {
439 getMixerLineBySource(handle, dst, src, &info->srcLines[srcIndex++]);
440 }
441 }
442 }
443 // now create the mapping to Java Sound
444 if ((info->targetPortCount + info->sourcePortCount) > 0) {
445 info->ports = (LPMIXERLINE*) malloc((info->targetPortCount + info->sourcePortCount) * sizeof(LPMIXERLINE));
446 success = (info->ports != NULL);
447 }
448 if (success && info->ports) {
449 // first add the target MIXERLINEs to the array
450 srcIndex = 0;
451 for (dst = 0; dst < info->dstLineCount; dst++) {
452 if (waveInLine != &info->dstLines[dst]) {
453 info->ports[srcIndex++] = &info->dstLines[dst];
454 }
455 }
456 if (srcIndex != info->targetPortCount) {
457 ERROR2("srcIndex=%d is NOT targetPortCount=%d !\n", srcIndex, info->targetPortCount);
458 }
459 //srcIndex = info->targetPortCount; // should be automatic!
460 if (waveInLine) {
461 // if the recording destination line has controls, add the line
462 if (waveInHasControls) {
463 info->ports[srcIndex++] = waveInLine;
464 }
465 for (src = 0; src < (int) waveInLine->cConnections; src++) {
466 info->ports[srcIndex++] = &info->srcLines[src + waveInLine->dwUser];
467 }
468 }
469 if (srcIndex != (info->targetPortCount + info->sourcePortCount)) {
470 ERROR2("srcIndex=%d is NOT PortCount=%d !\n", srcIndex, (info->targetPortCount + info->sourcePortCount));
471 }
472 }
473 }
474 if (!success) {
475 if (handle != NULL) {
476 mixerClose(handle);
477 }
478 PORT_Close((void*) info);
479 info = NULL;
480 }
481 return info;
482 }
483
PORT_Close(void * id)484 void PORT_Close(void* id) {
485 TRACE0("PORT_Close\n");
486 if (id != NULL) {
487 PortInfo* info = (PortInfo*) id;
488 if (info->handle) {
489 mixerClose(info->handle);
490 info->handle = NULL;
491 }
492 if (info->dstLines) {
493 free(info->dstLines);
494 info->dstLines = NULL;
495 }
496 if (info->srcLines) {
497 free(info->srcLines);
498 info->srcLines=NULL;
499 }
500 if (info->ports) {
501 free(info->ports);
502 info->ports = NULL;
503 }
504 if (info->controlIDs) {
505 free(info->controlIDs);
506 info->controlIDs = NULL;
507 }
508 if (info->muxData) {
509 free(info->muxData);
510 info->muxData = NULL;
511 }
512 free(info);
513 }
514 }
515
PORT_GetPortCount(void * id)516 INT32 PORT_GetPortCount(void* id) {
517 int ret = 0;
518 PortInfo* info = (PortInfo*) id;
519 if (info != NULL) {
520 ret = info->targetPortCount + info->sourcePortCount;
521 }
522 return ret;
523 }
524
componentType2type(DWORD componentType)525 int componentType2type(DWORD componentType) {
526 int ret = 0;
527 if (componentType >= MIXERLINE_COMPONENTTYPE_DST_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_DST_LAST) {
528 ret = PORT_DST_UNKNOWN;
529 }
530 else if (componentType >= MIXERLINE_COMPONENTTYPE_SRC_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_SRC_LAST) {
531 ret = PORT_SRC_UNKNOWN;
532 }
533 // handle special cases
534 switch (componentType) {
535 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: ret = PORT_DST_HEADPHONE; break;
536 case MIXERLINE_COMPONENTTYPE_DST_LINE: ret = PORT_DST_LINE_OUT; break;
537 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: ret = PORT_DST_SPEAKER; break;
538 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: ret = PORT_SRC_COMPACT_DISC; break;
539 case MIXERLINE_COMPONENTTYPE_SRC_LINE: ret = PORT_SRC_LINE_IN; break;
540 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: ret = PORT_SRC_MICROPHONE; break;
541 }
542 return ret;
543 }
544
PORT_GetPortType(void * id,INT32 portIndex)545 INT32 PORT_GetPortType(void* id, INT32 portIndex) {
546 MIXERLINE* line;
547 PortInfo* info = (PortInfo*) id;
548 if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
549 line = info->ports[portIndex];
550 if (line) {
551 return componentType2type(line->dwComponentType);
552 }
553 }
554 return 0;
555 }
556
PORT_GetPortName(void * id,INT32 portIndex,char * name,INT32 len)557 INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
558 MIXERLINE* line;
559 PortInfo* info = (PortInfo*) id;
560
561 if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
562 line = info->ports[portIndex];
563 if (line) {
564 strncpy(name, line->szName, len-1);
565 name[len-1] = 0;
566 return TRUE;
567 }
568 }
569 return FALSE;
570 }
571
getControlCount(HMIXER handle,MIXERLINE * line,INT32 * muxCount)572 int getControlCount(HMIXER handle, MIXERLINE* line, INT32* muxCount) {
573 MIXERLINECONTROLS controls;
574 int ret = 0;
575 UINT i;
576
577 controls.pamxctrl = NULL;
578 if (getControlInfo(handle, line, &controls)) {
579 for (i = 0; i < controls.cControls; i++) {
580 switch (controls.pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) {
581 case MIXERCONTROL_CT_CLASS_FADER : // fall through
582 case MIXERCONTROL_CT_CLASS_SLIDER : // fall through
583 case MIXERCONTROL_CT_CLASS_SWITCH : // fall through
584 case MIXERCONTROL_CT_CLASS_LIST : ret++; break;
585 }
586 if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
587 || (controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)) {
588 ret += controls.pamxctrl[i].cMultipleItems;
589 if (muxCount) {
590 (*muxCount) += controls.pamxctrl[i].cMultipleItems;
591 }
592 }
593 else if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
594 && (line->cChannels == 2)) {
595 ret++; // for FAKE volume/balance pairs
596 }
597 }
598 }
599 if (controls.pamxctrl) {
600 free(controls.pamxctrl);
601 controls.pamxctrl = NULL;
602 }
603 return ret;
604 }
605
findDestLine(PortInfo * info,DWORD dwDestination)606 MIXERLINE* findDestLine(PortInfo* info, DWORD dwDestination) {
607 int i;
608 TRACE0(">findDestLine\n");
609 for (i = 0; i < info->dstLineCount; i++) {
610 if (info->dstLines[i].dwDestination == dwDestination) {
611 TRACE0("<findDestLine\n");
612 return &(info->dstLines[i]);
613 }
614 }
615 TRACE0("<findDestLine NULL\n");
616 return NULL;
617 }
618
createMuxControl(PortInfo * info,PortControlCreator * creator,MIXERLINE * dstLine,DWORD srcLineID,void ** controlObjects,int * controlCount)619 void createMuxControl(PortInfo* info, PortControlCreator* creator, MIXERLINE* dstLine, DWORD srcLineID, void** controlObjects, int* controlCount) {
620 MIXERLINECONTROLS controlInfos;
621 MIXERCONTROLDETAILS* details;
622 MIXERCONTROLDETAILS_LISTTEXT* listTextDetails = NULL;
623 UINT listTextDetailCount = 0;
624 PortControlID* controlID;
625 UINT i, c;
626 int m;
627
628 TRACE0(">createMuxControl\n");
629 // go through all controls of dstline
630 controlInfos.pamxctrl = NULL;
631 if (getControlInfo(info->handle, dstLine, &controlInfos)) {
632 for (i = 0; i < controlInfos.cControls; i++) {
633 if (((controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
634 || (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX))
635 && (controlInfos.pamxctrl[i].cMultipleItems > 0)) {
636 if (info->usedControlIDs >= info->maxControlCount) {
637 ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
638 break;
639 }
640 // get the details for this mux control
641 controlID = &(info->controlIDs[info->usedControlIDs]);
642 controlID->portInfo = info;
643 if (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER) {
644 controlID->controlType = PORT_CONTROL_TYPE_MIXER;
645 } else {
646 controlID->controlType = PORT_CONTROL_TYPE_MUX;
647 }
648 details = &(controlID->details);
649 details->cbStruct = sizeof(MIXERCONTROLDETAILS);
650 details->dwControlID = controlInfos.pamxctrl[i].dwControlID;
651 details->cChannels = 1;
652 details->cMultipleItems = controlInfos.pamxctrl[i].cMultipleItems;
653 details->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
654 if (!listTextDetails || (listTextDetailCount < (details->cMultipleItems * details->cChannels))) {
655 // need to allocate new listTextDetails
656 if (listTextDetails) {
657 free(listTextDetails);
658 listTextDetails = NULL;
659 }
660 listTextDetailCount = details->cMultipleItems * details->cChannels;
661 listTextDetails = (MIXERCONTROLDETAILS_LISTTEXT*) malloc(listTextDetailCount * sizeof(MIXERCONTROLDETAILS_LISTTEXT));
662 if (!listTextDetails) {
663 ERROR0("createMuxControl: unable to allocate listTextDetails!\n");
664 if (controlInfos.pamxctrl) {
665 free(controlInfos.pamxctrl);
666 controlInfos.pamxctrl = NULL;
667 }
668 TRACE0("<createMuxControl ERROR\n");
669 return;
670 }
671 }
672 details->paDetails = listTextDetails;
673 if (mixerGetControlDetails((HMIXEROBJ) info->handle, details, MIXER_GETCONTROLDETAILSF_LISTTEXT | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
674 ERROR0("createMuxControl: unable to get control details!\n");
675 continue;
676 }
677 // prevent freeing this data
678 details->paDetails = NULL;
679 // go through all mux items. If the line matches, then add a BOOLEAN select control
680 for (c = 0; c < details->cMultipleItems; c++) {
681 if (listTextDetails[c].dwParam1 == srcLineID) {
682 // we have found the line in the MUX lines.
683 controlID->muxIndex = c;
684 details->cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
685 // now look if any other controlID was already part of this MUX line
686 for (m = 0; m < info->usedControlIDs; m++) {
687 if (info->controlIDs[m].details.dwControlID == details->dwControlID) {
688 // reuse the MUX Data
689 TRACE2("Reusing paDetails=%p of controlID[%d]\n", info->controlIDs[m].details.paDetails, m);
690 details->paDetails = info->controlIDs[m].details.paDetails;
691 break;
692 }
693 }
694 if (!details->paDetails) {
695 // first time this MUX control is used, allocate some of the muxData
696 details->paDetails = &(info->muxData[info->usedMuxData]);
697 TRACE2("Setting paDetails=%p to muxData[%d] \n", details->paDetails, info->usedMuxData);
698 info->usedMuxData += details->cMultipleItems;
699 }
700 // finally this line can be added
701 controlObjects[*controlCount] = (creator->newBooleanControl)(creator, controlID, CONTROL_TYPE_SELECT);
702 (*controlCount)++;
703 info->usedControlIDs++;
704 break;
705 }
706 }
707 }
708 }
709 }
710 if (listTextDetails) {
711 free(listTextDetails);
712 listTextDetails = NULL;
713 }
714 if (controlInfos.pamxctrl) {
715 free(controlInfos.pamxctrl);
716 controlInfos.pamxctrl = NULL;
717 }
718 TRACE0("<createMuxControl\n");
719 }
720
createPortControl(PortInfo * info,PortControlCreator * creator,MIXERCONTROL * mixerControl,INT32 type,void ** controlObjects,int * controlCount)721 void createPortControl(PortInfo* info, PortControlCreator* creator, MIXERCONTROL* mixerControl,
722 INT32 type, void** controlObjects, int* controlCount) {
723 PortControlID* controlID;
724 void* newControl = NULL;
725 char* typeName = mixerControl->szName;
726 float min;
727 TRACE0(">createPortControl\n");
728
729 // fill the ControlID structure and add this control
730 if (info->usedControlIDs >= info->maxControlCount) {
731 ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
732 return;
733 }
734 controlID = &(info->controlIDs[info->usedControlIDs]);
735 controlID->portInfo = info;
736 controlID->controlType = type;
737 controlID->details.cbStruct = sizeof(MIXERCONTROLDETAILS);
738 controlID->details.dwControlID = mixerControl->dwControlID;
739 controlID->details.cChannels = 1; // uniform
740 controlID->details.cMultipleItems = 0;
741 switch (type) {
742 case PORT_CONTROL_TYPE_BOOLEAN:
743 TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
744 controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
745 controlID->details.paDetails = &(controlID->boolValue);
746 if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) {
747 typeName = CONTROL_TYPE_MUTE;
748 }
749 newControl = (creator->newBooleanControl)(creator, controlID, typeName);
750 break;
751 case PORT_CONTROL_TYPE_SIGNED:
752 TRACE0(" PORT_CONTROL_TYPE_SIGNED\n");
753 controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
754 controlID->details.paDetails = &(controlID->signedValue);
755 controlID->min = (INT32) mixerControl->Bounds.lMinimum;
756 controlID->max = (INT32) mixerControl->Bounds.lMaximum;
757 if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_PAN) {
758 typeName = CONTROL_TYPE_PAN;
759 }
760 newControl = (creator->newFloatControl)(creator, controlID, typeName,
761 -1.0f, 1.0f, 2.0f / (controlID->max - controlID->min + 1), "");
762 break;
763 case PORT_CONTROL_TYPE_FAKE_VOLUME: // fall through
764 case PORT_CONTROL_TYPE_FAKE_BALANCE: // fall through
765 case PORT_CONTROL_TYPE_UNSIGNED:
766 TRACE0(" PORT_CONTROL_TYPE_UNSIGNED\n");
767 controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
768 controlID->details.paDetails = &(controlID->unsignedValue[0]);
769 controlID->min = (INT32) mixerControl->Bounds.dwMinimum;
770 controlID->max = (INT32) mixerControl->Bounds.dwMaximum;
771 min = 0.0f;
772 if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME)
773 || (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) {
774 typeName = CONTROL_TYPE_VOLUME;
775 }
776 if (type == PORT_CONTROL_TYPE_FAKE_BALANCE) {
777 typeName = CONTROL_TYPE_BALANCE;
778 min = -1.0f;
779 }
780 if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME)
781 || (type == PORT_CONTROL_TYPE_FAKE_BALANCE)) {
782 controlID->details.cChannels = 2;
783 }
784 TRACE0(" ....PORT_CONTROL_TYPE_UNSIGNED\n");
785 newControl = (creator->newFloatControl)(creator, controlID, typeName,
786 min, 1.0f, 1.0f / (controlID->max - controlID->min + 1), "");
787 break;
788 default:
789 ERROR1("createPortControl: unknown type %d !", type);
790 break;
791 }
792 if (newControl) {
793 controlObjects[*controlCount] = newControl;
794 (*controlCount)++;
795 info->usedControlIDs++;
796 }
797 TRACE0("<createPortControl\n");
798 }
799
createLineControls(PortInfo * info,PortControlCreator * creator,MIXERLINE * line,void ** controlObjects,int * controlCount)800 void createLineControls(PortInfo* info, PortControlCreator* creator, MIXERLINE* line, void** controlObjects, int* controlCount) {
801 MIXERLINECONTROLS controlInfos;
802 MIXERCONTROL* mixerControl;
803 UINT i;
804 INT32 type;
805
806 TRACE1(">createLineControls for line %s\n", line->szName);
807 // go through all controls of line
808 controlInfos.pamxctrl = NULL;
809 if (getControlInfo(info->handle, line, &controlInfos)) {
810 for (i = 0; i < controlInfos.cControls; i++) {
811 TRACE1(" %d\n", i);
812 mixerControl = &(controlInfos.pamxctrl[i]);
813 type = 0;
814 switch (mixerControl->dwControlType) {
815 case MIXERCONTROL_CONTROLTYPE_BOOLEAN : // fall through
816 case MIXERCONTROL_CONTROLTYPE_BUTTON : // fall through
817 case MIXERCONTROL_CONTROLTYPE_LOUDNESS : // fall through
818 case MIXERCONTROL_CONTROLTYPE_MONO : // fall through
819 case MIXERCONTROL_CONTROLTYPE_MUTE : // fall through
820 case MIXERCONTROL_CONTROLTYPE_ONOFF : // fall through
821 case MIXERCONTROL_CONTROLTYPE_STEREOENH: type = PORT_CONTROL_TYPE_BOOLEAN; break;
822
823 case MIXERCONTROL_CONTROLTYPE_PAN : // fall through
824 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN: // fall through
825 case MIXERCONTROL_CONTROLTYPE_SLIDER : type = PORT_CONTROL_TYPE_SIGNED; break;
826
827 case MIXERCONTROL_CONTROLTYPE_BASS : // fall through
828 //case MIXERCONTROL_CONTROLTYPE_EQUALIZER: // fall through
829 case MIXERCONTROL_CONTROLTYPE_FADER : // fall through
830 case MIXERCONTROL_CONTROLTYPE_TREBLE : type = PORT_CONTROL_TYPE_UNSIGNED; break;
831 case MIXERCONTROL_CONTROLTYPE_VOLUME :
832 type = PORT_CONTROL_TYPE_UNSIGNED;
833 if (line->cChannels == 2 && ((mixerControl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) == 0)) {
834 type = PORT_CONTROL_TYPE_FAKE_VOLUME;
835 }
836 break;
837 }
838 if (type != 0) {
839 createPortControl(info, creator, mixerControl, type, controlObjects, controlCount);
840 // create fake balance for fake volume
841 if (type == PORT_CONTROL_TYPE_FAKE_VOLUME) {
842 createPortControl(info, creator, mixerControl, PORT_CONTROL_TYPE_FAKE_BALANCE, controlObjects, controlCount);
843 }
844 }
845 }
846 }
847 if (controlInfos.pamxctrl) {
848 free(controlInfos.pamxctrl);
849 controlInfos.pamxctrl = NULL;
850 }
851 TRACE0("<createLineControls\n");
852 }
853
addCompoundControl(PortInfo * info,PortControlCreator * creator,char * name,void ** controlObjects,int * controlCount)854 void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
855 void* compControl;
856
857 TRACE1(">addCompoundControl %d controls\n", *controlCount);
858 if (*controlCount) {
859 // create compound control and add it to the vector
860 compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount);
861 if (compControl) {
862 TRACE1(" addCompoundControl: calling addControl %p\n", compControl);
863 (creator->addControl)(creator, compControl);
864 }
865 *controlCount = 0;
866 }
867 TRACE0("<addCompoundControl\n");
868 }
869
addAllControls(PortInfo * info,PortControlCreator * creator,void ** controlObjects,int * controlCount)870 void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
871 int i = 0;
872
873 TRACE0(">addAllControl\n");
874 // go through all controls and add them to the vector
875 for (i = 0; i < *controlCount; i++) {
876 (creator->addControl)(creator, controlObjects[i]);
877 }
878 *controlCount = 0;
879 TRACE0("<addAllControl\n");
880 }
881
882
883
PORT_GetControls(void * id,INT32 portIndex,PortControlCreator * creator)884 void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
885 MIXERLINE* line;
886 PortInfo* info = (PortInfo*) id;
887 int portCount = PORT_GetPortCount(id);
888 void** controls = NULL;
889 int controlCount;
890 UINT i;
891
892 TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", id, portIndex, info->controlIDs, info->maxControlCount);
893 if ((portIndex >= 0) && (portIndex < portCount)) {
894 line = info->ports[portIndex];
895 if (line) {
896 // if the memory isn't reserved for the control structures, allocate it
897 if (!info->controlIDs) {
898 int i, maxCount = 0, muxCount = 0;
899 TRACE0("getControl: allocate mem\n");
900 // get a maximum number of controls
901 // first for all destination lines
902 for (i = 0; i < info->dstLineCount; i++) {
903 MIXERLINE* thisLine = &(info->dstLines[i]);
904 maxCount += getControlCount(info->handle, thisLine, &muxCount);
905 }
906 // then all source lines
907 for (i = 0; i < info->srcLineCount; i++) {
908 MIXERLINE* thisLine = &(info->srcLines[i]);
909 maxCount += getControlCount(info->handle, thisLine, &muxCount);
910 }
911 info->maxControlCount = maxCount;
912 if (maxCount > 0) {
913 info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount);
914 } else {
915 // no ports: nothing to do !
916 return;
917 }
918 TRACE2("Creating muxData for %d elements and %d controlIDs.\n", muxCount, maxCount);
919 if (muxCount > 0) {
920 info->muxData = (MIXERCONTROLDETAILS_BOOLEAN*) malloc(sizeof(MIXERCONTROLDETAILS_BOOLEAN) * muxCount);
921 }
922 if (!info->controlIDs || (muxCount && !info->muxData)) {
923 ERROR3("PORT_GetControls: info->controlIDs=%p, muxCount=%d, info->muxData=%p !!\n", info->controlIDs, muxCount, info->muxData);
924 return;
925 }
926 }
927 if (info->maxControlCount == 0) {
928 return;
929 }
930 controls = (void*) malloc(info->maxControlCount * sizeof(void*));
931 if (!controls) {
932 ERROR0("PORT_GetControls: couldn't allocate controls!\n");
933 return;
934 }
935
936 // add controls of this line
937 controlCount = 0;
938 // if this line is part of MUX, add the respective BOOLEANCONTROL as a control
939 if ((line->fdwLine & MIXERLINE_LINEF_SOURCE) == MIXERLINE_LINEF_SOURCE) {
940 MIXERLINE* dstLine = findDestLine(info, line->dwDestination);
941 TRACE0("Port_getControls: this is a source line\n");
942 if (dstLine) {
943 // selection controls (implemented as Mute control)
944 createMuxControl(info, creator, dstLine, line->dwLineID, controls, &controlCount);
945 }
946 // then add all controls in one compound control
947 createLineControls(info, creator, line, controls, &controlCount);
948 addCompoundControl(info, creator, line->szName, controls, &controlCount);
949 } else {
950 TRACE0("getControl: this is a dest line\n");
951 // if this is a destination line, add its controls
952 createLineControls(info, creator, line, controls, &controlCount);
953 addAllControls(info, creator, controls, &controlCount);
954 // then add all controls of its source lines as one compound control
955 for (i = 0; i < line->cConnections; i++) {
956 // then add all controls
957 MIXERLINE* srcLine = &(info->srcLines[line->dwUser + i]);
958 TRACE1("PORT_getControls: add source line %d\n", i);
959 createLineControls(info, creator, srcLine, controls, &controlCount);
960 addCompoundControl(info, creator, srcLine->szName, controls, &controlCount);
961 }
962 }
963 }
964 }
965 if (controls) {
966 free(controls);
967 }
968 TRACE0("< PORT_getControls\n");
969 }
970
getControlValue(PortControlID * controlID)971 int getControlValue(PortControlID* controlID) {
972 if (mixerGetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details),
973 MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
974 ERROR0("getControlValue: unable to get control details!\n");
975 //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels);
976 //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails);
977 return FALSE;
978 }
979 return TRUE;
980 }
981
setControlValue(PortControlID * controlID)982 int setControlValue(PortControlID* controlID) {
983 if (mixerSetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details),
984 MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
985 ERROR0("setControlValue: unable to set control details!\n");
986 //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels);
987 //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails);
988 return FALSE;
989 }
990 return TRUE;
991 }
992
PORT_GetIntValue(void * controlIDV)993 INT32 PORT_GetIntValue(void* controlIDV) {
994 PortControlID* controlID = (PortControlID*) controlIDV;
995 MIXERCONTROLDETAILS_BOOLEAN* bools;
996 int ret = 0;
997 if (getControlValue(controlID)) {
998 switch (controlID->controlType) {
999 case PORT_CONTROL_TYPE_MUX: // fall through
1000 case PORT_CONTROL_TYPE_MIXER:
1001 bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
1002 ret = (bools[controlID->muxIndex].fValue)?TRUE:FALSE;
1003 break;
1004 case PORT_CONTROL_TYPE_BOOLEAN:
1005 ret = (controlID->boolValue.fValue)?TRUE:FALSE;
1006 break;
1007 default: ERROR1("PORT_GetIntValue: wrong controlType=%d !\n", controlID->controlType);
1008 }
1009 }
1010 return ret;
1011 }
1012
PORT_SetIntValue(void * controlIDV,INT32 value)1013 void PORT_SetIntValue(void* controlIDV, INT32 value) {
1014 PortControlID* controlID = (PortControlID*) controlIDV;
1015 MIXERCONTROLDETAILS_BOOLEAN* bools;
1016 UINT i;
1017
1018 switch (controlID->controlType) {
1019 case PORT_CONTROL_TYPE_MUX:
1020 if (!value) {
1021 // cannot unselect a MUX line
1022 return;
1023 }
1024 if (!getControlValue(controlID)) {
1025 return;
1026 }
1027 bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
1028 for (i = 0; i < controlID->details.cMultipleItems; i++) {
1029 bools[i].fValue = (i == (UINT) controlID->muxIndex)?TRUE:FALSE;
1030 }
1031 break;
1032 case PORT_CONTROL_TYPE_MIXER:
1033 if (!getControlValue(controlID)) {
1034 return;
1035 }
1036 bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
1037 bools[controlID->muxIndex].fValue = (value?TRUE:FALSE);
1038 break;
1039 case PORT_CONTROL_TYPE_BOOLEAN:
1040 controlID->boolValue.fValue = (value?TRUE:FALSE);
1041 break;
1042 default:
1043 ERROR1("PORT_SetIntValue: wrong controlType=%d !\n", controlID->controlType);
1044 return;
1045 }
1046 setControlValue(controlID);
1047 }
1048
getFakeBalance(PortControlID * controlID)1049 float getFakeBalance(PortControlID* controlID) {
1050 float volL, volR;
1051 float range = (float) (controlID->max - controlID->min);
1052 // pan is the ratio of left and right
1053 volL = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range);
1054 volR = (((float) (controlID->unsignedValue[1].dwValue - controlID->min)) / range);
1055 if (volL > volR) {
1056 return -1.0f + (volR / volL);
1057 }
1058 else if (volR > volL) {
1059 return 1.0f - (volL / volR);
1060 }
1061 return 0.0f;
1062 }
1063
getFakeVolume(PortControlID * controlID)1064 float getFakeVolume(PortControlID* controlID) {
1065 // volume is the greater value of both
1066 UINT vol = controlID->unsignedValue[0].dwValue;
1067 if (controlID->unsignedValue[1].dwValue > vol) {
1068 vol = controlID->unsignedValue[1].dwValue;
1069 }
1070 return (((float) (vol - controlID->min)) / (controlID->max - controlID->min));
1071 }
1072
1073 /*
1074 * sets the unsigned values for left and right volume according to
1075 * the given volume (0...1) and balance (-1..0..+1)
1076 */
setFakeVolume(PortControlID * controlID,float vol,float bal)1077 void setFakeVolume(PortControlID* controlID, float vol, float bal) {
1078 vol = vol * (controlID->max - controlID->min);
1079 if (bal < 0.0f) {
1080 controlID->unsignedValue[0].dwValue = (UINT) (vol + 0.5f) + controlID->min;
1081 controlID->unsignedValue[1].dwValue = (UINT) ((vol * (bal + 1.0f)) + 0.5f) + controlID->min;
1082 } else {
1083 controlID->unsignedValue[1].dwValue = (UINT) (vol + 0.5f) + controlID->min;
1084 controlID->unsignedValue[0].dwValue = (UINT) ((vol * (1.0f - bal)) + 0.5f) + controlID->min;
1085 }
1086 }
1087
PORT_GetFloatValue(void * controlIDV)1088 float PORT_GetFloatValue(void* controlIDV) {
1089 PortControlID* controlID = (PortControlID*) controlIDV;
1090 float ret = 0.0f;
1091 float range = (float) (controlID->max - controlID->min);
1092 if (getControlValue(controlID)) {
1093 switch (controlID->controlType) {
1094 case PORT_CONTROL_TYPE_SIGNED:
1095 ret = ((float) controlID->signedValue.lValue) / controlID->max;
1096 break;
1097 case PORT_CONTROL_TYPE_UNSIGNED:
1098 ret = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range);
1099 break;
1100 case PORT_CONTROL_TYPE_FAKE_VOLUME:
1101 ret = getFakeVolume(controlID);
1102 break;
1103 case PORT_CONTROL_TYPE_FAKE_BALANCE:
1104 ret = getFakeBalance(controlID);
1105 break;
1106 default: ERROR1("PORT_GetFloatValue: wrong controlType=%d !\n", controlID->controlType);
1107 }
1108 }
1109 return ret;
1110 }
1111
PORT_SetFloatValue(void * controlIDV,float value)1112 void PORT_SetFloatValue(void* controlIDV, float value) {
1113 PortControlID* controlID = (PortControlID*) controlIDV;
1114 float range = (float) (controlID->max - controlID->min);
1115 switch (controlID->controlType) {
1116 case PORT_CONTROL_TYPE_SIGNED:
1117 controlID->signedValue.lValue = (INT32) ((value * controlID->max) + 0.5f);
1118 break;
1119 case PORT_CONTROL_TYPE_UNSIGNED:
1120 controlID->unsignedValue[0].dwValue = (INT32) ((value * range) + 0.5f) + controlID->min;
1121 break;
1122 case PORT_CONTROL_TYPE_FAKE_VOLUME:
1123 if (!getControlValue(controlID)) {
1124 return;
1125 }
1126 setFakeVolume(controlID, value, getFakeBalance(controlID));
1127 break;
1128 case PORT_CONTROL_TYPE_FAKE_BALANCE:
1129 if (!getControlValue(controlID)) {
1130 return;
1131 }
1132 setFakeVolume(controlID, getFakeVolume(controlID), value);
1133 break;
1134 default:
1135 ERROR1("PORT_SetFloatValue: wrong controlType=%d !\n", controlID->controlType);
1136 return;
1137 }
1138 setControlValue(controlID);
1139 }
1140
1141 #endif // USE_PORTS
1142