0N/A/*
2362N/A * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/A#define USE_ERROR
0N/A//#define USE_TRACE
0N/A
0N/A#ifndef WIN32_EXTRA_LEAN
0N/A#define WIN32_EXTRA_LEAN
0N/A#endif
0N/A#ifndef WIN32_LEAN_AND_MEAN
0N/A#define WIN32_LEAN_AND_MEAN
0N/A#endif
0N/A
0N/A#include <windows.h>
0N/A#include <mmsystem.h>
0N/A#include "Ports.h"
0N/A
0N/A#if USE_PORTS == TRUE
0N/A
0N/Atypedef struct tag_PortControlID PortControlID;
0N/A
0N/Atypedef struct tag_PortInfo {
0N/A // Windows API stuff
0N/A HMIXER handle;
0N/A INT32 mixerIndex;
0N/A int dstLineCount; // how many MIXERLINE structs in dstMixerLine
0N/A MIXERLINE* dstLines;
0N/A int srcLineCount; // how many MIXERLINE structs in srcMixerLine
0N/A MIXERLINE* srcLines; // contains all the Source Lines of dstLines
0N/A // Java Sound mapping
0N/A int targetPortCount; // one port per dstLine (playback)
0N/A int sourcePortCount; // only WAVEIN; one port maps to one srcLine
0N/A LPMIXERLINE* ports; // points into dstLines and dstLines. Starts with Target Ports (Playback)
0N/A int maxControlCount; // upper bound of number of controls
0N/A int usedControlIDs; // number of items already filled in controlIDs
0N/A PortControlID* controlIDs; // the control IDs themselves
0N/A int usedMuxData;
0N/A MIXERCONTROLDETAILS_BOOLEAN* muxData;
0N/A} PortInfo;
0N/A
0N/A#define PORT_CONTROL_TYPE_BOOLEAN 1
0N/A#define PORT_CONTROL_TYPE_SIGNED 2
0N/A#define PORT_CONTROL_TYPE_UNSIGNED 3
0N/A//#define PORT_CONTROL_TYPE_UNSIGNED_DB 4
0N/A#define PORT_CONTROL_TYPE_FAKE_VOLUME 5
0N/A#define PORT_CONTROL_TYPE_FAKE_BALANCE 6
0N/A#define PORT_CONTROL_TYPE_MUX 5
0N/A#define PORT_CONTROL_TYPE_MIXER 6
0N/A
0N/Atypedef struct tag_PortControlID {
0N/A PortInfo* portInfo;
0N/A INT32 controlType; // one of PORT_CONTROL_TYPE_XX
0N/A INT32 min;
0N/A INT32 max;
0N/A MIXERCONTROLDETAILS details;
0N/A union {
0N/A MIXERCONTROLDETAILS_BOOLEAN boolValue;
0N/A MIXERCONTROLDETAILS_SIGNED signedValue;
0N/A MIXERCONTROLDETAILS_UNSIGNED unsignedValue[2];
0N/A INT32 muxIndex;
0N/A };
0N/A} PortControlID;
0N/A
0N/A
0N/Aint getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls);
0N/A
0N/AINT32 PORT_GetPortMixerCount() {
0N/A return (INT32) mixerGetNumDevs();
0N/A}
0N/A
0N/A#ifdef USE_TRACE
0N/A
0N/Achar* getLineFlags(DWORD flags) {
0N/A static char ret[100];
0N/A ret[0]=0;
0N/A if (flags & MIXERLINE_LINEF_ACTIVE) {
0N/A strcat(ret, "ACTIVE ");
0N/A flags ^= MIXERLINE_LINEF_ACTIVE;
0N/A }
0N/A if (flags & MIXERLINE_LINEF_DISCONNECTED) {
0N/A strcat(ret, "DISCONNECTED ");
0N/A flags ^= MIXERLINE_LINEF_DISCONNECTED;
0N/A }
0N/A if (flags & MIXERLINE_LINEF_SOURCE) {
0N/A strcat(ret, "SOURCE ");
0N/A flags ^= MIXERLINE_LINEF_SOURCE;
0N/A }
0N/A if (flags!=0) {
0N/A UINT_PTR r = (UINT_PTR) ret;
0N/A r += strlen(ret);
0N/A sprintf((char*) r, "%d", flags);
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Achar* getComponentType(int componentType) {
0N/A switch (componentType) {
0N/A case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return "DST_HEADPHONES";
0N/A case MIXERLINE_COMPONENTTYPE_DST_LINE: return "DST_LINE";
0N/A case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return "DST_SPEAKERS";
0N/A case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return "DST_DIGITAL";
0N/A case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return "DST_MONITOR";
0N/A case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return "DST_TELEPHONE";
0N/A case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return "DST_UNDEFINED";
0N/A case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return "DST_VOICEIN";
0N/A case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return "DST_WAVEIN";
0N/A
0N/A case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return "SRC_COMPACTDISC";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_LINE: return "SRC_LINE";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return "SRC_MICROPHONE";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return "SRC_ANALOG";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return "SRC_AUXILIARY";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return "SRC_DIGITAL";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return "SRC_PCSPEAKER";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return "SRC_SYNTHESIZER";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return "SRC_TELEPHONE";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return "SRC_UNDEFINED";
0N/A case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return "SRC_WAVEOUT";
0N/A }
0N/A return "";
0N/A}
0N/A
0N/Avoid printMixerLine(MIXERLINE* mixerLine) {
0N/A TRACE2("MIXERLINE destination=%d, source=%d, ", mixerLine->dwDestination, mixerLine->dwSource);
0N/A TRACE3("channels=%d, connections=%d, controls=%d, ", mixerLine->cChannels, mixerLine->cConnections, mixerLine->cControls);
0N/A TRACE3("\"%s\", fdwLine=%s, componentType=%s\n", mixerLine->szName, getLineFlags(mixerLine->fdwLine), getComponentType(mixerLine->dwComponentType));
0N/A}
0N/A
0N/Achar* getControlClass(int controlType) {
0N/A switch (controlType & MIXERCONTROL_CT_CLASS_MASK) {
0N/A case MIXERCONTROL_CT_CLASS_CUSTOM : return "CLASS_CUSTOM";
0N/A case MIXERCONTROL_CT_CLASS_FADER : return "CLASS_FADER ";
0N/A case MIXERCONTROL_CT_CLASS_LIST : return "CLASS_LIST ";
0N/A case MIXERCONTROL_CT_CLASS_METER : return "CLASS_METER ";
0N/A case MIXERCONTROL_CT_CLASS_NUMBER : return "CLASS_NUMBER";
0N/A case MIXERCONTROL_CT_CLASS_SLIDER : return "CLASS_SLIDER";
0N/A case MIXERCONTROL_CT_CLASS_SWITCH : return "CLASS_SWITCH";
0N/A case MIXERCONTROL_CT_CLASS_TIME : return "CLASS_TIME ";
0N/A }
0N/A return "unknown class";
0N/A}
0N/A
0N/Achar* getControlType(int controlType) {
0N/A switch (controlType) {
0N/A case MIXERCONTROL_CONTROLTYPE_CUSTOM : return "CUSTOM ";
0N/A case MIXERCONTROL_CONTROLTYPE_BASS : return "BASS ";
0N/A case MIXERCONTROL_CONTROLTYPE_EQUALIZER : return "EQUALIZER ";
0N/A case MIXERCONTROL_CONTROLTYPE_FADER : return "FADER ";
0N/A case MIXERCONTROL_CONTROLTYPE_TREBLE : return "TREBLE ";
0N/A case MIXERCONTROL_CONTROLTYPE_VOLUME : return "VOLUME ";
0N/A case MIXERCONTROL_CONTROLTYPE_MIXER : return "MIXER ";
0N/A case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT : return "MULTIPLESELECT ";
0N/A case MIXERCONTROL_CONTROLTYPE_MUX : return "MUX ";
0N/A case MIXERCONTROL_CONTROLTYPE_SINGLESELECT : return "SINGLESELECT ";
0N/A case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER : return "BOOLEANMETER ";
0N/A case MIXERCONTROL_CONTROLTYPE_PEAKMETER : return "PEAKMETER ";
0N/A case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER : return "SIGNEDMETER ";
0N/A case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER : return "UNSIGNEDMETER ";
0N/A case MIXERCONTROL_CONTROLTYPE_DECIBELS : return "DECIBELS ";
0N/A case MIXERCONTROL_CONTROLTYPE_PERCENT : return "PERCENT ";
0N/A case MIXERCONTROL_CONTROLTYPE_SIGNED : return "SIGNED ";
0N/A case MIXERCONTROL_CONTROLTYPE_UNSIGNED : return "UNSIGNED ";
0N/A case MIXERCONTROL_CONTROLTYPE_PAN : return "PAN ";
0N/A case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN : return "QSOUNDPAN ";
0N/A case MIXERCONTROL_CONTROLTYPE_SLIDER : return "SLIDER ";
0N/A case MIXERCONTROL_CONTROLTYPE_BOOLEAN : return "BOOLEAN ";
0N/A case MIXERCONTROL_CONTROLTYPE_BUTTON : return "BUTTON ";
0N/A case MIXERCONTROL_CONTROLTYPE_LOUDNESS : return "LOUDNESS ";
0N/A case MIXERCONTROL_CONTROLTYPE_MONO : return "MONO ";
0N/A case MIXERCONTROL_CONTROLTYPE_MUTE : return "MUTE ";
0N/A case MIXERCONTROL_CONTROLTYPE_ONOFF : return "ONOFF ";
0N/A case MIXERCONTROL_CONTROLTYPE_STEREOENH : return "STEREOENH ";
0N/A case MIXERCONTROL_CONTROLTYPE_MICROTIME : return "MICROTIME ";
0N/A case MIXERCONTROL_CONTROLTYPE_MILLITIME : return "MILLITIME ";
0N/A }
0N/A return "unknown";
0N/A}
0N/A
0N/Achar* getControlState(DWORD controlState) {
0N/A static char ret[100];
0N/A ret[0]=0;
0N/A if (controlState & MIXERCONTROL_CONTROLF_DISABLED) {
0N/A strcat(ret, "DISABLED ");
0N/A controlState ^= MIXERCONTROL_CONTROLF_DISABLED;
0N/A }
0N/A if (controlState & MIXERCONTROL_CONTROLF_MULTIPLE) {
0N/A strcat(ret, "MULTIPLE ");
0N/A controlState ^= MIXERCONTROL_CONTROLF_MULTIPLE;
0N/A }
0N/A if (controlState & MIXERCONTROL_CONTROLF_UNIFORM) {
0N/A strcat(ret, "UNIFORM ");
0N/A controlState ^= MIXERCONTROL_CONTROLF_UNIFORM;
0N/A }
0N/A if (controlState!=0) {
0N/A UINT_PTR r = (UINT_PTR) ret;
0N/A r += strlen(ret);
0N/A sprintf((char*) r, "%d", controlState);
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Avoid printControl(MIXERCONTROL* control) {
0N/A TRACE3(" %s: dwControlType=%s/%s, ", control->szName, getControlClass(control->dwControlType), getControlType(control->dwControlType));
0N/A TRACE3("multpleItems=%d, state=%d, %s\n", control->cMultipleItems, control->fdwControl, getControlState(control->fdwControl));
0N/A}
0N/A
0N/Avoid printMixerLineControls(HMIXER handle, MIXERLINE* mixerLine) {
0N/A MIXERLINECONTROLS controls;
0N/A DWORD i;
0N/A TRACE1(" Controls for %s:\n", mixerLine->szName);
0N/A if (getControlInfo(handle, mixerLine, &controls)) {
0N/A for (i = 0; i < controls.cControls; i++) {
0N/A printControl(&controls.pamxctrl[i]);
0N/A }
0N/A if (controls.pamxctrl) {
0N/A free(controls.pamxctrl);
0N/A controls.pamxctrl = NULL;
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid printInfo(PortInfo* info) {
0N/A TRACE5(" PortInfo %p: handle=%p, mixerIndex=%d, dstLineCount=%d, dstLines=%p, ", info, (void*) info->handle, info->mixerIndex, info->dstLineCount, info->dstLines);
0N/A TRACE5("srcLineCount=%d, srcLines=%p, targetPortCount=%d, sourcePortCount=%d, ports=%p, ", info->srcLineCount, info->srcLines, info->targetPortCount, info->sourcePortCount, info->ports);
0N/A TRACE3("maxControlCount=%d, usedControlIDs=%d, controlIDs=%p \n", info->maxControlCount, info->usedControlIDs, info->controlIDs);
0N/A TRACE2("usedMuxData=%d, muxData=%p, controlIDs=%p \n", info->usedMuxData, info->muxData);
0N/A}
0N/A
0N/A#endif // USE_TRACE
0N/A
0N/A// internal utility functions
0N/A
0N/Aint getMixerLineByDestination(HMIXER handle, DWORD dstIndex, MIXERLINE* mixerLine) {
0N/A mixerLine->cbStruct = sizeof(MIXERLINE);
0N/A mixerLine->dwDestination = dstIndex;
0N/A if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
0N/A MIXER_GETLINEINFOF_DESTINATION | MIXER_OBJECTF_HMIXER
0N/A ) == MMSYSERR_NOERROR) {
0N/A return TRUE;
0N/A }
0N/A mixerLine->cControls = 0;
0N/A mixerLine->cConnections = 0;
0N/A return FALSE;
0N/A}
0N/A
0N/Aint getMixerLineByType(HMIXER handle, DWORD linetype, MIXERLINE* mixerLine) {
0N/A mixerLine->cbStruct = sizeof(MIXERLINE);
0N/A mixerLine->dwComponentType = linetype;
0N/A if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
0N/A MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_HMIXER
0N/A ) == MMSYSERR_NOERROR) {
0N/A return TRUE;
0N/A }
0N/A mixerLine->cControls = 0;
0N/A mixerLine->cConnections = 0;
0N/A return FALSE;
0N/A}
0N/A
0N/Aint getMixerLineBySource(HMIXER handle, DWORD dstIndex, DWORD srcIndex, MIXERLINE* mixerLine) {
0N/A mixerLine->cbStruct = sizeof(MIXERLINE);
0N/A mixerLine->dwDestination = dstIndex;
0N/A mixerLine->dwSource = srcIndex;
0N/A if (mixerGetLineInfo((HMIXEROBJ) handle, mixerLine,
0N/A MIXER_GETLINEINFOF_SOURCE | MIXER_OBJECTF_HMIXER
0N/A ) == MMSYSERR_NOERROR) {
0N/A return TRUE;
0N/A }
0N/A mixerLine->cControls = 0;
0N/A mixerLine->cConnections = 0;
0N/A return FALSE;
0N/A}
0N/A
0N/Aint getControlInfo(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) {
0N/A int ret = FALSE;
0N/A
0N/A //TRACE2(">getControlInfo for line %s with %d controls\n", line->szName, line->cControls);
0N/A controls->pamxctrl = NULL;
0N/A if (line->cControls > 0) {
0N/A // line points to the requested line.
0N/A // Reserve memory for the control infos
0N/A controls->cbStruct = sizeof(MIXERLINECONTROLS);
0N/A controls->dwLineID = line->dwLineID;
0N/A controls->cControls = line->cControls;
0N/A controls->cbmxctrl = sizeof(MIXERCONTROL);
0N/A controls->pamxctrl = (MIXERCONTROL*) malloc(sizeof(MIXERCONTROL) * line->cControls);
0N/A if (controls->pamxctrl) {
0N/A //TRACE0(" calling mixerGetLineControls\n");
0N/A ret = mixerGetLineControls((HMIXEROBJ) handle, controls,
0N/A MIXER_GETLINECONTROLSF_ALL | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR;
0N/A }
0N/A }
0N/A if (!ret) {
0N/A if (controls->pamxctrl) {
0N/A free(controls->pamxctrl);
0N/A controls->pamxctrl = NULL;
0N/A }
0N/A }
0N/A //TRACE0("<getControlInfo \n");
0N/A return ret;
0N/A}
0N/A
0N/A// returns TRUE if there are more than MIXER/MUX controls in this line
0N/A// if controls is non-NULL, it will be filled with the info
0N/Aint lineHasControls(HMIXER handle, MIXERLINE* line, MIXERLINECONTROLS* controls) {
0N/A MIXERLINECONTROLS localControls;
0N/A int ret = FALSE;
0N/A UINT i;
0N/A
0N/A localControls.pamxctrl = NULL;
0N/A if (controls == NULL) {
0N/A controls = &localControls;
0N/A }
0N/A if (getControlInfo(handle, line, controls)) {
0N/A for (i = 0; !ret && (i < controls->cControls); i++) {
0N/A switch (controls->pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) {
0N/A case MIXERCONTROL_CT_CLASS_FADER : // fall through
0N/A case MIXERCONTROL_CT_CLASS_SLIDER : // fall through
0N/A case MIXERCONTROL_CT_CLASS_SWITCH : ret = TRUE;
0N/A }
0N/A }
0N/A }
0N/A if (localControls.pamxctrl) {
0N/A free(localControls.pamxctrl);
0N/A localControls.pamxctrl = NULL;
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/A
0N/A///// implemented functions of Ports.h
0N/A
0N/AINT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
0N/A MIXERCAPS mixerCaps;
0N/A if (mixerGetDevCaps(mixerIndex, &mixerCaps, sizeof(MIXERCAPS)) == MMSYSERR_NOERROR) {
0N/A strncpy(description->name, mixerCaps.szPname, PORT_STRING_LENGTH-1);
0N/A description->name[PORT_STRING_LENGTH-1] = 0;
0N/A sprintf(description->version, "%d.%d", (mixerCaps.vDriverVersion & 0xFF00) >> 8, mixerCaps.vDriverVersion & 0xFF);
0N/A strncpy(description->description, "Port Mixer", PORT_STRING_LENGTH-1);
0N/A return TRUE;
0N/A }
0N/A return FALSE;
0N/A}
0N/A
0N/Aint getDestinationCount(HMIXER handle) {
0N/A int ret = 0;
0N/A MIXERCAPS mixerCaps;
0N/A
0N/A if (mixerGetDevCaps((UINT_PTR) handle, &mixerCaps, sizeof(MIXERCAPS)) == MMSYSERR_NOERROR) {
0N/A ret = mixerCaps.cDestinations;
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Avoid* PORT_Open(INT32 mixerIndex) {
0N/A PortInfo* info = NULL;
0N/A MMRESULT mmres;
0N/A HMIXER handle;
0N/A MIXERLINE* waveInLine;
0N/A int success = FALSE;
0N/A int src, dst, srcIndex, waveInHasControls;
0N/A int dstCount;
0N/A
0N/A TRACE0("PORT_Open\n");
0N/A mmres = mixerOpen((LPHMIXER) &handle, mixerIndex, 0, 0, MIXER_OBJECTF_MIXER);
0N/A if (mmres != MMSYSERR_NOERROR) {
0N/A return NULL;
0N/A }
0N/A
0N/A info = (PortInfo*) malloc(sizeof(PortInfo));
0N/A if (info != NULL) {
0N/A success = TRUE;
0N/A memset(info, 0, sizeof(PortInfo));
0N/A info->handle = handle;
0N/A info->mixerIndex = mixerIndex;
0N/A waveInLine = NULL;
0N/A waveInHasControls = FALSE;
0N/A // number of destinations
0N/A dstCount = getDestinationCount(handle);
0N/A if (dstCount) {
0N/A info->dstLines = (MIXERLINE*) malloc(dstCount * sizeof(MIXERLINE));
0N/A success = (info->dstLines != NULL);
0N/A }
0N/A if (success && info->dstLines) {
0N/A // go through all destinations and fill the structures in PortInfo
0N/A for (dst = 0; dst < dstCount; dst++) {
0N/A if (getMixerLineByDestination(handle, dst, &info->dstLines[info->dstLineCount])) {
0N/A info->srcLineCount += info->dstLines[info->dstLineCount].cConnections;
0N/A if (info->dstLines[info->dstLineCount].dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN && !waveInLine) {
0N/A waveInLine = &info->dstLines[info->dstLineCount];
0N/A info->sourcePortCount = waveInLine->cConnections;
0N/A if (lineHasControls(handle, waveInLine, NULL)) {
0N/A // add a single port for all the controls that do not show in the MUX/MIXER controls
0N/A info->sourcePortCount++;
0N/A waveInHasControls = TRUE;
0N/A }
0N/A } else {
0N/A info->targetPortCount++;
0N/A }
0N/A info->dstLineCount++;
0N/A }
0N/A }
0N/A }
0N/A if (info->srcLineCount) {
0N/A info->srcLines = (MIXERLINE*) malloc(info->srcLineCount * sizeof(MIXERLINE));
0N/A success = (info->srcLines != NULL);
0N/A }
0N/A if (success && info->srcLines) {
0N/A // go through all destinations and fill the source line structures in PortInfo
0N/A srcIndex = 0;
0N/A for (dst = 0; dst < info->dstLineCount; dst++) {
0N/A // remember the srcIndex for mapping the srcLines to this destination line
0N/A info->dstLines[dst].dwUser = srcIndex;
0N/A for (src = 0; src < (int) info->dstLines[dst].cConnections; src++) {
0N/A getMixerLineBySource(handle, dst, src, &info->srcLines[srcIndex++]);
0N/A }
0N/A }
0N/A }
0N/A // now create the mapping to Java Sound
0N/A if ((info->targetPortCount + info->sourcePortCount) > 0) {
0N/A info->ports = (LPMIXERLINE*) malloc((info->targetPortCount + info->sourcePortCount) * sizeof(LPMIXERLINE));
0N/A success = (info->ports != NULL);
0N/A }
0N/A if (success && info->ports) {
0N/A // first add the target MIXERLINEs to the array
0N/A srcIndex = 0;
0N/A for (dst = 0; dst < info->dstLineCount; dst++) {
0N/A if (waveInLine != &info->dstLines[dst]) {
0N/A info->ports[srcIndex++] = &info->dstLines[dst];
0N/A }
0N/A }
0N/A if (srcIndex != info->targetPortCount) {
0N/A ERROR2("srcIndex=%d is NOT targetPortCount=%d !\n", srcIndex, info->targetPortCount);
0N/A }
0N/A //srcIndex = info->targetPortCount; // should be automatic!
0N/A if (waveInLine) {
0N/A // if the recording destination line has controls, add the line
0N/A if (waveInHasControls) {
0N/A info->ports[srcIndex++] = waveInLine;
0N/A }
0N/A for (src = 0; src < (int) waveInLine->cConnections; src++) {
0N/A info->ports[srcIndex++] = &info->srcLines[src + waveInLine->dwUser];
0N/A }
0N/A }
0N/A if (srcIndex != (info->targetPortCount + info->sourcePortCount)) {
0N/A ERROR2("srcIndex=%d is NOT PortCount=%d !\n", srcIndex, (info->targetPortCount + info->sourcePortCount));
0N/A }
0N/A }
0N/A }
0N/A if (!success) {
0N/A if (handle != NULL) {
0N/A mixerClose(handle);
0N/A }
0N/A PORT_Close((void*) info);
0N/A info = NULL;
0N/A }
0N/A return info;
0N/A}
0N/A
0N/Avoid PORT_Close(void* id) {
0N/A TRACE0("PORT_Close\n");
0N/A if (id != NULL) {
0N/A PortInfo* info = (PortInfo*) id;
0N/A if (info->handle) {
0N/A mixerClose(info->handle);
0N/A info->handle = NULL;
0N/A }
0N/A if (info->dstLines) {
0N/A free(info->dstLines);
0N/A info->dstLines = NULL;
0N/A }
0N/A if (info->srcLines) {
0N/A free(info->srcLines);
0N/A info->srcLines=NULL;
0N/A }
0N/A if (info->ports) {
0N/A free(info->ports);
0N/A info->ports = NULL;
0N/A }
0N/A if (info->controlIDs) {
0N/A free(info->controlIDs);
0N/A info->controlIDs = NULL;
0N/A }
0N/A if (info->muxData) {
0N/A free(info->muxData);
0N/A info->muxData = NULL;
0N/A }
0N/A free(info);
0N/A }
0N/A}
0N/A
0N/AINT32 PORT_GetPortCount(void* id) {
0N/A int ret = 0;
0N/A PortInfo* info = (PortInfo*) id;
0N/A if (info != NULL) {
0N/A ret = info->targetPortCount + info->sourcePortCount;
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Aint componentType2type(DWORD componentType) {
0N/A int ret = 0;
0N/A if (componentType >= MIXERLINE_COMPONENTTYPE_DST_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_DST_LAST) {
0N/A ret = PORT_DST_UNKNOWN;
0N/A }
0N/A else if (componentType >= MIXERLINE_COMPONENTTYPE_SRC_FIRST && componentType <= MIXERLINE_COMPONENTTYPE_SRC_LAST) {
0N/A ret = PORT_SRC_UNKNOWN;
0N/A }
0N/A // handle special cases
0N/A switch (componentType) {
0N/A case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: ret = PORT_DST_HEADPHONE; break;
0N/A case MIXERLINE_COMPONENTTYPE_DST_LINE: ret = PORT_DST_LINE_OUT; break;
0N/A case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: ret = PORT_DST_SPEAKER; break;
0N/A case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: ret = PORT_SRC_COMPACT_DISC; break;
0N/A case MIXERLINE_COMPONENTTYPE_SRC_LINE: ret = PORT_SRC_LINE_IN; break;
0N/A case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: ret = PORT_SRC_MICROPHONE; break;
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/AINT32 PORT_GetPortType(void* id, INT32 portIndex) {
0N/A MIXERLINE* line;
0N/A PortInfo* info = (PortInfo*) id;
0N/A if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
0N/A line = info->ports[portIndex];
0N/A if (line) {
0N/A return componentType2type(line->dwComponentType);
0N/A }
0N/A }
0N/A return 0;
0N/A}
0N/A
0N/AINT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
0N/A MIXERLINE* line;
0N/A PortInfo* info = (PortInfo*) id;
0N/A
0N/A if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
0N/A line = info->ports[portIndex];
0N/A if (line) {
0N/A strncpy(name, line->szName, len-1);
0N/A name[len-1] = 0;
0N/A return TRUE;
0N/A }
0N/A }
0N/A return FALSE;
0N/A}
0N/A
0N/Aint getControlCount(HMIXER handle, MIXERLINE* line, INT32* muxCount) {
0N/A MIXERLINECONTROLS controls;
0N/A int ret = 0;
0N/A UINT i;
0N/A
0N/A controls.pamxctrl = NULL;
0N/A if (getControlInfo(handle, line, &controls)) {
0N/A for (i = 0; i < controls.cControls; i++) {
0N/A switch (controls.pamxctrl[i].dwControlType & MIXERCONTROL_CT_CLASS_MASK) {
0N/A case MIXERCONTROL_CT_CLASS_FADER : // fall through
0N/A case MIXERCONTROL_CT_CLASS_SLIDER : // fall through
0N/A case MIXERCONTROL_CT_CLASS_SWITCH : // fall through
0N/A case MIXERCONTROL_CT_CLASS_LIST : ret++; break;
0N/A }
0N/A if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
0N/A || (controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)) {
0N/A ret += controls.pamxctrl[i].cMultipleItems;
0N/A if (muxCount) {
0N/A (*muxCount) += controls.pamxctrl[i].cMultipleItems;
0N/A }
0N/A }
0N/A else if ((controls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
0N/A && (line->cChannels == 2)) {
0N/A ret++; // for FAKE volume/balance pairs
0N/A }
0N/A }
0N/A }
0N/A if (controls.pamxctrl) {
0N/A free(controls.pamxctrl);
0N/A controls.pamxctrl = NULL;
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/AMIXERLINE* findDestLine(PortInfo* info, DWORD dwDestination) {
0N/A int i;
0N/A TRACE0(">findDestLine\n");
0N/A for (i = 0; i < info->dstLineCount; i++) {
0N/A if (info->dstLines[i].dwDestination == dwDestination) {
0N/A TRACE0("<findDestLine\n");
0N/A return &(info->dstLines[i]);
0N/A }
0N/A }
0N/A TRACE0("<findDestLine NULL\n");
0N/A return NULL;
0N/A}
0N/A
0N/Avoid createMuxControl(PortInfo* info, PortControlCreator* creator, MIXERLINE* dstLine, DWORD srcLineID, void** controlObjects, int* controlCount) {
0N/A MIXERLINECONTROLS controlInfos;
0N/A MIXERCONTROLDETAILS* details;
0N/A MIXERCONTROLDETAILS_LISTTEXT* listTextDetails = NULL;
0N/A UINT listTextDetailCount = 0;
0N/A PortControlID* controlID;
0N/A UINT i, c;
0N/A int m;
0N/A
0N/A TRACE0(">createMuxControl\n");
0N/A // go through all controls of dstline
0N/A controlInfos.pamxctrl = NULL;
0N/A if (getControlInfo(info->handle, dstLine, &controlInfos)) {
0N/A for (i = 0; i < controlInfos.cControls; i++) {
0N/A if (((controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER)
0N/A || (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX))
0N/A && (controlInfos.pamxctrl[i].cMultipleItems > 0)) {
0N/A if (info->usedControlIDs >= info->maxControlCount) {
0N/A ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
0N/A break;
0N/A }
0N/A // get the details for this mux control
0N/A controlID = &(info->controlIDs[info->usedControlIDs]);
0N/A controlID->portInfo = info;
0N/A if (controlInfos.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER) {
0N/A controlID->controlType = PORT_CONTROL_TYPE_MIXER;
0N/A } else {
0N/A controlID->controlType = PORT_CONTROL_TYPE_MUX;
0N/A }
0N/A details = &(controlID->details);
0N/A details->cbStruct = sizeof(MIXERCONTROLDETAILS);
0N/A details->dwControlID = controlInfos.pamxctrl[i].dwControlID;
0N/A details->cChannels = 1;
0N/A details->cMultipleItems = controlInfos.pamxctrl[i].cMultipleItems;
0N/A details->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
0N/A if (!listTextDetails || (listTextDetailCount < (details->cMultipleItems * details->cChannels))) {
0N/A // need to allocate new listTextDetails
0N/A if (listTextDetails) {
0N/A free(listTextDetails);
0N/A listTextDetails = NULL;
0N/A }
0N/A listTextDetailCount = details->cMultipleItems * details->cChannels;
0N/A listTextDetails = (MIXERCONTROLDETAILS_LISTTEXT*) malloc(listTextDetailCount * sizeof(MIXERCONTROLDETAILS_LISTTEXT));
0N/A if (!listTextDetails) {
0N/A ERROR0("createMuxControl: unable to allocate listTextDetails!\n");
0N/A if (controlInfos.pamxctrl) {
0N/A free(controlInfos.pamxctrl);
0N/A controlInfos.pamxctrl = NULL;
0N/A }
0N/A TRACE0("<createMuxControl ERROR\n");
0N/A return;
0N/A }
0N/A }
0N/A details->paDetails = listTextDetails;
0N/A if (mixerGetControlDetails((HMIXEROBJ) info->handle, details, MIXER_GETCONTROLDETAILSF_LISTTEXT | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
0N/A ERROR0("createMuxControl: unable to get control details!\n");
0N/A continue;
0N/A }
0N/A // prevent freeing this data
0N/A details->paDetails = NULL;
0N/A // go through all mux items. If the line matches, then add a BOOLEAN select control
0N/A for (c = 0; c < details->cMultipleItems; c++) {
0N/A if (listTextDetails[c].dwParam1 == srcLineID) {
0N/A // we have found the line in the MUX lines.
0N/A controlID->muxIndex = c;
0N/A details->cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
0N/A // now look if any other controlID was already part of this MUX line
0N/A for (m = 0; m < info->usedControlIDs; m++) {
0N/A if (info->controlIDs[m].details.dwControlID == details->dwControlID) {
0N/A // reuse the MUX Data
0N/A TRACE2("Reusing paDetails=%p of controlID[%d]\n", info->controlIDs[m].details.paDetails, m);
0N/A details->paDetails = info->controlIDs[m].details.paDetails;
0N/A break;
0N/A }
0N/A }
0N/A if (!details->paDetails) {
0N/A // first time this MUX control is used, allocate some of the muxData
0N/A details->paDetails = &(info->muxData[info->usedMuxData]);
0N/A TRACE2("Setting paDetails=%p to muxData[%d] \n", details->paDetails, info->usedMuxData);
0N/A info->usedMuxData += details->cMultipleItems;
0N/A }
0N/A // finally this line can be added
0N/A controlObjects[*controlCount] = (creator->newBooleanControl)(creator, controlID, CONTROL_TYPE_SELECT);
0N/A (*controlCount)++;
0N/A info->usedControlIDs++;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A if (listTextDetails) {
0N/A free(listTextDetails);
0N/A listTextDetails = NULL;
0N/A }
0N/A if (controlInfos.pamxctrl) {
0N/A free(controlInfos.pamxctrl);
0N/A controlInfos.pamxctrl = NULL;
0N/A }
0N/A TRACE0("<createMuxControl\n");
0N/A}
0N/A
0N/Avoid createPortControl(PortInfo* info, PortControlCreator* creator, MIXERCONTROL* mixerControl,
0N/A INT32 type, void** controlObjects, int* controlCount) {
0N/A PortControlID* controlID;
0N/A void* newControl = NULL;
0N/A char* typeName = mixerControl->szName;
0N/A float min;
0N/A TRACE0(">createPortControl\n");
0N/A
0N/A // fill the ControlID structure and add this control
0N/A if (info->usedControlIDs >= info->maxControlCount) {
0N/A ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
0N/A return;
0N/A }
0N/A controlID = &(info->controlIDs[info->usedControlIDs]);
0N/A controlID->portInfo = info;
0N/A controlID->controlType = type;
0N/A controlID->details.cbStruct = sizeof(MIXERCONTROLDETAILS);
0N/A controlID->details.dwControlID = mixerControl->dwControlID;
0N/A controlID->details.cChannels = 1; // uniform
0N/A controlID->details.cMultipleItems = 0;
0N/A switch (type) {
0N/A case PORT_CONTROL_TYPE_BOOLEAN:
0N/A TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
0N/A controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
0N/A controlID->details.paDetails = &(controlID->boolValue);
0N/A if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) {
0N/A typeName = CONTROL_TYPE_MUTE;
0N/A }
0N/A newControl = (creator->newBooleanControl)(creator, controlID, typeName);
0N/A break;
0N/A case PORT_CONTROL_TYPE_SIGNED:
0N/A TRACE0(" PORT_CONTROL_TYPE_SIGNED\n");
0N/A controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
0N/A controlID->details.paDetails = &(controlID->signedValue);
0N/A controlID->min = (INT32) mixerControl->Bounds.lMinimum;
0N/A controlID->max = (INT32) mixerControl->Bounds.lMaximum;
0N/A if (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_PAN) {
0N/A typeName = CONTROL_TYPE_PAN;
0N/A }
0N/A newControl = (creator->newFloatControl)(creator, controlID, typeName,
0N/A -1.0f, 1.0f, 2.0f / (controlID->max - controlID->min + 1), "");
0N/A break;
0N/A case PORT_CONTROL_TYPE_FAKE_VOLUME: // fall through
0N/A case PORT_CONTROL_TYPE_FAKE_BALANCE: // fall through
0N/A case PORT_CONTROL_TYPE_UNSIGNED:
0N/A TRACE0(" PORT_CONTROL_TYPE_UNSIGNED\n");
0N/A controlID->details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
0N/A controlID->details.paDetails = &(controlID->unsignedValue[0]);
0N/A controlID->min = (INT32) mixerControl->Bounds.dwMinimum;
0N/A controlID->max = (INT32) mixerControl->Bounds.dwMaximum;
0N/A min = 0.0f;
0N/A if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME)
0N/A || (mixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) {
0N/A typeName = CONTROL_TYPE_VOLUME;
0N/A }
0N/A if (type == PORT_CONTROL_TYPE_FAKE_BALANCE) {
0N/A typeName = CONTROL_TYPE_BALANCE;
0N/A min = -1.0f;
0N/A }
0N/A if ((type == PORT_CONTROL_TYPE_FAKE_VOLUME)
0N/A || (type == PORT_CONTROL_TYPE_FAKE_BALANCE)) {
0N/A controlID->details.cChannels = 2;
0N/A }
0N/A TRACE0(" ....PORT_CONTROL_TYPE_UNSIGNED\n");
0N/A newControl = (creator->newFloatControl)(creator, controlID, typeName,
0N/A min, 1.0f, 1.0f / (controlID->max - controlID->min + 1), "");
0N/A break;
0N/A default:
0N/A ERROR1("createPortControl: unknown type %d !", type);
0N/A break;
0N/A }
0N/A if (newControl) {
0N/A controlObjects[*controlCount] = newControl;
0N/A (*controlCount)++;
0N/A info->usedControlIDs++;
0N/A }
0N/A TRACE0("<createPortControl\n");
0N/A}
0N/A
0N/Avoid createLineControls(PortInfo* info, PortControlCreator* creator, MIXERLINE* line, void** controlObjects, int* controlCount) {
0N/A MIXERLINECONTROLS controlInfos;
0N/A MIXERCONTROL* mixerControl;
0N/A UINT i;
0N/A INT32 type;
0N/A
0N/A TRACE1(">createLineControls for line %s\n", line->szName);
0N/A // go through all controls of line
0N/A controlInfos.pamxctrl = NULL;
0N/A if (getControlInfo(info->handle, line, &controlInfos)) {
0N/A for (i = 0; i < controlInfos.cControls; i++) {
0N/A TRACE1(" %d\n", i);
0N/A mixerControl = &(controlInfos.pamxctrl[i]);
0N/A type = 0;
0N/A switch (mixerControl->dwControlType) {
0N/A case MIXERCONTROL_CONTROLTYPE_BOOLEAN : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_BUTTON : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_LOUDNESS : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_MONO : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_MUTE : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_ONOFF : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_STEREOENH: type = PORT_CONTROL_TYPE_BOOLEAN; break;
0N/A
0N/A case MIXERCONTROL_CONTROLTYPE_PAN : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN: // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_SLIDER : type = PORT_CONTROL_TYPE_SIGNED; break;
0N/A
0N/A case MIXERCONTROL_CONTROLTYPE_BASS : // fall through
0N/A //case MIXERCONTROL_CONTROLTYPE_EQUALIZER: // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_FADER : // fall through
0N/A case MIXERCONTROL_CONTROLTYPE_TREBLE : type = PORT_CONTROL_TYPE_UNSIGNED; break;
0N/A case MIXERCONTROL_CONTROLTYPE_VOLUME :
0N/A type = PORT_CONTROL_TYPE_UNSIGNED;
0N/A if (line->cChannels == 2 && ((mixerControl->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) == 0)) {
0N/A type = PORT_CONTROL_TYPE_FAKE_VOLUME;
0N/A }
0N/A break;
0N/A }
0N/A if (type != 0) {
0N/A createPortControl(info, creator, mixerControl, type, controlObjects, controlCount);
0N/A // create fake balance for fake volume
0N/A if (type == PORT_CONTROL_TYPE_FAKE_VOLUME) {
0N/A createPortControl(info, creator, mixerControl, PORT_CONTROL_TYPE_FAKE_BALANCE, controlObjects, controlCount);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A if (controlInfos.pamxctrl) {
0N/A free(controlInfos.pamxctrl);
0N/A controlInfos.pamxctrl = NULL;
0N/A }
0N/A TRACE0("<createLineControls\n");
0N/A}
0N/A
0N/Avoid addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
0N/A void* compControl;
0N/A
0N/A TRACE1(">addCompoundControl %d controls\n", *controlCount);
0N/A if (*controlCount) {
0N/A // create compound control and add it to the vector
0N/A compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount);
0N/A if (compControl) {
0N/A TRACE1(" addCompoundControl: calling addControl %p\n", compControl);
0N/A (creator->addControl)(creator, compControl);
0N/A }
0N/A *controlCount = 0;
0N/A }
0N/A TRACE0("<addCompoundControl\n");
0N/A}
0N/A
0N/Avoid addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
0N/A int i = 0;
0N/A
0N/A TRACE0(">addAllControl\n");
0N/A // go through all controls and add them to the vector
0N/A for (i = 0; i < *controlCount; i++) {
0N/A (creator->addControl)(creator, controlObjects[i]);
0N/A }
0N/A *controlCount = 0;
0N/A TRACE0("<addAllControl\n");
0N/A}
0N/A
0N/A
0N/A
0N/Avoid PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
0N/A MIXERLINE* line;
0N/A PortInfo* info = (PortInfo*) id;
0N/A int portCount = PORT_GetPortCount(id);
0N/A void** controls = NULL;
0N/A int controlCount;
0N/A UINT i;
0N/A
0N/A TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", id, portIndex, info->controlIDs, info->maxControlCount);
0N/A if ((portIndex >= 0) && (portIndex < portCount)) {
0N/A line = info->ports[portIndex];
0N/A if (line) {
0N/A // if the memory isn't reserved for the control structures, allocate it
0N/A if (!info->controlIDs) {
0N/A int i, maxCount = 0, muxCount = 0;
0N/A TRACE0("getControl: allocate mem\n");
0N/A // get a maximum number of controls
0N/A // first for all destination lines
0N/A for (i = 0; i < info->dstLineCount; i++) {
0N/A MIXERLINE* thisLine = &(info->dstLines[i]);
0N/A maxCount += getControlCount(info->handle, thisLine, &muxCount);
0N/A }
0N/A // then all source lines
0N/A for (i = 0; i < info->srcLineCount; i++) {
0N/A MIXERLINE* thisLine = &(info->srcLines[i]);
0N/A maxCount += getControlCount(info->handle, thisLine, &muxCount);
0N/A }
0N/A info->maxControlCount = maxCount;
0N/A if (maxCount > 0) {
0N/A info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount);
0N/A } else {
0N/A // no ports: nothing to do !
0N/A return;
0N/A }
0N/A TRACE2("Creating muxData for %d elements and %d controlIDs.\n", muxCount, maxCount);
0N/A if (muxCount > 0) {
0N/A info->muxData = (MIXERCONTROLDETAILS_BOOLEAN*) malloc(sizeof(MIXERCONTROLDETAILS_BOOLEAN) * muxCount);
0N/A }
0N/A if (!info->controlIDs || (muxCount && !info->muxData)) {
0N/A ERROR3("PORT_GetControls: info->controlIDs=%p, muxCount=%d, info->muxData=%p !!\n", info->controlIDs, muxCount, info->muxData);
0N/A return;
0N/A }
0N/A }
0N/A if (info->maxControlCount == 0) {
0N/A return;
0N/A }
0N/A controls = (void*) malloc(info->maxControlCount * sizeof(void*));
0N/A if (!controls) {
0N/A ERROR0("PORT_GetControls: couldn't allocate controls!\n");
0N/A return;
0N/A }
0N/A
0N/A // add controls of this line
0N/A controlCount = 0;
0N/A // if this line is part of MUX, add the respective BOOLEANCONTROL as a control
0N/A if ((line->fdwLine & MIXERLINE_LINEF_SOURCE) == MIXERLINE_LINEF_SOURCE) {
0N/A MIXERLINE* dstLine = findDestLine(info, line->dwDestination);
0N/A TRACE0("Port_getControls: this is a source line\n");
0N/A if (dstLine) {
0N/A // selection controls (implemented as Mute control)
0N/A createMuxControl(info, creator, dstLine, line->dwLineID, controls, &controlCount);
0N/A }
0N/A // then add all controls in one compound control
0N/A createLineControls(info, creator, line, controls, &controlCount);
0N/A addCompoundControl(info, creator, line->szName, controls, &controlCount);
0N/A } else {
0N/A TRACE0("getControl: this is a dest line\n");
0N/A // if this is a destination line, add its controls
0N/A createLineControls(info, creator, line, controls, &controlCount);
0N/A addAllControls(info, creator, controls, &controlCount);
0N/A // then add all controls of its source lines as one compound control
0N/A for (i = 0; i < line->cConnections; i++) {
0N/A // then add all controls
0N/A MIXERLINE* srcLine = &(info->srcLines[line->dwUser + i]);
0N/A TRACE1("PORT_getControls: add source line %d\n", i);
0N/A createLineControls(info, creator, srcLine, controls, &controlCount);
0N/A addCompoundControl(info, creator, srcLine->szName, controls, &controlCount);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A if (controls) {
0N/A free(controls);
0N/A }
0N/A TRACE0("< PORT_getControls\n");
0N/A}
0N/A
0N/Aint getControlValue(PortControlID* controlID) {
0N/A if (mixerGetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details),
0N/A MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
0N/A ERROR0("getControlValue: unable to get control details!\n");
0N/A //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels);
0N/A //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails);
0N/A return FALSE;
0N/A }
0N/A return TRUE;
0N/A}
0N/A
0N/Aint setControlValue(PortControlID* controlID) {
0N/A if (mixerSetControlDetails((HMIXEROBJ) controlID->portInfo->handle, &(controlID->details),
0N/A MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) != MMSYSERR_NOERROR) {
0N/A ERROR0("setControlValue: unable to set control details!\n");
0N/A //ERROR3(" cbStruct=%d, dwControlID=%d, cChannels=%d, ", controlID->details.cbStruct, controlID->details.dwControlID, controlID->details.cChannels);
0N/A //ERROR2(" cMultipleItems=%d, cbDetails=%d\n", controlID->details.cMultipleItems, controlID->details.cbDetails);
0N/A return FALSE;
0N/A }
0N/A return TRUE;
0N/A}
0N/A
0N/AINT32 PORT_GetIntValue(void* controlIDV) {
0N/A PortControlID* controlID = (PortControlID*) controlIDV;
0N/A MIXERCONTROLDETAILS_BOOLEAN* bools;
0N/A int ret = 0;
0N/A if (getControlValue(controlID)) {
0N/A switch (controlID->controlType) {
0N/A case PORT_CONTROL_TYPE_MUX: // fall through
0N/A case PORT_CONTROL_TYPE_MIXER:
0N/A bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
0N/A ret = (bools[controlID->muxIndex].fValue)?TRUE:FALSE;
0N/A break;
0N/A case PORT_CONTROL_TYPE_BOOLEAN:
0N/A ret = (controlID->boolValue.fValue)?TRUE:FALSE;
0N/A break;
0N/A default: ERROR1("PORT_GetIntValue: wrong controlType=%d !\n", controlID->controlType);
0N/A }
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Avoid PORT_SetIntValue(void* controlIDV, INT32 value) {
0N/A PortControlID* controlID = (PortControlID*) controlIDV;
0N/A MIXERCONTROLDETAILS_BOOLEAN* bools;
0N/A UINT i;
0N/A
0N/A switch (controlID->controlType) {
0N/A case PORT_CONTROL_TYPE_MUX:
0N/A if (!value) {
0N/A // cannot unselect a MUX line
0N/A return;
0N/A }
0N/A if (!getControlValue(controlID)) {
0N/A return;
0N/A }
0N/A bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
0N/A for (i = 0; i < controlID->details.cMultipleItems; i++) {
0N/A bools[i].fValue = (i == (UINT) controlID->muxIndex)?TRUE:FALSE;
0N/A }
0N/A break;
0N/A case PORT_CONTROL_TYPE_MIXER:
0N/A if (!getControlValue(controlID)) {
0N/A return;
0N/A }
0N/A bools = (MIXERCONTROLDETAILS_BOOLEAN*) controlID->details.paDetails;
0N/A bools[controlID->muxIndex].fValue = (value?TRUE:FALSE);
0N/A break;
0N/A case PORT_CONTROL_TYPE_BOOLEAN:
0N/A controlID->boolValue.fValue = (value?TRUE:FALSE);
0N/A break;
0N/A default:
0N/A ERROR1("PORT_SetIntValue: wrong controlType=%d !\n", controlID->controlType);
0N/A return;
0N/A }
0N/A setControlValue(controlID);
0N/A}
0N/A
0N/Afloat getFakeBalance(PortControlID* controlID) {
0N/A float volL, volR;
0N/A float range = (float) (controlID->max - controlID->min);
0N/A // pan is the ratio of left and right
0N/A volL = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range);
0N/A volR = (((float) (controlID->unsignedValue[1].dwValue - controlID->min)) / range);
0N/A if (volL > volR) {
0N/A return -1.0f + (volR / volL);
0N/A }
0N/A else if (volR > volL) {
0N/A return 1.0f - (volL / volR);
0N/A }
0N/A return 0.0f;
0N/A}
0N/A
0N/Afloat getFakeVolume(PortControlID* controlID) {
0N/A // volume is the greater value of both
0N/A UINT vol = controlID->unsignedValue[0].dwValue;
0N/A if (controlID->unsignedValue[1].dwValue > vol) {
0N/A vol = controlID->unsignedValue[1].dwValue;
0N/A }
0N/A return (((float) (vol - controlID->min)) / (controlID->max - controlID->min));
0N/A}
0N/A
0N/A/*
0N/A * sets the unsigned values for left and right volume according to
0N/A * the given volume (0...1) and balance (-1..0..+1)
0N/A */
0N/Avoid setFakeVolume(PortControlID* controlID, float vol, float bal) {
0N/A vol = vol * (controlID->max - controlID->min);
0N/A if (bal < 0.0f) {
0N/A controlID->unsignedValue[0].dwValue = (UINT) (vol + 0.5f) + controlID->min;
0N/A controlID->unsignedValue[1].dwValue = (UINT) ((vol * (bal + 1.0f)) + 0.5f) + controlID->min;
0N/A } else {
0N/A controlID->unsignedValue[1].dwValue = (UINT) (vol + 0.5f) + controlID->min;
0N/A controlID->unsignedValue[0].dwValue = (UINT) ((vol * (1.0f - bal)) + 0.5f) + controlID->min;
0N/A }
0N/A}
0N/A
0N/Afloat PORT_GetFloatValue(void* controlIDV) {
0N/A PortControlID* controlID = (PortControlID*) controlIDV;
0N/A float ret = 0.0f;
0N/A float range = (float) (controlID->max - controlID->min);
0N/A if (getControlValue(controlID)) {
0N/A switch (controlID->controlType) {
0N/A case PORT_CONTROL_TYPE_SIGNED:
0N/A ret = ((float) controlID->signedValue.lValue) / controlID->max;
0N/A break;
0N/A case PORT_CONTROL_TYPE_UNSIGNED:
0N/A ret = (((float) (controlID->unsignedValue[0].dwValue - controlID->min)) / range);
0N/A break;
0N/A case PORT_CONTROL_TYPE_FAKE_VOLUME:
0N/A ret = getFakeVolume(controlID);
0N/A break;
0N/A case PORT_CONTROL_TYPE_FAKE_BALANCE:
0N/A ret = getFakeBalance(controlID);
0N/A break;
0N/A default: ERROR1("PORT_GetFloatValue: wrong controlType=%d !\n", controlID->controlType);
0N/A }
0N/A }
0N/A return ret;
0N/A}
0N/A
0N/Avoid PORT_SetFloatValue(void* controlIDV, float value) {
0N/A PortControlID* controlID = (PortControlID*) controlIDV;
0N/A float range = (float) (controlID->max - controlID->min);
0N/A switch (controlID->controlType) {
0N/A case PORT_CONTROL_TYPE_SIGNED:
0N/A controlID->signedValue.lValue = (INT32) ((value * controlID->max) + 0.5f);
0N/A break;
0N/A case PORT_CONTROL_TYPE_UNSIGNED:
0N/A controlID->unsignedValue[0].dwValue = (INT32) ((value * range) + 0.5f) + controlID->min;
0N/A break;
0N/A case PORT_CONTROL_TYPE_FAKE_VOLUME:
0N/A if (!getControlValue(controlID)) {
0N/A return;
0N/A }
0N/A setFakeVolume(controlID, value, getFakeBalance(controlID));
0N/A break;
0N/A case PORT_CONTROL_TYPE_FAKE_BALANCE:
0N/A if (!getControlValue(controlID)) {
0N/A return;
0N/A }
0N/A setFakeVolume(controlID, getFakeVolume(controlID), value);
0N/A break;
0N/A default:
0N/A ERROR1("PORT_SetFloatValue: wrong controlType=%d !\n", controlID->controlType);
0N/A return;
0N/A }
0N/A setControlValue(controlID);
0N/A}
0N/A
0N/A#endif // USE_PORTS