503 lines · 16.8 KB · Java
RawDownload
/* * Copyright (c) 2002, 2007, 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 */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 class PortMixerPort extends AbstractLine implements Port {        private 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 class BoolCtrl extends BooleanControl {        // the handle to the native control function        private 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 class BCT extends BooleanControl.Type {            private BCT(String name) {                super(name);            }        }    }     /**     * Private inner class representing a CompoundControl for PortMixerPort     */    private static class CompCtrl extends CompoundControl {        private CompCtrl(String name, Control[] controls) {            super(new CCT(name), controls);        }         /**         * inner class for custom compound control types         */        private static class CCT extends CompoundControl.Type {            private CCT(String name) {                super(name);            }        }    }     /**     * Private inner class representing a BooleanControl for PortMixerPort     */    private static class FloatCtrl extends FloatControl {        // the handle to the native control function        private 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 class FCT extends FloatControl.Type {            private FCT(String name) {                super(name);            }        }    }     /**     * Private inner class representing a port info     */    private static 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);

Lines 1–500 of 503.