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

Java example source code file (PortMixer.java)

This example Java source code file (PortMixer.java) 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

bct, boolctrl, cct, control, fct, floatctrl, lineunavailableexception, portinfo, portmixer, portmixerport, src_line_in, src_mask, string, util, vector

The PortMixer.java Java example source code

/*
 * Copyright (c) 2002, 2013, 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.
 */

package com.sun.media.sound;

import java.util.Vector;

import javax.sound.sampled.Control;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Port;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.CompoundControl;
import javax.sound.sampled.FloatControl;


/**
 * A Mixer which only provides Ports.
 *
 * @author Florian Bomers
 */
final class PortMixer extends AbstractMixer {

    // CONSTANTS
    private static final int SRC_UNKNOWN      = 0x01;
    private static final int SRC_MICROPHONE   = 0x02;
    private static final int SRC_LINE_IN      = 0x03;
    private static final int SRC_COMPACT_DISC = 0x04;
    private static final int SRC_MASK         = 0xFF;

    private static final int DST_UNKNOWN      = 0x0100;
    private static final int DST_SPEAKER      = 0x0200;
    private static final int DST_HEADPHONE    = 0x0300;
    private static final int DST_LINE_OUT     = 0x0400;
    private static final int DST_MASK         = 0xFF00;

    // INSTANCE VARIABLES
    private Port.Info[] portInfos;
    // cache of instantiated ports
    private PortMixerPort[] ports;

    // instance ID of the native implementation
    private long id = 0;

