alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (PLATFORM_API_MacOSX_Ports.cpp)

This example Java source code file (PLATFORM_API_MacOSX_Ports.cpp) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

audiocontrol, createportcontrol, float32, fourcc2str, getaudioobjectproperty, int32, null, osstatus, port_getcontrols, portcontrol, portmixer, trace1, uint32, validcontrolcount

The PLATFORM_API_MacOSX_Ports.cpp Java example source code

/*
 * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

//#define USE_ERROR
//#define USE_TRACE

#include <CoreAudio/CoreAudio.h>
#include <IOKit/audio/IOAudioTypes.h>

#include "PLATFORM_API_MacOSX_Utils.h"

extern "C" {
#include "Ports.h"
}

#if USE_PORTS == TRUE

/* If a device has the only AudioStream in the scope (input or output),
 * PortMixer provides a single Port, using the stream kAudioStreamPropertyTerminalType
 * property value to determine Port.Type (PORT_GetPortType function).
 * If the device has several (more than 1) AudioStreams, there are 2 ways to represent Ports:
 * 1. (HALLab-style) single Port which represents all device channels with
 *    "master volume" and (if number of channel is 2) "master balance"; if AudioDevice
 *    does not provide "master" controls, implement "virtual master" controls.
 *    Port.Type is PORT_SRC_UNKNOWN or PORT_DST_UNKNOWN.
 * 2. provide a separate Port for every AudioStream (with appropriate Port.Type);
 *
 * AudioHardware.h claims that AudioStream objects share AudioControl objects with their owning AudioDevice.
 * In practice 10.7 OSX drivers (built-in devices, USB audio) implement AudioControl only for AudioDevice.
 * For now 1st way is implemented (2nd way can be better if AudioStreams provide AudioControls).
 */

static DeviceList deviceCache;

#define FourCC2Str(n) ((char[5]){(char)(n >> 24), (char)(n >> 16), (char)(n >> 8), (char)(n), 0})


// CoreAudio's AudioControl
struct AudioControl {
    AudioObjectID controlID;
    AudioClassID classID;               // kAudioVolumeControlClassID etc.
    AudioObjectPropertyScope scope;     // input, output
    AudioObjectPropertyElement channel; // master = 0, channels = 1 2 ...
};

// Controls for Java
// PortMixer do all memory management (alloc/free audioControls)
struct PortControl {
    enum ControlType {
        Volume,     // manages single or multiple volume AudioControl
        Mute,       // manages single or multiple mute AudioControls
        Balance     // "virtual" control, manages 2 volume AudioControls (only for stereo lines)
    };
    ControlType type;

    int controlCount;
    AudioControl **audioControls;

    PortControl *next;  // to organize PortControl list
};

// represents line (port) for PortMixer
// used for PORT_GetPortCount/PORT_GetPortType/PORT_GetPortName functions
struct PortLine {
    AudioObjectPropertyScope scope;
    // if the device has several AudioStreams in the scope, streamID == 0
    AudioStreamID streamID;
};

struct PortMixer {
    AudioDeviceID deviceID;

    int portCount;
    PortLine ports[2]; // maximum 2 lines - 1 for input & 1 for output

    int deviceControlCount; // -1 means "not initialized"
    AudioControl *deviceControls;

    PortControl *portControls;  // list of port controls

    bool listenersInstalled;
};


void RemoveChangeListeners(PortMixer *mixer);   // forward declaration

