| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
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;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class PortMixer extends AbstractMixer { | 
 | 
 | 
 | 
      | 
 | 
    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;  | 
 | 
 | 
 | 
      | 
 | 
    private Port.Info[] portInfos;  | 
 | 
      | 
 | 
    private PortMixerPort[] ports;  | 
 | 
 | 
 | 
      | 
 | 
    private long id = 0;  | 
 | 
 | 
 | 
      | 
 | 
    PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) { | 
 | 
          | 
 | 
        super(portMixerInfo,                | 
 | 
              null,                         | 
 | 
              null,                         | 
 | 
              null);                        | 
 | 
 | 
 | 
        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;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        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 (fullInfo == null) { | 
 | 
            return 0;  | 
 | 
        }  | 
 | 
 | 
 | 
        if (fullInfo instanceof Port.Info) { | 
 | 
              | 
 | 
            return 1;  | 
 | 
        }  | 
 | 
        return 0;  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    protected void implOpen() throws LineUnavailableException { | 
 | 
        if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")"); | 
 | 
 | 
 | 
          | 
 | 
        id = nOpen(getMixerIndex());  | 
 | 
 | 
 | 
        if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded."); | 
 | 
    }  | 
 | 
 | 
 | 
    protected void implClose() { | 
 | 
        if (Printer.trace) Printer.trace(">> PortMixer: implClose"); | 
 | 
 | 
 | 
          | 
 | 
        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;  | 
 | 
        }  | 
 | 
          | 
 | 
        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];  | 
 | 
        }  | 
 | 
          | 
 | 
        return ports[index];  | 
 | 
    }  | 
 | 
 | 
 | 
    long getID() { | 
 | 
        return id;  | 
 | 
    }  | 
 | 
 | 
 | 
    // INNER CLASSES  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class PortMixerPort extends AbstractLine  | 
 | 
            implements Port { | 
 | 
 | 
 | 
        private final int portIndex;  | 
 | 
        private long id;  | 
 | 
 | 
 | 
          | 
 | 
        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()"); | 
 | 
              | 
 | 
            enableControls(controls, false);  | 
 | 
            if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded"); | 
 | 
        }  | 
 | 
 | 
 | 
        // METHOD OVERRIDES  | 
 | 
 | 
 | 
          | 
 | 
        public void open() throws LineUnavailableException { | 
 | 
            synchronized (mixer) { | 
 | 
                  | 
 | 
                if (!isOpen()) { | 
 | 
                    if (Printer.trace) Printer.trace("> PortMixerPort: open"); | 
 | 
                      | 
 | 
                    mixer.open(this);  | 
 | 
                    try { | 
 | 
                          | 
 | 
                        implOpen();  | 
 | 
 | 
 | 
                          | 
 | 
                        setOpen(true);  | 
 | 
                    } catch (LineUnavailableException e) { | 
 | 
                          | 
 | 
                        mixer.close(this);  | 
 | 
                        throw e;  | 
 | 
                    }  | 
 | 
                    if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded"); | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        public void close() { | 
 | 
            synchronized (mixer) { | 
 | 
                if (isOpen()) { | 
 | 
                    if (Printer.trace) Printer.trace("> PortMixerPort.close()"); | 
 | 
 | 
 | 
                      | 
 | 
                    setOpen(false);  | 
 | 
 | 
 | 
                      | 
 | 
                    implClose();  | 
 | 
 | 
 | 
                      | 
 | 
                    mixer.close(this);  | 
 | 
                    if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded"); | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
    } // class PortMixerPort  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class BoolCtrl extends BooleanControl { | 
 | 
          | 
 | 
        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) { | 
 | 
                  | 
 | 
                return (nControlGetIntValue(controlID)!=0)?true:false;  | 
 | 
            }  | 
 | 
              | 
 | 
            return false;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        private static final class BCT extends BooleanControl.Type { | 
 | 
            private BCT(String name) { | 
 | 
                super(name);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class CompCtrl extends CompoundControl { | 
 | 
        private CompCtrl(String name, Control[] controls) { | 
 | 
            super(new CCT(name), controls);  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        private static final class CCT extends CompoundControl.Type { | 
 | 
            private CCT(String name) { | 
 | 
                super(name);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class FloatCtrl extends FloatControl { | 
 | 
          | 
 | 
        private final long controlID;  | 
 | 
        private boolean closed = false;  | 
 | 
 | 
 | 
          | 
 | 
        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) { | 
 | 
                  | 
 | 
                return nControlGetFloatValue(controlID);  | 
 | 
            }  | 
 | 
              | 
 | 
            return getMinimum();  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        private static final class FCT extends FloatControl.Type { | 
 | 
            private FCT(String name) { | 
 | 
                super(name);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class PortInfo extends Port.Info { | 
 | 
        private PortInfo(String name, boolean isSource) { | 
 | 
            super(Port.class, name, isSource);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private static native long nOpen(int mixerIndex) throws LineUnavailableException;  | 
 | 
    private static native void nClose(long id);  | 
 | 
 | 
 | 
      | 
 | 
    private static native int nGetPortCount(long id);  | 
 | 
 | 
 | 
      | 
 | 
    private static native int nGetPortType(long id, int portIndex);  | 
 | 
 | 
 | 
      | 
 | 
    private static native String nGetPortName(long id, int portIndex);  | 
 | 
 | 
 | 
      | 
 | 
    private static native void nGetControls(long id, int portIndex, Vector vector);  | 
 | 
 | 
 | 
      | 
 | 
    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);  | 
 | 
 | 
 | 
}  |