    // CONSTRUCTOR
    PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) {
        // pass in Line.Info, mixer, controls
        super(portMixerInfo,              // Mixer.Info
              null,                       // Control[]
              null,                       // Line.Info[] sourceLineInfo
              null);                      // Line.Info[] targetLineInfo

        if (Printer.trace) Printer.trace(">> PortMixer: constructor");

        int count = 0;
        int srcLineCount = 0;
        int dstLineCount = 0;

        try {
            try {
                id = nOpen(getMixerIndex());
                if (id != 0) {
                    count = nGetPortCount(id);
                    if (count < 0) {
                        if (Printer.trace) Printer.trace("nGetPortCount() returned error code: " + count);
                        count = 0;
                    }
                }
            } catch (Exception e) {}

            portInfos = new Port.Info[count];

            for (int i = 0; i < count; i++) {
                int type = nGetPortType(id, i);
                srcLineCount += ((type & SRC_MASK) != 0)?1:0;
                dstLineCount += ((type & DST_MASK) != 0)?1:0;
                portInfos[i] = getPortInfo(i, type);
            }
        } finally {
            if (id != 0) {
                nClose(id);
            }
            id = 0;
        }

        // fill sourceLineInfo and targetLineInfos with copies of the ones in portInfos
        sourceLineInfo = new Port.Info[srcLineCount];
        targetLineInfo = new Port.Info[dstLineCount];

        srcLineCount = 0; dstLineCount = 0;
        for (int i = 0; i < count; i++) {
            if (portInfos[i].isSource()) {
                sourceLineInfo[srcLineCount++] = portInfos[i];
            } else {
                targetLineInfo[dstLineCount++] = portInfos[i];
            }
        }

        if (Printer.trace) Printer.trace("<< PortMixer: constructor completed");
    }


    // ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS

    public Line getLine(Line.Info info) throws LineUnavailableException {
        Line.Info fullInfo = getLineInfo(info);

        if ((fullInfo != null) && (fullInfo instanceof Port.Info)) {
            for (int i = 0; i < portInfos.length; i++) {
                if (fullInfo.equals(portInfos[i])) {
                    return getPort(i);
                }
            }
        }
        throw new IllegalArgumentException("Line unsupported: " + info);
    }


    public int getMaxLines(Line.Info info) {
        Line.Info fullInfo = getLineInfo(info);

        // if it's not supported at all, return 0.
        if (fullInfo == null) {
            return 0;
        }

        if (fullInfo instanceof Port.Info) {
            //return AudioSystem.NOT_SPECIFIED; // if several instances of PortMixerPort
            return 1;
        }
        return 0;
    }


    protected void implOpen() throws LineUnavailableException {
        if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")");

        // open the mixer device
        id = nOpen(getMixerIndex());

        if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded.");
    }

    protected void implClose() {
        if (Printer.trace) Printer.trace(">> PortMixer: implClose");

        // close the mixer device
        long thisID = id;
        id = 0;
        nClose(thisID);
        if (ports != null) {
            for (int i = 0; i < ports.length; i++) {
                if (ports[i] != null) {
                    ports[i].disposeControls();
                }
            }
        }

        if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded");
    }

    protected void implStart() {}
    protected void implStop() {}

    // IMPLEMENTATION HELPERS

    private Port.Info getPortInfo(int portIndex, int type) {
        switch (type) {
        case SRC_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), true);
        case SRC_MICROPHONE:   return Port.Info.MICROPHONE;
        case SRC_LINE_IN:      return Port.Info.LINE_IN;
        case SRC_COMPACT_DISC: return Port.Info.COMPACT_DISC;

        case DST_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), false);
        case DST_SPEAKER:      return Port.Info.SPEAKER;
        case DST_HEADPHONE:    return Port.Info.HEADPHONE;
        case DST_LINE_OUT:     return Port.Info.LINE_OUT;
        }
        // should never happen...
        if (Printer.debug) Printer.debug("unknown port type: "+type);
        return null;
    }

    int getMixerIndex() {
        return ((PortMixerProvider.PortMixerInfo) getMixerInfo()).getIndex();
    }

    Port getPort(int index) {
        if (ports == null) {
            ports = new PortMixerPort[portInfos.length];
        }
        if (ports[index] == null) {
            ports[index] = new PortMixerPort((Port.Info)portInfos[index], this, index);
            return ports[index];
        }
        // $$fb TODO: return (Port) (ports[index].clone());
        return ports[index];
    }

    long getID() {
        return id;
    }

    // INNER CLASSES

    /**
     * Private inner class representing a Port for the PortMixer.
     */
    private static final class PortMixerPort extends AbstractLine
            implements Port {

        private final int portIndex;
        private long id;

        // CONSTRUCTOR
        private PortMixerPort(Port.Info info,
                              PortMixer mixer,
                              int portIndex) {
            super(info, mixer, null);
            if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info);
            this.portIndex = portIndex;
        }


        // ABSTRACT METHOD IMPLEMENTATIONS

        // ABSTRACT LINE

        void implOpen() throws LineUnavailableException {
            if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen().");
            long newID = ((PortMixer) mixer).getID();
            if ((id == 0) || (newID != id) || (controls.length == 0)) {
                id = newID;
                Vector vector = new Vector();
                synchronized (vector) {
                    nGetControls(id, portIndex, vector);
                    controls = new Control[vector.size()];
                    for (int i = 0; i < controls.length; i++) {
                        controls[i] = (Control) vector.elementAt(i);
                    }
                }
            } else {
                enableControls(controls, true);
            }
            if (Printer.trace) Printer.trace("<< PortMixerPort: implOpen() succeeded");
        }

        private void enableControls(Control[] controls, boolean enable) {
            for (int i = 0; i < controls.length; i++) {
                if (controls[i] instanceof BoolCtrl) {
                    ((BoolCtrl) controls[i]).closed = !enable;
                }
                else if (controls[i] instanceof FloatCtrl) {
                    ((FloatCtrl) controls[i]).closed = !enable;
                }
                else if (controls[i] instanceof CompoundControl) {
                    enableControls(((CompoundControl) controls[i]).getMemberControls(), enable);
                }
            }
        }

        private void disposeControls() {
            enableControls(controls, false);
            controls = new Control[0];
        }


        void implClose() {
            if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()");
            // get rid of controls
            enableControls(controls, false);
            if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded");
        }

        // METHOD OVERRIDES

        // this is very similar to open(AudioFormat, int) in AbstractDataLine...
        public void open() throws LineUnavailableException {
            synchronized (mixer) {
                // if the line is not currently open, try to open it with this format and buffer size
                if (!isOpen()) {
                    if (Printer.trace) Printer.trace("> PortMixerPort: open");
                    // reserve mixer resources for this line
                    mixer.open(this);
                    try {
                        // open the line.  may throw LineUnavailableException.
                        implOpen();

                        // if we succeeded, set the open state to true and send events
                        setOpen(true);
                    } catch (LineUnavailableException e) {
                        // release mixer resources for this line and then throw the exception
                        mixer.close(this);
                        throw e;
                    }
                    if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded");
                }
            }
        }

        // this is very similar to close() in AbstractDataLine...
        public void close() {
            synchronized (mixer) {
                if (isOpen()) {
                    if (Printer.trace) Printer.trace("> PortMixerPort.close()");

                    // set the open state to false and send events
                    setOpen(false);

                    // close resources for this line
                    implClose();

                    // release mixer resources for this line
                    mixer.close(this);
                    if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded");
                }
            }
        }

    } // class PortMixerPort

    /**
     * Private inner class representing a BooleanControl for PortMixerPort
     */
    private static final class BoolCtrl extends BooleanControl {
        // the handle to the native control function
        private final long controlID;
        private boolean closed = false;

        private static BooleanControl.Type createType(String name) {
            if (name.equals("Mute")) {
                return BooleanControl.Type.MUTE;
            }
            else if (name.equals("Select")) {
                // $$fb add as new static type?
                //return BooleanControl.Type.SELECT;
            }
            return new BCT(name);
        }


        private BoolCtrl(long controlID, String name) {
            this(controlID, createType(name));
        }

        private BoolCtrl(long controlID, BooleanControl.Type typ) {
            super(typ, false);
            this.controlID = controlID;
        }

        public void setValue(boolean value) {
            if (!closed) {
                nControlSetIntValue(controlID, value?1:0);
            }
        }

        public boolean getValue() {
            if (!closed) {
                // never use any cached values
                return (nControlGetIntValue(controlID)!=0)?true:false;
            }
            // ??
            return false;
        }

        /**
         * inner class for custom types
         */
        private static final class BCT extends BooleanControl.Type {
            private BCT(String name) {
                super(name);
            }
        }
    }

    /**
     * Private inner class representing a CompoundControl for PortMixerPort
     */
    private static final class CompCtrl extends CompoundControl {
        private CompCtrl(String name, Control[] controls) {
            super(new CCT(name), controls);
        }

        /**
         * inner class for custom compound control types
         */
        private static final class CCT extends CompoundControl.Type {
            private CCT(String name) {
                super(name);
            }
        }
    }

    /**
     * Private inner class representing a BooleanControl for PortMixerPort
     */
    private static final class FloatCtrl extends FloatControl {
        // the handle to the native control function
        private final long controlID;
        private boolean closed = false;

        // predefined float control types. See also Ports.h
        private final static FloatControl.Type[] FLOAT_CONTROL_TYPES = {
            null,
            FloatControl.Type.BALANCE,
            FloatControl.Type.MASTER_GAIN,
            FloatControl.Type.PAN,
            FloatControl.Type.VOLUME
        };

        private FloatCtrl(long controlID, String name,
                          float min, float max, float precision, String units) {
            this(controlID, new FCT(name), min, max, precision, units);
        }

        private FloatCtrl(long controlID, int type,
                          float min, float max, float precision, String units) {
            this(controlID, FLOAT_CONTROL_TYPES[type], min, max, precision, units);
        }

        private FloatCtrl(long controlID, FloatControl.Type typ,
                         float min, float max, float precision, String units) {
            super(typ, min, max, precision, 1000, min, units);
            this.controlID = controlID;
        }

        public void setValue(float value) {
            if (!closed) {
                nControlSetFloatValue(controlID, value);
            }
        }

        public float getValue() {
            if (!closed) {
                // never use any cached values
                return nControlGetFloatValue(controlID);
            }
            // ??
            return getMinimum();
        }

        /**
         * inner class for custom types
         */
        private static final class FCT extends FloatControl.Type {
            private FCT(String name) {
                super(name);
            }
        }
    }

    /**
     * Private inner class representing a port info
     */
    private static final class PortInfo extends Port.Info {
        private PortInfo(String name, boolean isSource) {
            super(Port.class, name, isSource);
        }
    }

    // open the mixer with the given index. Returns a handle ID
    private static native long nOpen(int mixerIndex) throws LineUnavailableException;
    private static native void nClose(long id);

    // gets the number of ports for this mixer
    private static native int nGetPortCount(long id);

    // gets the type of the port with this index
    private static native int nGetPortType(long id, int portIndex);

    // gets the name of the port with this index
    private static native String nGetPortName(long id, int portIndex);

    // fills the vector with the controls for this port
    private static native void nGetControls(long id, int portIndex, Vector vector);

    // getters/setters for controls
    private static native void nControlSetIntValue(long controlID, int value);
    private static native int nControlGetIntValue(long controlID);
    private static native void nControlSetFloatValue(long controlID, float value);
    private static native float nControlGetFloatValue(long controlID);

}

Other Java examples (source code examples)

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

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

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 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.