< prev index next >

src/java.desktop/share/classes/com/sun/media/sound/PortMixer.java

Print this page




  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 final 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);


 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(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 final class PortMixerPort extends AbstractLine
 232             implements Port {
 233 
 234         private final int portIndex;
 235         private long id;
 236 
 237         // CONSTRUCTOR
 238         private PortMixerPort(Port.Info info,
 239                               PortMixer mixer,
 240                               int portIndex) {
 241             super(info, mixer, null);
 242             if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info);
 243             this.portIndex = portIndex;
 244         }
 245 
 246 
 247         // ABSTRACT METHOD IMPLEMENTATIONS
 248 
 249         // ABSTRACT LINE
 250 
 251         void implOpen() throws LineUnavailableException {
 252             if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen().");
 253             long newID = ((PortMixer) mixer).getID();
 254             if ((id == 0) || (newID != id) || (controls.length == 0)) {
 255                 id = newID;
 256                 Vector<Control> vector = new Vector<>();
 257                 synchronized (vector) {
 258                     nGetControls(id, portIndex, vector);
 259                     controls = new Control[vector.size()];
 260                     for (int i = 0; i < controls.length; i++) {
 261                         controls[i] = vector.elementAt(i);
 262                     }
 263                 }
 264             } else {
 265                 enableControls(controls, true);
 266             }
 267             if (Printer.trace) Printer.trace("<< PortMixerPort: implOpen() succeeded");
 268         }
 269 
 270         private void enableControls(Control[] controls, boolean enable) {
 271             for (int i = 0; i < controls.length; i++) {
 272                 if (controls[i] instanceof BoolCtrl) {
 273                     ((BoolCtrl) controls[i]).closed = !enable;
 274                 }
 275                 else if (controls[i] instanceof FloatCtrl) {
 276                     ((FloatCtrl) controls[i]).closed = !enable;
 277                 }
 278                 else if (controls[i] instanceof CompoundControl) {
 279                     enableControls(((CompoundControl) controls[i]).getMemberControls(), enable);
 280                 }
 281             }
 282         }
 283 
 284         private void disposeControls() {
 285             enableControls(controls, false);
 286             controls = new Control[0];
 287         }
 288 
 289 
 290         void implClose() {
 291             if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()");
 292             // get rid of controls
 293             enableControls(controls, false);
 294             if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded");
 295         }
 296 
 297         // METHOD OVERRIDES
 298 
 299         // this is very similar to open(AudioFormat, int) in AbstractDataLine...

 300         public void open() throws LineUnavailableException {
 301             synchronized (mixer) {
 302                 // if the line is not currently open, try to open it with this format and buffer size
 303                 if (!isOpen()) {
 304                     if (Printer.trace) Printer.trace("> PortMixerPort: open");
 305                     // reserve mixer resources for this line
 306                     mixer.open(this);
 307                     try {
 308                         // open the line.  may throw LineUnavailableException.
 309                         implOpen();
 310 
 311                         // if we succeeded, set the open state to true and send events
 312                         setOpen(true);
 313                     } catch (LineUnavailableException e) {
 314                         // release mixer resources for this line and then throw the exception
 315                         mixer.close(this);
 316                         throw e;
 317                     }
 318                     if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded");
 319                 }
 320             }
 321         }
 322 
 323         // this is very similar to close() in AbstractDataLine...

 324         public void close() {
 325             synchronized (mixer) {
 326                 if (isOpen()) {
 327                     if (Printer.trace) Printer.trace("> PortMixerPort.close()");
 328 
 329                     // set the open state to false and send events
 330                     setOpen(false);
 331 
 332                     // close resources for this line
 333                     implClose();
 334 
 335                     // release mixer resources for this line
 336                     mixer.close(this);
 337                     if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded");
 338                 }
 339             }
 340         }
 341 
 342     } // class PortMixerPort
 343 
 344     /**
 345      * Private inner class representing a BooleanControl for PortMixerPort
 346      */
 347     private static final class BoolCtrl extends BooleanControl {
 348         // the handle to the native control function
 349         private final long controlID;
 350         private boolean closed = false;
 351 
 352         private static BooleanControl.Type createType(String name) {
 353             if (name.equals("Mute")) {
 354                 return BooleanControl.Type.MUTE;
 355             }
 356             else if (name.equals("Select")) {
 357                 // $$fb add as new static type?
 358                 //return BooleanControl.Type.SELECT;
 359             }
 360             return new BCT(name);
 361         }
 362 
 363 
 364         private BoolCtrl(long controlID, String name) {
 365             this(controlID, createType(name));
 366         }
 367 
 368         private BoolCtrl(long controlID, BooleanControl.Type typ) {
 369             super(typ, false);
 370             this.controlID = controlID;
 371         }
 372 

 373         public void setValue(boolean value) {
 374             if (!closed) {
 375                 nControlSetIntValue(controlID, value?1:0);
 376             }
 377         }
 378 

 379         public boolean getValue() {
 380             if (!closed) {
 381                 // never use any cached values
 382                 return (nControlGetIntValue(controlID)!=0)?true:false;
 383             }
 384             // ??
 385             return false;
 386         }
 387 
 388         /**
 389          * inner class for custom types
 390          */
 391         private static final class BCT extends BooleanControl.Type {
 392             private BCT(String name) {
 393                 super(name);
 394             }
 395         }
 396     }
 397 
 398     /**
 399      * Private inner class representing a CompoundControl for PortMixerPort
 400      */
 401     private static final class CompCtrl extends CompoundControl {
 402         private CompCtrl(String name, Control[] controls) {
 403             super(new CCT(name), controls);
 404         }
 405 
 406         /**
 407          * inner class for custom compound control types
 408          */
 409         private static final class CCT extends CompoundControl.Type {
 410             private CCT(String name) {
 411                 super(name);
 412             }
 413         }
 414     }
 415 
 416     /**
 417      * Private inner class representing a BooleanControl for PortMixerPort
 418      */
 419     private static final class FloatCtrl extends FloatControl {
 420         // the handle to the native control function
 421         private final long controlID;
 422         private boolean closed = false;
 423 
 424         // predefined float control types. See also Ports.h
 425         private static final FloatControl.Type[] FLOAT_CONTROL_TYPES = {
 426             null,
 427             FloatControl.Type.BALANCE,
 428             FloatControl.Type.MASTER_GAIN,
 429             FloatControl.Type.PAN,
 430             FloatControl.Type.VOLUME
 431         };
 432 
 433         private FloatCtrl(long controlID, String name,
 434                           float min, float max, float precision, String units) {
 435             this(controlID, new FCT(name), min, max, precision, units);
 436         }
 437 
 438         private FloatCtrl(long controlID, int type,
 439                           float min, float max, float precision, String units) {
 440             this(controlID, FLOAT_CONTROL_TYPES[type], min, max, precision, units);
 441         }
 442 
 443         private FloatCtrl(long controlID, FloatControl.Type typ,
 444                          float min, float max, float precision, String units) {
 445             super(typ, min, max, precision, 1000, min, units);
 446             this.controlID = controlID;
 447         }
 448 

 449         public void setValue(float value) {
 450             if (!closed) {
 451                 nControlSetFloatValue(controlID, value);
 452             }
 453         }
 454 

 455         public float getValue() {
 456             if (!closed) {
 457                 // never use any cached values
 458                 return nControlGetFloatValue(controlID);
 459             }
 460             // ??
 461             return getMinimum();
 462         }
 463 
 464         /**
 465          * inner class for custom types
 466          */
 467         private static final class FCT extends FloatControl.Type {
 468             private FCT(String name) {
 469                 super(name);
 470             }
 471         }
 472     }
 473 
 474     /**
 475      * Private inner class representing a port info
 476      */
 477     private static final class PortInfo extends Port.Info {
 478         private PortInfo(String name, boolean isSource) {
 479             super(Port.class, name, isSource);
 480         }
 481     }
 482 
 483     // open the mixer with the given index. Returns a handle ID
 484     private static native long nOpen(int mixerIndex) throws LineUnavailableException;
 485     private static native void nClose(long id);
 486 
 487     // gets the number of ports for this mixer
 488     private static native int nGetPortCount(long id);
 489 
 490     // gets the type of the port with this index
 491     private static native int nGetPortType(long id, int portIndex);
 492 
 493     // gets the name of the port with this index
 494     private static native String nGetPortName(long id, int portIndex);
 495 


  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.BooleanControl;
  31 import javax.sound.sampled.CompoundControl;
  32 import javax.sound.sampled.Control;
  33 import javax.sound.sampled.FloatControl;
  34 import javax.sound.sampled.Line;
  35 import javax.sound.sampled.LineUnavailableException;
  36 import javax.sound.sampled.Port;




  37 
  38 /**
  39  * A Mixer which only provides Ports.
  40  *
  41  * @author Florian Bomers
  42  */
  43 final class PortMixer extends AbstractMixer {
  44 

  45     private static final int SRC_UNKNOWN      = 0x01;
  46     private static final int SRC_MICROPHONE   = 0x02;
  47     private static final int SRC_LINE_IN      = 0x03;
  48     private static final int SRC_COMPACT_DISC = 0x04;
  49     private static final int SRC_MASK         = 0xFF;
  50 
  51     private static final int DST_UNKNOWN      = 0x0100;
  52     private static final int DST_SPEAKER      = 0x0200;
  53     private static final int DST_HEADPHONE    = 0x0300;
  54     private static final int DST_LINE_OUT     = 0x0400;
  55     private static final int DST_MASK         = 0xFF00;
  56 
  57     private final Port.Info[] portInfos;

  58     // cache of instantiated ports
  59     private PortMixerPort[] ports;
  60 
  61     // instance ID of the native implementation
  62     private long id = 0;
  63 

  64     PortMixer(PortMixerProvider.PortMixerInfo portMixerInfo) {
  65         // pass in Line.Info, mixer, controls
  66         super(portMixerInfo,              // Mixer.Info
  67               null,                       // Control[]
  68               null,                       // Line.Info[] sourceLineInfo
  69               null);                      // Line.Info[] targetLineInfo
  70 
  71         if (Printer.trace) Printer.trace(">> PortMixer: constructor");
  72 
  73         int count = 0;
  74         int srcLineCount = 0;
  75         int dstLineCount = 0;
  76 
  77         try {
  78             try {
  79                 id = nOpen(getMixerIndex());
  80                 if (id != 0) {
  81                     count = nGetPortCount(id);
  82                     if (count < 0) {
  83                         if (Printer.trace) Printer.trace("nGetPortCount() returned error code: " + count);


 100             }
 101             id = 0;
 102         }
 103 
 104         // fill sourceLineInfo and targetLineInfos with copies of the ones in portInfos
 105         sourceLineInfo = new Port.Info[srcLineCount];
 106         targetLineInfo = new Port.Info[dstLineCount];
 107 
 108         srcLineCount = 0; dstLineCount = 0;
 109         for (int i = 0; i < count; i++) {
 110             if (portInfos[i].isSource()) {
 111                 sourceLineInfo[srcLineCount++] = portInfos[i];
 112             } else {
 113                 targetLineInfo[dstLineCount++] = portInfos[i];
 114             }
 115         }
 116 
 117         if (Printer.trace) Printer.trace("<< PortMixer: constructor completed");
 118     }
 119 
 120     @Override


 121     public Line getLine(Line.Info info) throws LineUnavailableException {
 122         Line.Info fullInfo = getLineInfo(info);
 123 
 124         if ((fullInfo != null) && (fullInfo instanceof Port.Info)) {
 125             for (int i = 0; i < portInfos.length; i++) {
 126                 if (fullInfo.equals(portInfos[i])) {
 127                     return getPort(i);
 128                 }
 129             }
 130         }
 131         throw new IllegalArgumentException("Line unsupported: " + info);
 132     }
 133 
 134     @Override
 135     public int getMaxLines(Line.Info info) {
 136         Line.Info fullInfo = getLineInfo(info);
 137 
 138         // if it's not supported at all, return 0.
 139         if (fullInfo == null) {
 140             return 0;
 141         }
 142 
 143         if (fullInfo instanceof Port.Info) {
 144             //return AudioSystem.NOT_SPECIFIED; // if several instances of PortMixerPort
 145             return 1;
 146         }
 147         return 0;
 148     }
 149 
 150     @Override
 151     protected void implOpen() throws LineUnavailableException {
 152         if (Printer.trace) Printer.trace(">> PortMixer: implOpen (id="+id+")");
 153 
 154         // open the mixer device
 155         id = nOpen(getMixerIndex());
 156 
 157         if (Printer.trace) Printer.trace("<< PortMixer: implOpen succeeded.");
 158     }
 159 
 160     @Override
 161     protected void implClose() {
 162         if (Printer.trace) Printer.trace(">> PortMixer: implClose");
 163 
 164         // close the mixer device
 165         long thisID = id;
 166         id = 0;
 167         nClose(thisID);
 168         if (ports != null) {
 169             for (int i = 0; i < ports.length; i++) {
 170                 if (ports[i] != null) {
 171                     ports[i].disposeControls();
 172                 }
 173             }
 174         }
 175 
 176         if (Printer.trace) Printer.trace("<< PortMixer: implClose succeeded");
 177     }
 178 
 179     @Override
 180     protected void implStart() {}
 181     @Override
 182     protected void implStop() {}
 183 


 184     private Port.Info getPortInfo(int portIndex, int type) {
 185         switch (type) {
 186         case SRC_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), true);
 187         case SRC_MICROPHONE:   return Port.Info.MICROPHONE;
 188         case SRC_LINE_IN:      return Port.Info.LINE_IN;
 189         case SRC_COMPACT_DISC: return Port.Info.COMPACT_DISC;
 190 
 191         case DST_UNKNOWN:      return new PortInfo(nGetPortName(getID(), portIndex), false);
 192         case DST_SPEAKER:      return Port.Info.SPEAKER;
 193         case DST_HEADPHONE:    return Port.Info.HEADPHONE;
 194         case DST_LINE_OUT:     return Port.Info.LINE_OUT;
 195         }
 196         // should never happen...
 197         if (Printer.debug) Printer.debug("unknown port type: "+type);
 198         return null;
 199     }
 200 
 201     int getMixerIndex() {
 202         return ((PortMixerProvider.PortMixerInfo) getMixerInfo()).getIndex();
 203     }
 204 
 205     Port getPort(int index) {
 206         if (ports == null) {
 207             ports = new PortMixerPort[portInfos.length];
 208         }
 209         if (ports[index] == null) {
 210             ports[index] = new PortMixerPort(portInfos[index], this, index);
 211             return ports[index];
 212         }
 213         // $$fb TODO: return (Port) (ports[index].clone());
 214         return ports[index];
 215     }
 216 
 217     long getID() {
 218         return id;
 219     }
 220 


 221     /**
 222      * Private inner class representing a Port for the PortMixer.
 223      */
 224     private static final class PortMixerPort extends AbstractLine
 225             implements Port {
 226 
 227         private final int portIndex;
 228         private long id;
 229 

 230         private PortMixerPort(Port.Info info,
 231                               PortMixer mixer,
 232                               int portIndex) {
 233             super(info, mixer, null);
 234             if (Printer.trace) Printer.trace("PortMixerPort CONSTRUCTOR: info: " + info);
 235             this.portIndex = portIndex;
 236         }
 237 





 238         void implOpen() throws LineUnavailableException {
 239             if (Printer.trace) Printer.trace(">> PortMixerPort: implOpen().");
 240             long newID = ((PortMixer) mixer).getID();
 241             if ((id == 0) || (newID != id) || (controls.length == 0)) {
 242                 id = newID;
 243                 Vector<Control> vector = new Vector<>();
 244                 synchronized (vector) {
 245                     nGetControls(id, portIndex, vector);
 246                     controls = new Control[vector.size()];
 247                     for (int i = 0; i < controls.length; i++) {
 248                         controls[i] = vector.elementAt(i);
 249                     }
 250                 }
 251             } else {
 252                 enableControls(controls, true);
 253             }
 254             if (Printer.trace) Printer.trace("<< PortMixerPort: implOpen() succeeded");
 255         }
 256 
 257         private void enableControls(Control[] controls, boolean enable) {
 258             for (int i = 0; i < controls.length; i++) {
 259                 if (controls[i] instanceof BoolCtrl) {
 260                     ((BoolCtrl) controls[i]).closed = !enable;
 261                 }
 262                 else if (controls[i] instanceof FloatCtrl) {
 263                     ((FloatCtrl) controls[i]).closed = !enable;
 264                 }
 265                 else if (controls[i] instanceof CompoundControl) {
 266                     enableControls(((CompoundControl) controls[i]).getMemberControls(), enable);
 267                 }
 268             }
 269         }
 270 
 271         private void disposeControls() {
 272             enableControls(controls, false);
 273             controls = new Control[0];
 274         }
 275 

 276         void implClose() {
 277             if (Printer.trace) Printer.trace(">> PortMixerPort: implClose()");
 278             // get rid of controls
 279             enableControls(controls, false);
 280             if (Printer.trace) Printer.trace("<< PortMixerPort: implClose() succeeded");
 281         }
 282 


 283         // this is very similar to open(AudioFormat, int) in AbstractDataLine...
 284         @Override
 285         public void open() throws LineUnavailableException {
 286             synchronized (mixer) {
 287                 // if the line is not currently open, try to open it with this format and buffer size
 288                 if (!isOpen()) {
 289                     if (Printer.trace) Printer.trace("> PortMixerPort: open");
 290                     // reserve mixer resources for this line
 291                     mixer.open(this);
 292                     try {
 293                         // open the line.  may throw LineUnavailableException.
 294                         implOpen();
 295 
 296                         // if we succeeded, set the open state to true and send events
 297                         setOpen(true);
 298                     } catch (LineUnavailableException e) {
 299                         // release mixer resources for this line and then throw the exception
 300                         mixer.close(this);
 301                         throw e;
 302                     }
 303                     if (Printer.trace) Printer.trace("< PortMixerPort: open succeeded");
 304                 }
 305             }
 306         }
 307 
 308         // this is very similar to close() in AbstractDataLine...
 309         @Override
 310         public void close() {
 311             synchronized (mixer) {
 312                 if (isOpen()) {
 313                     if (Printer.trace) Printer.trace("> PortMixerPort.close()");
 314 
 315                     // set the open state to false and send events
 316                     setOpen(false);
 317 
 318                     // close resources for this line
 319                     implClose();
 320 
 321                     // release mixer resources for this line
 322                     mixer.close(this);
 323                     if (Printer.trace) Printer.trace("< PortMixerPort.close() succeeded");
 324                 }
 325             }
 326         }
 327 
 328     } // class PortMixerPort
 329 
 330     /**
 331      * Private inner class representing a BooleanControl for PortMixerPort.
 332      */
 333     private static final class BoolCtrl extends BooleanControl {
 334         // the handle to the native control function
 335         private final long controlID;
 336         private boolean closed = false;
 337 
 338         private static BooleanControl.Type createType(String name) {
 339             if (name.equals("Mute")) {
 340                 return BooleanControl.Type.MUTE;
 341             }
 342             else if (name.equals("Select")) {
 343                 // $$fb add as new static type?
 344                 //return BooleanControl.Type.SELECT;
 345             }
 346             return new BCT(name);
 347         }
 348 

 349         private BoolCtrl(long controlID, String name) {
 350             this(controlID, createType(name));
 351         }
 352 
 353         private BoolCtrl(long controlID, BooleanControl.Type typ) {
 354             super(typ, false);
 355             this.controlID = controlID;
 356         }
 357 
 358         @Override
 359         public void setValue(boolean value) {
 360             if (!closed) {
 361                 nControlSetIntValue(controlID, value?1:0);
 362             }
 363         }
 364 
 365         @Override
 366         public boolean getValue() {
 367             if (!closed) {
 368                 // never use any cached values
 369                 return (nControlGetIntValue(controlID)!=0)?true:false;
 370             }
 371             // ??
 372             return false;
 373         }
 374 
 375         /**
 376          * inner class for custom types.
 377          */
 378         private static final class BCT extends BooleanControl.Type {
 379             private BCT(String name) {
 380                 super(name);
 381             }
 382         }
 383     }
 384 
 385     /**
 386      * Private inner class representing a CompoundControl for PortMixerPort.
 387      */
 388     private static final class CompCtrl extends CompoundControl {
 389         private CompCtrl(String name, Control[] controls) {
 390             super(new CCT(name), controls);
 391         }
 392 
 393         /**
 394          * inner class for custom compound control types.
 395          */
 396         private static final class CCT extends CompoundControl.Type {
 397             private CCT(String name) {
 398                 super(name);
 399             }
 400         }
 401     }
 402 
 403     /**
 404      * Private inner class representing a BooleanControl for PortMixerPort.
 405      */
 406     private static final class FloatCtrl extends FloatControl {
 407         // the handle to the native control function
 408         private final long controlID;
 409         private boolean closed = false;
 410 
 411         // predefined float control types. See also Ports.h
 412         private static final FloatControl.Type[] FLOAT_CONTROL_TYPES = {
 413             null,
 414             FloatControl.Type.BALANCE,
 415             FloatControl.Type.MASTER_GAIN,
 416             FloatControl.Type.PAN,
 417             FloatControl.Type.VOLUME
 418         };
 419 
 420         private FloatCtrl(long controlID, String name,
 421                           float min, float max, float precision, String units) {
 422             this(controlID, new FCT(name), min, max, precision, units);
 423         }
 424 
 425         private FloatCtrl(long controlID, int type,
 426                           float min, float max, float precision, String units) {
 427             this(controlID, FLOAT_CONTROL_TYPES[type], min, max, precision, units);
 428         }
 429 
 430         private FloatCtrl(long controlID, FloatControl.Type typ,
 431                          float min, float max, float precision, String units) {
 432             super(typ, min, max, precision, 1000, min, units);
 433             this.controlID = controlID;
 434         }
 435 
 436         @Override
 437         public void setValue(float value) {
 438             if (!closed) {
 439                 nControlSetFloatValue(controlID, value);
 440             }
 441         }
 442 
 443         @Override
 444         public float getValue() {
 445             if (!closed) {
 446                 // never use any cached values
 447                 return nControlGetFloatValue(controlID);
 448             }
 449             // ??
 450             return getMinimum();
 451         }
 452 
 453         /**
 454          * inner class for custom types.
 455          */
 456         private static final class FCT extends FloatControl.Type {
 457             private FCT(String name) {
 458                 super(name);
 459             }
 460         }
 461     }
 462 
 463     /**
 464      * Private inner class representing a port info.
 465      */
 466     private static final class PortInfo extends Port.Info {
 467         private PortInfo(String name, boolean isSource) {
 468             super(Port.class, name, isSource);
 469         }
 470     }
 471 
 472     // open the mixer with the given index. Returns a handle ID
 473     private static native long nOpen(int mixerIndex) throws LineUnavailableException;
 474     private static native void nClose(long id);
 475 
 476     // gets the number of ports for this mixer
 477     private static native int nGetPortCount(long id);
 478 
 479     // gets the type of the port with this index
 480     private static native int nGetPortType(long id, int portIndex);
 481 
 482     // gets the name of the port with this index
 483     private static native String nGetPortName(long id, int portIndex);
 484 
< prev index next >