OSStatus ChangeListenerProc(AudioObjectID inObjectID, UInt32 inNumberAddresses,
        const AudioObjectPropertyAddress inAddresses[], void *inClientData)
{
    PortMixer *mixer = (PortMixer *)inClientData;

    OSStatus err = noErr;
    UInt32 size;

    bool invalid = false;

    for (UInt32 i = 0; i < inNumberAddresses; i++) {
        switch (inAddresses[i].mSelector) {
        case kAudioHardwarePropertyDevices:
            // check if the device has been removed
            err = GetAudioObjectPropertySize(kAudioObjectSystemObject, kAudioObjectPropertyScopeGlobal,
                kAudioHardwarePropertyDevices, &size);
            if (err == noErr) {
                int count = size/sizeof(AudioDeviceID);
                AudioDeviceID devices[count];
                err = GetAudioObjectProperty(kAudioObjectSystemObject, kAudioObjectPropertyScopeGlobal,
                    kAudioHardwarePropertyDevices, count*sizeof(AudioDeviceID), devices, 1);
                if (err == noErr) {
                    bool found = false;
                    for (int j = 0; j < count; j++) {
                        if (devices[j] == mixer->deviceID) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        invalid = true;
                    }
                }
            }
            break;
        case kAudioObjectPropertyOwnedObjects:
        case kAudioDevicePropertyDeviceHasChanged:
            // ensure all _used_ AudioControl are valid
            err = GetAudioObjectPropertySize(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
                kAudioObjectPropertyOwnedObjects, &size);
            if (err == noErr) {
                int count = size / sizeof(AudioObjectID);
                AudioObjectID controlIDs[count];
                err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
                    kAudioObjectPropertyOwnedObjects, count * sizeof(AudioObjectID), &controlIDs, 1);
                if (err == noErr) {
                    for (PortControl *ctrl = mixer->portControls; ctrl != NULL; ctrl = ctrl->next) {
                        for (int i = 0; i < ctrl->controlCount; i++) {
                            bool found = false;
                            for (int j = 0; j < count; j++) {
                                if (ctrl->audioControls[i]->controlID == controlIDs[j]) {
                                    found = true;
                                    break;
                                }
                            }
                            if (!found) {
                                invalid = true;
                                break;  // goto next control
                            }
                        }
                    }
                }
            }
        }
    }

    if (invalid) {
        TRACE1("PortMixer (deviceID=0x%x) becomes invalid", (int)mixer->deviceID);
        // invalidate all controls
        for (int i=0; i<mixer->deviceControlCount; i++) {
            mixer->deviceControls[i].controlID = 0;
        }
        RemoveChangeListeners(mixer);
    }


    return noErr;
}

const AudioObjectPropertyAddress changeListenersAddresses[] = {
    {kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster},
    {kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster},
    {kAudioDevicePropertyDeviceHasChanged, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}
};

void AddChangeListeners(PortMixer *mixer) {
    if (!mixer->listenersInstalled) {
        for (size_t i=0; i<sizeof(changeListenersAddresses)/sizeof(changeListenersAddresses[0]); i++) {
            AudioObjectAddPropertyListener(mixer->deviceID, &changeListenersAddresses[i], ChangeListenerProc, mixer);
        }
        mixer->listenersInstalled = true;
    }
}

void RemoveChangeListeners(PortMixer *mixer) {
    if (mixer->listenersInstalled) {
        for (size_t i=0; i<sizeof(changeListenersAddresses)/sizeof(changeListenersAddresses[0]); i++) {
            AudioObjectRemovePropertyListener(mixer->deviceID, &changeListenersAddresses[i], ChangeListenerProc, mixer);
        }
        mixer->listenersInstalled = false;
    }
}


////////////////////////////////////////////////////////////////////////////////
// functions from Port.h

