Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.media.sound;
   27   
   28   import java.util.Vector;
   29   
   30   import javax.sound.sampled.Control;
   31   import javax.sound.sampled.Line;
   32   import javax.sound.sampled.LineUnavailableException;
   33   import javax.sound.sampled.Port;
   34   import javax.sound.sampled.BooleanControl;
   35   import javax.sound.sampled.CompoundControl;
   36   import javax.sound.sampled.FloatControl;
   37   
   38   
   39   /**
   40    * A Mixer which only provides Ports.
   41    *
   42    * @author Florian Bomers
   43    */
   44   class PortMixer extends AbstractMixer {
   45   
   46       // CONSTANTS
   47       private static final int SRC_UNKNOWN      = 0x01;
   48       private static final int SRC_MICROPHONE   = 0x02;
   49       private static final int SRC_LINE_IN      = 0x03;
   50       private static final int SRC_COMPACT_DISC = 0x04;
   51       private static final int SRC_MASK         = 0xFF;
   52   
   53       private static final int DST_UNKNOWN      = 0x0100;
   54       private static final int DST_SPEAKER      = 0x0200;
   55       private static final int DST_HEADPHONE    = 0x0300;
   56       private static final int DST_LINE_OUT     = 0x0400;
   57       private static final int DST_MASK         = 0xFF00;
   58   
   59       // INSTANCE VARIABLES
   60       private Port.Info[] portInfos;
   61       // cache of instantiated ports
   62       private PortMixerPort[] ports;
   63   
   64       // instance ID of the native implementation
   65       private long id = 0;
   66   
   67       // CONSTRUCTOR
   68       PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) {
   69           // pass in Line.Info, mixer, controls
   70           super(portMixerInfo,              // Mixer.Info
   71                 null,                       // Control[]
   72                 null,                       // Line.Info[] sourceLineInfo
   73                 null);                      // Line.Info[] targetLineInfo
   74   
   75           if (Printer.trace) Printer.trace(">> PortMixer: constructor");
   76   
   77           int count = 0;
   78           int srcLineCount = 0;
   79           int dstLineCount = 0;
   80   
   81           try {
   82               try {
   83                   id = nOpen(getMixerIndex());
   84                   if (id != 0) {
   85                       count = nGetPortCount(id);
   86                       if (count < 0) {
   87                           if (Printer.trace) Printer.trace("nGetPortCount() returned error code: " + count);
   88                           count = 0;
   89                       }
   90                   }
   91               } catch (Exception e) {}
   92   
   93               portInfos = new Port.Info[count];
   94   
   95               for (int i = 0; i < count; i++) {
   96                   int type = nGetPortType(id, i);
   97                   srcLineCount += ((type & SRC_MASK) != 0)?1:0;
   98                   dstLineCount += ((type & DST_MASK) != 0)?1:0;
   99                   portInfos[i] = getPortInfo(i, type);
  100               }
  101           } finally {
  102               if (id != 0) {
  103                   nClose(id);
  104               }
  105               id = 0;
  106           }
  107   
  108           // fill sourceLineInfo and targetLineInfos with copies of the ones in portInfos
  109           sourceLineInfo = new Port.Info[srcLineCount];
  110           targetLineInfo = new Port.Info[dstLineCount];
  111   
  112           srcLineCount = 0; dstLineCount = 0;
  113           for (int i = 0; i < count; i++) {
  114               if (portInfos[i].isSource()) {
  115                   sourceLineInfo[srcLineCount++] = portInfos[i];
  116               } else {
  117                   targetLineInfo[dstLineCount++] = portInfos[i];
  118               }
  119           }
  120   
  121           if (Printer.trace) Printer.trace("<< PortMixer: constructor completed");
  122       }
  123   
  124   
  125       // ABSTRACT MIXER: ABSTRACT METHOD IMPLEMENTATIONS
  126   
  127       public Line getLine(Line.Info info) throws LineUnavailableException {
  128           Line.Info fullInfo = getLineInfo(info);
  129   
  130           if ((fullInfo != null) && (fullInfo instanceof Port.Info)) {
  131               for (int i = 0; i < portInfos.length; i++) {
  132                   if (fullInfo.equals(portInfos[i])) {
  133                       return getPort(i);
  134                   }
  135               }
  136           }
  137           throw new IllegalArgumentException("Line unsupported: " + info);
  138       }
  139   
  140   
  141       public int getMaxLines(Line.Info info) {
  142           Line.Info fullInfo = getLineInfo(info);
  143   
  144           // if it's not supported at all, return 0.
  145           if (fullInfo == null) {
  146               return 0;
  147           }
  148   
  149           if (fullInfo instanceof Port.Info) {
  150               //return AudioSystem.NOT_SPECIFIED; // if several instances of PortMixerPort
  151               return 1;
  152           }
  153           return 0;
  154       }
  155   
  156   
  157       protected void implOpen() throws LineUnavailableException {
  158           if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")");
  159   
  160           // open the mixer device
  161           id = nOpen(getMixerIndex());
  162   
  163           if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded.");
  164       }
  165   
  166       protected void implClose() {
  167           if (Printer.trace) Printer.trace(">> PortMixer: implClose");
  168   
  169           // close the mixer device
  170           long thisID = id;
  171           id = 0;
  172           nClose(thisID);
  173           if (ports != null) {
  174               for (int i = 0; i < ports.length; i++) {
  175                   if (ports[i] != null) {
  176                       ports[i].disposeControls();
  177                   }
  178               }
  179           }
  180   
  181           if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded");
  182       }
  183   
  184       protected void implStart() {}
  185       protected void implStop() {}
  186   
  187       // IMPLEMENTATION HELPERS
  188   
  189       private Port.Info getPortInfo(int portIndex, int type) {
  190           switch (type) {
  191           case SRC_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), true);
  192           case SRC_MICROPHONE:   return Port.Info.MICROPHONE;
  193           case SRC_LINE_IN:      return Port.Info.LINE_IN;
  194           case SRC_COMPACT_DISC: return Port.Info.COMPACT_DISC;
  195   
  196           case DST_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), false);
  197           case DST_SPEAKER:      return Port.Info.SPEAKER;
  198           case DST_HEADPHONE:    return Port.Info.HEADPHONE;
  199           case DST_LINE_OUT:     return Port.Info.LINE_OUT;
  200           }
  201           // should never happen...
  202           if (Printer.debug) Printer.debug("unknown port type: "+type);
  203           return null;
  204       }
  205   
  206       int getMixerIndex() {
  207           return ((PortMixerProvider.PortMixerInfo) getMixerInfo()).getIndex();
  208       }
  209   
  210       Port getPort(int index) {
  211           if (ports == null) {
  212               ports = new PortMixerPort[portInfos.length];
  213           }
  214           if (ports[index] == null) {
  215               ports[index] = new PortMixerPort((Port.Info)portInfos[index], this, index);
  216               return ports[index];
  217           }
  218           // $$fb TODO: return (Port) (ports[index].clone());
  219           return ports[index];
  220       }
  221   
  222       long getID() {
  223           return id;
  224       }
  225   
  226       // INNER CLASSES
  227   
  228       /**
  229        * Private inner class representing a Port for the PortMixer.
  230        */
  231       private static class PortMixerPort extends AbstractLine implements Port {
  232           private int portIndex;
  233           private long id;
  234   
  235           // CONSTRUCTOR
  236           private PortMixerPort(Port.Info info,
  237                                 PortMixer mixer,
  238                                 int portIndex) {
  239               super(info, mixer, null);
  240               if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info);
  241               this.portIndex = portIndex;
  242           }
  243   
  244   
  245           // ABSTRACT METHOD IMPLEMENTATIONS
  246   
  247           // ABSTRACT LINE
  248   
  249           void implOpen() throws LineUnavailableException {
  250               if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen().");
  251               long newID = ((PortMixer) mixer).getID();
  252               if ((id == 0) || (newID != id) || (controls.length == 0)) {
  253                   id = newID;
  254                   Vector vector = new Vector();
  255                   synchronized (vector) {
  256                       nGetControls(id, portIndex, vector);
  257                       controls = new Control[vector.size()];
  258                       for (int i = 0; i < controls.length; i++) {
  259                           controls[i] = (Control) vector.elementAt(i);
  260                       }
  261                   }
  262               } else {
  263                   enableControls(controls, true);
  264               }
  265               if (Printer.trace) Printer.trace("<< PortMixerPort: implOpen() succeeded");
  266           }
  267   
  268           private void enableControls(Control[] controls, boolean enable) {
  269               for (int i = 0; i < controls.length; i++) {
  270                   if (controls[i] instanceof BoolCtrl) {
  271                       ((BoolCtrl) controls[i]).closed = !enable;
  272                   }
  273                   else if (controls[i] instanceof FloatCtrl) {
  274                       ((FloatCtrl) controls[i]).closed = !enable;
  275                   }
  276                   else if (controls[i] instanceof CompoundControl) {
  277                       enableControls(((CompoundControl) controls[i]).getMemberControls(), enable);
  278                   }
  279               }
  280           }
  281   
  282           private void disposeControls() {
  283               enableControls(controls, false);
  284               controls = new Control[0];
  285           }
  286   
  287   
  288           void implClose() {
  289               if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()");
  290               // get rid of controls
  291               enableControls(controls, false);
  292               if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded");
  293           }
  294   
  295           // METHOD OVERRIDES
  296   
  297           // this is very similar to open(AudioFormat, int) in AbstractDataLine...
  298           public void open() throws LineUnavailableException {
  299               synchronized (mixer) {
  300                   // if the line is not currently open, try to open it with this format and buffer size
  301                   if (!isOpen()) {
  302                       if (Printer.trace) Printer.trace("> PortMixerPort: open");
  303                       // reserve mixer resources for this line
  304                       mixer.open(this);
  305                       try {
  306                           // open the line.  may throw LineUnavailableException.
  307                           implOpen();
  308   
  309                           // if we succeeded, set the open state to true and send events
  310                           setOpen(true);
  311                       } catch (LineUnavailableException e) {
  312                           // release mixer resources for this line and then throw the exception
  313                           mixer.close(this);
  314                           throw e;
  315                       }
  316                       if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded");
  317                   }
  318               }
  319           }
  320   
  321           // this is very similar to close() in AbstractDataLine...
  322           public void close() {
  323               synchronized (mixer) {
  324                   if (isOpen()) {
  325                       if (Printer.trace) Printer.trace("> PortMixerPort.close()");
  326   
  327                       // set the open state to false and send events
  328                       setOpen(false);
  329   
  330                       // close resources for this line
  331                       implClose();
  332   
  333                       // release mixer resources for this line
  334                       mixer.close(this);
  335                       if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded");
  336                   }
  337               }
  338           }
  339   
  340       } // class PortMixerPort
  341   
  342       /**
  343        * Private inner class representing a BooleanControl for PortMixerPort
  344        */
  345       private static class BoolCtrl extends BooleanControl {
  346           // the handle to the native control function
  347           private long controlID;
  348           private boolean closed = false;
  349   
  350           private static BooleanControl.Type createType(String name) {
  351               if (name.equals("Mute")) {
  352                   return BooleanControl.Type.MUTE;
  353               }
  354               else if (name.equals("Select")) {
  355                   // $$fb add as new static type?
  356                   //return BooleanControl.Type.SELECT;
  357               }
  358               return new BCT(name);
  359           }
  360   
  361   
  362           private BoolCtrl(long controlID, String name) {
  363               this(controlID, createType(name));
  364           }
  365   
  366           private BoolCtrl(long controlID, BooleanControl.Type typ) {
  367               super(typ, false);
  368               this.controlID = controlID;
  369           }
  370   
  371           public void setValue(boolean value) {
  372               if (!closed) {
  373                   nControlSetIntValue(controlID, value?1:0);
  374               }
  375           }
  376   
  377           public boolean getValue() {
  378               if (!closed) {
  379                   // never use any cached values
  380                   return (nControlGetIntValue(controlID)!=0)?true:false;
  381               }
  382               // ??
  383               return false;
  384           }
  385   
  386           /**
  387            * inner class for custom types
  388            */
  389           private static class BCT extends BooleanControl.Type {
  390               private BCT(String name) {
  391                   super(name);
  392               }
  393           }
  394       }
  395   
  396       /**
  397        * Private inner class representing a CompoundControl for PortMixerPort
  398        */
  399       private static class CompCtrl extends CompoundControl {
  400           private CompCtrl(String name, Control[] controls) {
  401               super(new CCT(name), controls);
  402           }
  403   
  404           /**
  405            * inner class for custom compound control types
  406            */
  407           private static class CCT extends CompoundControl.Type {
  408               private CCT(String name) {
  409                   super(name);
  410               }
  411           }
  412       }
  413   
  414       /**
  415        * Private inner class representing a BooleanControl for PortMixerPort
  416        */
  417       private static class FloatCtrl extends FloatControl {
  418           // the handle to the native control function
  419           private long controlID;
  420           private boolean closed = false;
  421   
  422           // predefined float control types. See also Ports.h
  423           private final static FloatControl.Type[] FLOAT_CONTROL_TYPES = {
  424               null,
  425               FloatControl.Type.BALANCE,
  426               FloatControl.Type.MASTER_GAIN,
  427               FloatControl.Type.PAN,
  428               FloatControl.Type.VOLUME
  429           };
  430   
  431           private FloatCtrl(long controlID, String name,
  432                             float min, float max, float precision, String units) {
  433               this(controlID, new FCT(name), min, max, precision, units);
  434           }
  435   
  436           private FloatCtrl(long controlID, int type,
  437                             float min, float max, float precision, String units) {
  438               this(controlID, FLOAT_CONTROL_TYPES[type], min, max, precision, units);
  439           }
  440   
  441           private FloatCtrl(long controlID, FloatControl.Type typ,
  442                            float min, float max, float precision, String units) {
  443               super(typ, min, max, precision, 1000, min, units);
  444               this.controlID = controlID;
  445           }
  446   
  447           public void setValue(float value) {
  448               if (!closed) {
  449                   nControlSetFloatValue(controlID, value);
  450               }
  451           }
  452   
  453           public float getValue() {
  454               if (!closed) {
  455                   // never use any cached values
  456                   return nControlGetFloatValue(controlID);
  457               }
  458               // ??
  459               return getMinimum();
  460           }
  461   
  462           /**
  463            * inner class for custom types
  464            */
  465           private static class FCT extends FloatControl.Type {
  466               private FCT(String name) {
  467                   super(name);
  468               }
  469           }
  470       }
  471   
  472       /**
  473        * Private inner class representing a port info
  474        */
  475       private static class PortInfo extends Port.Info {
  476           private PortInfo(String name, boolean isSource) {
  477               super(Port.class, name, isSource);
  478           }
  479       }
  480   
  481       // open the mixer with the given index. Returns a handle ID
  482       private static native long nOpen(int mixerIndex) throws LineUnavailableException;
  483       private static native void nClose(long id);
  484   
  485       // gets the number of ports for this mixer
  486       private static native int nGetPortCount(long id);
  487   
  488       // gets the type of the port with this index
  489       private static native int nGetPortType(long id, int portIndex);
  490   
  491       // gets the name of the port with this index
  492       private static native String nGetPortName(long id, int portIndex);
  493   
  494       // fills the vector with the controls for this port
  495       private static native void nGetControls(long id, int portIndex, Vector vector);
  496   
  497       // getters/setters for controls
  498       private static native void nControlSetIntValue(long controlID, int value);
  499       private static native int nControlGetIntValue(long controlID);
  500       private static native void nControlSetFloatValue(long controlID, float value);
  501       private static native float nControlGetFloatValue(long controlID);
  502   
  503   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]