INT32 PORT_GetPortMixerCount() {
    deviceCache.Refresh();
    int count = deviceCache.GetCount();
    TRACE1("<vendor, mixerDescription->description, mixerDescription->version);
    return result ? TRUE : FALSE;
}

void* PORT_Open(INT32 mixerIndex) {
    TRACE1("\n>>PORT_Open (mixerIndex=%d)\n", (int)mixerIndex);
    PortMixer *mixer = (PortMixer *)calloc(1, sizeof(PortMixer));

    mixer->deviceID = deviceCache.GetDeviceID(mixerIndex);
    if (mixer->deviceID != 0) {
        mixer->deviceControlCount = -1; // not initialized
        // fill mixer->ports (and mixer->portCount)
        for (int i=0; i<2; i++) {
            OSStatus err;
            UInt32 size = 0;
            AudioObjectPropertyScope scope =
                (i == 0) ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;

            err = GetAudioObjectPropertySize(mixer->deviceID, scope, kAudioDevicePropertyStreams, &size);
            if (err || size == 0) {
                continue;
            }
            if (size / sizeof(AudioStreamID) == 1) {
                // the device has the only AudioStream
                AudioStreamID streamID;
                err = GetAudioObjectProperty(mixer->deviceID, scope, kAudioDevicePropertyStreams,
                    sizeof(streamID), &streamID, 1);
                if (err) {
                    continue;
                }
                mixer->ports[mixer->portCount].streamID = streamID;
            } else {
                // the device has several AudioStreams in the scope
                mixer->ports[mixer->portCount].streamID = 0;
            }
            mixer->ports[mixer->portCount].scope = scope;
            mixer->portCount++;
        }
    }

    TRACE2("<PORT_Close %p\n", id);
    PortMixer *mixer = (PortMixer *)id;

    if (mixer) {
        RemoveChangeListeners(mixer);
        while (mixer->portControls != NULL) {
            PortControl *control2delete = mixer->portControls;
            mixer->portControls = control2delete->next;

            if (control2delete->audioControls != NULL) {
                free(control2delete->audioControls);
            }
            free(control2delete);
        }
        if (mixer->deviceControls) {
            free(mixer->deviceControls);
        }
        free(mixer);
    }
    TRACE1("<portCount) {
        ERROR1("PORT_GetPortType: line (portIndex = %d) not found\n", portIndex);
        return 0;
    }

    AudioObjectPropertyScope scope = mixer->ports[portIndex].scope;
    AudioStreamID streamID = mixer->ports[portIndex].streamID;
    if (streamID != 0) {
        UInt32 terminalType;

        OSStatus err = GetAudioObjectProperty(streamID, kAudioObjectPropertyScopeGlobal,
            kAudioStreamPropertyTerminalType, sizeof(terminalType), &terminalType, 1);
        if (err) {
            OS_ERROR1(err, "PORT_GetPortType(kAudioStreamPropertyTerminalType), portIndex=%d", portIndex);
            return 0;
        }

        // Note that kAudioStreamPropertyTerminalType actually returns values from
        // IOAudioTypes.h, not the defined kAudioStreamTerminalType*.
        TRACE4("PORT_GetPortType (portIndex=%d), scope=%s, termType=0x%04x (%s)\n",
            (int)portIndex, FourCC2Str(scope), (int)terminalType, FourCC2Str(terminalType));
        switch (terminalType) {
        case INPUT_MICROPHONE:
            ret = PORT_SRC_MICROPHONE;
            break;

        case OUTPUT_SPEAKER:
            ret = PORT_DST_SPEAKER;
            break;
        case OUTPUT_HEADPHONES:
            ret = PORT_DST_HEADPHONE;
            break;

        case EXTERNAL_LINE_CONNECTOR:
            ret = scope == kAudioDevicePropertyScopeInput ? PORT_SRC_LINE_IN : PORT_DST_LINE_OUT;
            break;

        default:
            TRACE1("  unknown output terminal type %#x\n", terminalType);
        }
    } else {
        TRACE0("  PORT_GetPortType: multiple streams\n");
    }

    if (ret == 0) {
        // if the type not detected, return "common type"
        ret = scope == kAudioDevicePropertyScopeInput ? PORT_SRC_UNKNOWN : PORT_DST_UNKNOWN;
    }

    TRACE2("<portCount) {
        ERROR1("PORT_GetPortName: line (portIndex = %d) not found\n", portIndex);
        return FALSE;
    }

    AudioStreamID streamID = mixer->ports[portIndex].streamID;
    CFStringRef cfname = NULL;
    if (streamID != 0) {
        OSStatus err = GetAudioObjectProperty(streamID, kAudioObjectPropertyScopeGlobal,
            kAudioObjectPropertyName, sizeof(cfname), &cfname, 1);
        if (err && err != kAudioHardwareUnknownPropertyError) {
            OS_ERROR1(err, "PORT_GetPortName(stream name), portIndex=%d", portIndex);
            return FALSE;
        }
    }

    if (!cfname) {
        // use the device's name if the stream has no name (usually the case)
        // or the device has several AudioStreams
        OSStatus err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
            kAudioObjectPropertyName, sizeof(cfname), &cfname, 1);
        if (err) {
            OS_ERROR1(err, "PORT_GetPortName(device name), portIndex=%d", portIndex);
            return FALSE;
        }
    }

    if (cfname) {
        CFStringGetCString(cfname, name, len, kCFStringEncodingUTF8);
        CFRelease(cfname);
    }

    TRACE2("<portControls;
    mixer->portControls = control;

    return jControl;
}

void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
    PortMixer *mixer = (PortMixer *)id;

    TRACE1(">>PORT_GetControls (portIndex = %d)\n", portIndex);

    if (portIndex < 0 || portIndex >= mixer->portCount) {
        ERROR1("<deviceControlCount, sizeof(AudioControl));

                for (int i = 0; i < mixer->deviceControlCount; i++) {
                    AudioControl *control = &mixer->deviceControls[i];

                    control->controlID = controlIDs[i];

                    OSStatus err1 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioObjectPropertyClass, sizeof(control->classID), &control->classID, 1);
                    OSStatus err2 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioControlPropertyScope, sizeof(control->scope), &control->scope, 1);
                    OSStatus err3 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
                        kAudioControlPropertyElement, sizeof(control->channel), &control->channel, 1);
                    if (err1 || err2 || err3) { // not a control or other error
                        control->classID = 0;
                        continue;
                    }

                    TRACE4("- control 0x%x, class='%s', scope='%s', channel=%d\n",
                        control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
                }
            }
        }
    }

    if (mixer->deviceControlCount <= 0) {
        TRACE1("<scope == kAudioDevicePropertyScopeOutput ? 1 : 0);

    // collect volume and mute controls
    AudioControl* volumeControls[totalChannels+1];  // 0 - for master channel
    memset(&volumeControls, 0, sizeof(AudioControl *) * (totalChannels+1));
    AudioControl* muteControls[totalChannels+1];  // 0 - for master channel
    memset(&muteControls, 0, sizeof(AudioControl *) * (totalChannels+1));

    for (int i=0; i<mixer->deviceControlCount; i++) {
        AudioControl *control = &mixer->deviceControls[i];
        if (control->classID == 0 || control->scope != port->scope || control->channel > (unsigned)totalChannels) {
            continue;
        }
        if (control->classID == kAudioVolumeControlClassID) {
            if (volumeControls[control->channel] == NULL) {
                volumeControls[control->channel] = control;
            } else {
                ERROR4("WARNING: duplicate VOLUME control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
        } else if (control->classID == kAudioMuteControlClassID) {
            if (muteControls[control->channel] == NULL) {
                muteControls[control->channel] = control;
            } else {
                ERROR4("WARNING: duplicate MUTE control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
        } else {
#ifdef USE_ERROR
            if (control->classID != 0) {
                ERROR4("WARNING: unhandled control 0x%x, class='%s', scope='%s', channel=%d\n",
                    control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
            }
#endif
        }
    }

    ////////////////////////////////////////////////////////
    // create java control hierarchy

    void *masterVolume = NULL, *masterMute = NULL, *masterBalance = NULL;
    // volumeControls[0] and muteControls[0] - master volume/mute
    // volumeControls[n] and muteControls[n] (n=1..totalChannels) - corresponding channel controls
    if (volumeControls[0] != NULL) {    // "master volume" AudioControl
        masterVolume = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, 0, 1);
    } else {
        if (ValidControlCount(volumeControls, 1, totalChannels) == totalChannels) {
            // every channel has volume control => create virtual master volume
            masterVolume = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (master volume): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(volumeControls, 1, totalChannels));
        }
    }

    if (muteControls[0] != NULL) {      // "master mute"
        masterMute = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, 0, 1);
    } else {
        if (ValidControlCount(muteControls, 1, totalChannels) == totalChannels) {
            // every channel has mute control => create virtual master mute control
            masterMute = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (master mute): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(muteControls, 1, totalChannels));
        }
    }

    // virtual balance
    if (totalChannels == 2) {
        if (ValidControlCount(volumeControls, 1, totalChannels) == totalChannels) {
            masterBalance = CreatePortControl(mixer, creator, PortControl::Balance, volumeControls, 1, totalChannels);
        } else {
            TRACE2("  PORT_GetControls (naster balance): totalChannels = %d, valid volume controls = %d\n",
                totalChannels, ValidControlCount(volumeControls, 1, totalChannels));
        }
    }

    // add "master" controls
    if (masterVolume != NULL) {
        creator->addControl(creator, masterVolume);
    }
    if (masterBalance != NULL) {
        creator->addControl(creator, masterBalance);
    }
    if (masterMute != NULL) {
        creator->addControl(creator, masterMute);
    }

    // don't add per-channel controls for mono & stereo - they are handled by "master" controls
    // TODO: this should be reviewed to handle controls other than mute & volume
    if (totalChannels > 2) {
        // add separate compound control for each channel (containing volume and mute)
        // (ensure that we have controls)
        if (ValidControlCount(volumeControls, 1, totalChannels) > 0 || ValidControlCount(muteControls, 1, totalChannels) > 0) {
            for (int ch=1; ch<=totalChannels; ch++) {
                // get the channel name
                char *channelName;
                CFStringRef cfname = NULL;
                const AudioObjectPropertyAddress address = {kAudioObjectPropertyElementName, port->scope, ch};
                UInt32 size = sizeof(cfname);
                OSStatus err = AudioObjectGetPropertyData(mixer->deviceID, &address, 0, NULL, &size, &cfname);
                if (err == noErr) {
                    CFIndex length = CFStringGetLength(cfname) + 1;
                    channelName = (char *)malloc(length);
                    CFStringGetCString(cfname, channelName, length, kCFStringEncodingUTF8);
                    CFRelease(cfname);
                } else {
                    channelName = (char *)malloc(16);
                    sprintf(channelName, "Ch %d", ch);
                }

                void* jControls[2];
                int controlCount = 0;
                if (volumeControls[ch] != NULL) {
                    jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, ch, 1);
                }
                if (muteControls[ch] != NULL) {
                    jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, ch, 1);
                }
                // TODO: add any extra controls for "other" controls for the channel

                void *compoundControl = creator->newCompoundControl(creator, channelName, jControls, controlCount);
                creator->addControl(creator, compoundControl);

                free(channelName);
            }
        }
    }

    AddChangeListeners(mixer);

    TRACE1("<controlID == 0)
            return false;
    }
    return true;
}


#define DEFAULT_MUTE_VALUE 0

INT32 PORT_GetIntValue(void* controlIDV) {
    PortControl *control = (PortControl *)controlIDV;
    INT32 result = 0;

    switch (control->type) {
    case PortControl::Mute:
        if (!TestPortControlValidity(control)) {
            return DEFAULT_MUTE_VALUE;
        }
        result = 1; // default is "muted", if some channel in unmuted, then "virtual mute" is also unmuted
        for (int i=0; i<control->controlCount; i++) {
            UInt32 value;
            OSStatus err = GetAudioObjectProperty(control->audioControls[i]->controlID,
                kAudioObjectPropertyScopeGlobal, kAudioBooleanControlPropertyValue, sizeof(value), &value, 1);
            if (err) {
                OS_ERROR3(err, "PORT_GetIntValue, control %d of %d (coltrolID = 0x%x)",
                    i, control->controlCount, control->audioControls[i]->controlID);
                return DEFAULT_MUTE_VALUE;
            }
            if (value == 0) {
                result = 0;
            }
        }
        break;
    default:
        ERROR1("PORT_GetIntValue requested for non-Int control (control-type == %d)\n", control->type);
        return 0;
    }

    //TRACE1("<controlID,
                kAudioObjectPropertyScopeGlobal, kAudioBooleanControlPropertyValue, sizeof(value), &value);
            if (err) {
                OS_ERROR3(err, "PORT_SetIntValue, control %d of %d (coltrolID = 0x%x)",
                    i, control->controlCount, control->audioControls[i]->controlID);
                // don't return - try to set the rest of AudioControls
            }
        }
        break;
    default:
        ERROR1("PORT_SetIntValue requested for non-Int control (control-type == %d)\n", control->type);
        return;
    }
}


// gets volume value for all AudioControls of the PortControl
static bool GetPortControlVolumes(PortControl *control, Float32 *volumes, Float32 *maxVolume) {
    *maxVolume = 0.0f;
    for (int i=0; i<control->controlCount; i++) {
        OSStatus err = GetAudioObjectProperty(control->audioControls[i]->controlID,
            kAudioObjectPropertyScopeGlobal, kAudioLevelControlPropertyScalarValue,
            sizeof(volumes[i]), &volumes[i], 1);
        if (err) {
            OS_ERROR3(err, "GetPortControlVolumes, control %d of %d (controlID = 0x%x)",
                i, control->controlCount, control->audioControls[i]->controlID);
            return false;
        }
        if (volumes[i] > *maxVolume) {
            *maxVolume = volumes[i];
        }
    }
    return true;
}

// sets volume value for all AudioControls of the PortControl
static void SetPortControlVolumes(PortControl *control, Float32 *volumes) {
    for (int i=0; i<control->controlCount; i++) {
        OSStatus err = SetAudioObjectProperty(control->audioControls[i]->controlID,
            kAudioObjectPropertyScopeGlobal, kAudioLevelControlPropertyScalarValue,
            sizeof(volumes[i]), &volumes[i]);
        if (err) {
            OS_ERROR3(err, "SetPortControlVolumes , control %d of %d (coltrolID = 0x%x)",
                i, control->controlCount, control->audioControls[i]->controlID);
            // don't return - try to set the rest of AudioControls
        }
    }
}

#define DEFAULT_VOLUME_VALUE    1.0f
#define DEFAULT_BALANCE_VALUE   0.0f

float PORT_GetFloatValue(void* controlIDV) {
    PortControl *control = (PortControl *)controlIDV;
    Float32 result = 0;

    Float32 subVolumes[control->controlCount];
    Float32 maxVolume;

    switch (control->type) {
    case PortControl::Volume:
        if (!TestPortControlValidity(control)) {
            return DEFAULT_VOLUME_VALUE;
        }

        if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) {
            return DEFAULT_VOLUME_VALUE;
        }
        result = maxVolume;
        break;
    case PortControl::Balance:
        if (!TestPortControlValidity(control)) {
            return DEFAULT_BALANCE_VALUE;
        }

        // balance control always has 2 volume controls
        if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) {
            return DEFAULT_VOLUME_VALUE;
        }
        // calculate balance value
        if (subVolumes[0] > subVolumes[1]) {
            result = -1.0f + (subVolumes[1] / subVolumes[0]);
        } else if (subVolumes[1] > subVolumes[0]) {
            result = 1.0f - (subVolumes[0] / subVolumes[1]);
        } else {
            result = 0.0f;
        }
        break;
    default:
        ERROR1("GetFloatValue requested for non-Float control (control-type == %d)\n", control->type);
        return 0;
    }

    TRACE1("<

Other Java examples (source code examples)

Here is a short list of links related to this Java PLATFORM_API_MacOSX_Ports.cpp source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.