Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 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.AudioFormat;
   31   import javax.sound.sampled.AudioSystem;
   32   import javax.sound.sampled.Control;
   33   import javax.sound.sampled.DataLine;
   34   import javax.sound.sampled.Mixer;
   35   import javax.sound.sampled.Line;
   36   import javax.sound.sampled.LineEvent;
   37   import javax.sound.sampled.LineListener;
   38   import javax.sound.sampled.LineUnavailableException;
   39   
   40   /**
   41    * Abstract Mixer.  Implements Mixer (with abstract methods) and specifies
   42    * some other common methods for use by our implementation.
   43    *
   44    * @author Kara Kytle
   45    */
   46   //$$fb 2002-07-26: let AbstractMixer be an AbstractLine and NOT an AbstractDataLine!
   47   abstract class AbstractMixer extends AbstractLine implements Mixer {
   48   
   49       //  STATIC VARIABLES
   50       protected static final int PCM  = 0;
   51       protected static final int ULAW = 1;
   52       protected static final int ALAW = 2;
   53   
   54   
   55       // IMMUTABLE PROPERTIES
   56   
   57       /**
   58        * Info object describing this mixer.
   59        */
   60       private final Mixer.Info mixerInfo;
   61   
   62       /**
   63        * source lines provided by this mixer
   64        */
   65       protected Line.Info[] sourceLineInfo;
   66   
   67       /**
   68        * target lines provided by this mixer
   69        */
   70       protected Line.Info[] targetLineInfo;
   71   
   72       /**
   73        * if any line of this mixer is started
   74        */
   75       private boolean started = false;
   76   
   77       /**
   78        * if this mixer had been opened manually with open()
   79        * If it was, then it won't be closed automatically,
   80        * only when close() is called manually.
   81        */
   82       private boolean manuallyOpened = false;
   83   
   84   
   85       /**
   86        * Supported formats for the mixer.
   87        */
   88       //$$fb DELETE
   89       //protected Vector formats = new Vector();
   90   
   91   
   92       // STATE VARIABLES
   93   
   94   
   95       /**
   96        * Source lines (ports) currently open
   97        */
   98       protected Vector sourceLines = new Vector();
   99   
  100   
  101       /**
  102        * Target lines currently open.
  103        */
  104       protected Vector targetLines = new Vector();
  105   
  106   
  107       /**
  108        * Constructs a new AbstractMixer.
  109        * @param mixer the mixer with which this line is associated
  110        * @param controls set of supported controls
  111        */
  112       protected AbstractMixer(Mixer.Info mixerInfo,
  113                               Control[] controls,
  114                               Line.Info[] sourceLineInfo,
  115                               Line.Info[] targetLineInfo) {
  116   
  117           // Line.Info, AbstractMixer, Control[]
  118           super(new Line.Info(Mixer.class), null, controls);
  119   
  120           // setup the line part
  121           this.mixer = this;
  122           if (controls == null) {
  123               controls = new Control[0];
  124           }
  125   
  126           // setup the mixer part
  127           this.mixerInfo = mixerInfo;
  128           this.sourceLineInfo = sourceLineInfo;
  129           this.targetLineInfo = targetLineInfo;
  130       }
  131   
  132   
  133       // MIXER METHODS
  134   
  135   
  136       public Mixer.Info getMixerInfo() {
  137           return mixerInfo;
  138       }
  139   
  140   
  141       public Line.Info[] getSourceLineInfo() {
  142           Line.Info[] localArray = new Line.Info[sourceLineInfo.length];
  143           System.arraycopy(sourceLineInfo, 0, localArray, 0, sourceLineInfo.length);
  144           return localArray;
  145       }
  146   
  147   
  148       public Line.Info[] getTargetLineInfo() {
  149   
  150           Line.Info[] localArray = new Line.Info[targetLineInfo.length];
  151           System.arraycopy(targetLineInfo, 0, localArray, 0, targetLineInfo.length);
  152           return localArray;
  153       }
  154   
  155   
  156       public Line.Info[] getSourceLineInfo(Line.Info info) {
  157   
  158           int i;
  159           Vector vec = new Vector();
  160   
  161           for (i = 0; i < sourceLineInfo.length; i++) {
  162   
  163               if (info.matches(sourceLineInfo[i])) {
  164                   vec.addElement(sourceLineInfo[i]);
  165               }
  166           }
  167   
  168           Line.Info[] returnedArray = new Line.Info[vec.size()];
  169           for (i = 0; i < returnedArray.length; i++) {
  170               returnedArray[i] = (Line.Info)vec.elementAt(i);
  171           }
  172   
  173           return returnedArray;
  174       }
  175   
  176   
  177       public Line.Info[] getTargetLineInfo(Line.Info info) {
  178   
  179           int i;
  180           Vector vec = new Vector();
  181   
  182           for (i = 0; i < targetLineInfo.length; i++) {
  183   
  184               if (info.matches(targetLineInfo[i])) {
  185                   vec.addElement(targetLineInfo[i]);
  186               }
  187           }
  188   
  189           Line.Info[] returnedArray = new Line.Info[vec.size()];
  190           for (i = 0; i < returnedArray.length; i++) {
  191               returnedArray[i] = (Line.Info)vec.elementAt(i);
  192           }
  193   
  194           return returnedArray;
  195       }
  196   
  197   
  198       public boolean isLineSupported(Line.Info info) {
  199   
  200           int i;
  201   
  202           for (i = 0; i < sourceLineInfo.length; i++) {
  203   
  204               if (info.matches(sourceLineInfo[i])) {
  205                   return true;
  206               }
  207           }
  208   
  209           for (i = 0; i < targetLineInfo.length; i++) {
  210   
  211               if (info.matches(targetLineInfo[i])) {
  212                   return true;
  213               }
  214           }
  215   
  216           return false;
  217       }
  218   
  219   
  220       public abstract Line getLine(Line.Info info) throws LineUnavailableException;
  221   
  222       public abstract int getMaxLines(Line.Info info);
  223   
  224       protected abstract void implOpen() throws LineUnavailableException;
  225       protected abstract void implStart();
  226       protected abstract void implStop();
  227       protected abstract void implClose();
  228   
  229   
  230       public Line[] getSourceLines() {
  231   
  232           Line[] localLines;
  233   
  234           synchronized(sourceLines) {
  235   
  236               localLines = new Line[sourceLines.size()];
  237   
  238               for (int i = 0; i < localLines.length; i++) {
  239                   localLines[i] = (Line)sourceLines.elementAt(i);
  240               }
  241           }
  242   
  243           return localLines;
  244       }
  245   
  246   
  247       public Line[] getTargetLines() {
  248   
  249           Line[] localLines;
  250   
  251           synchronized(targetLines) {
  252   
  253               localLines = new Line[targetLines.size()];
  254   
  255               for (int i = 0; i < localLines.length; i++) {
  256                   localLines[i] = (Line)targetLines.elementAt(i);
  257               }
  258           }
  259   
  260           return localLines;
  261       }
  262   
  263   
  264       /**
  265        * Default implementation always throws an exception.
  266        */
  267       public void synchronize(Line[] lines, boolean maintainSync) {
  268           throw new IllegalArgumentException("Synchronization not supported by this mixer.");
  269       }
  270   
  271   
  272       /**
  273        * Default implementation always throws an exception.
  274        */
  275       public void unsynchronize(Line[] lines) {
  276           throw new IllegalArgumentException("Synchronization not supported by this mixer.");
  277       }
  278   
  279   
  280       /**
  281        * Default implementation always returns false.
  282        */
  283       public boolean isSynchronizationSupported(Line[] lines, boolean maintainSync) {
  284           return false;
  285       }
  286   
  287   
  288       // OVERRIDES OF ABSTRACT DATA LINE METHODS
  289   
  290       /**
  291        * This implementation tries to open the mixer with its current format and buffer size settings.
  292        */
  293       public synchronized void open() throws LineUnavailableException {
  294           open(true);
  295       }
  296   
  297       /**
  298        * This implementation tries to open the mixer with its current format and buffer size settings.
  299        */
  300       protected synchronized void open(boolean manual) throws LineUnavailableException {
  301           if (Printer.trace) Printer.trace(">> AbstractMixer: open()");
  302           if (!isOpen()) {
  303               implOpen();
  304               // if the mixer is not currently open, set open to true and send event
  305               setOpen(true);
  306               if (manual) {
  307                   manuallyOpened = true;
  308               }
  309           }
  310   
  311           if (Printer.trace) Printer.trace("<< AbstractMixer: open() succeeded");
  312       }
  313   
  314   
  315       // METHOD FOR INTERNAL IMPLEMENTATION USE
  316   
  317   
  318       /**
  319        * The default implementation of this method just determines whether
  320        * this line is a source or target line, calls open(no-arg) on the
  321        * mixer, and adds the line to the appropriate vector.
  322        * The mixer may be opened at a format different than the line's
  323        * format if it is a DataLine.
  324        */
  325       protected synchronized void open(Line line) throws LineUnavailableException {
  326   
  327           if (Printer.trace) Printer.trace(">> AbstractMixer: open(line = " + line + ")");
  328   
  329           // $$kk: 06.11.99: ignore ourselves for now
  330           if (this.equals(line)) {
  331               if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") nothing done");
  332               return;
  333           }
  334   
  335           // source line?
  336           if (isSourceLine(line.getLineInfo())) {
  337               if (! sourceLines.contains(line) ) {
  338                   // call the no-arg open method for the mixer; it should open at its
  339                   // default format if it is not open yet
  340                   open(false);
  341   
  342                   // we opened successfully! add the line to the list
  343                   sourceLines.addElement(line);
  344               }
  345           } else {
  346               // target line?
  347               if(isTargetLine(line.getLineInfo())) {
  348                   if (! targetLines.contains(line) ) {
  349                       // call the no-arg open method for the mixer; it should open at its
  350                       // default format if it is not open yet
  351                       open(false);
  352   
  353                       // we opened successfully!  add the line to the list
  354                       targetLines.addElement(line);
  355                   }
  356               } else {
  357                   if (Printer.err) Printer.err("Unknown line received for AbstractMixer.open(Line): " + line);
  358               }
  359           }
  360   
  361           if (Printer.trace) Printer.trace("<< AbstractMixer: open(" + line + ") completed");
  362       }
  363   
  364   
  365       /**
  366        * Removes this line from the list of open source lines and
  367        * open target lines, if it exists in either.
  368        * If the list is now empty, closes the mixer.
  369        */
  370       protected synchronized void close(Line line) {
  371   
  372           if (Printer.trace) Printer.trace(">> AbstractMixer: close(" + line + ")");
  373   
  374           // $$kk: 06.11.99: ignore ourselves for now
  375           if (this.equals(line)) {
  376               if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") nothing done");
  377               return;
  378           }
  379   
  380           sourceLines.removeElement(line);
  381           targetLines.removeElement(line);
  382   
  383           if (Printer.debug) Printer.debug("AbstractMixer: close(line): sourceLines.size() now: " + sourceLines.size());
  384           if (Printer.debug) Printer.debug("AbstractMixer: close(line): targetLines.size() now: " + targetLines.size());
  385   
  386   
  387           if (sourceLines.isEmpty() && targetLines.isEmpty() && !manuallyOpened) {
  388               if (Printer.trace) Printer.trace("AbstractMixer: close(" + line + "): need to close the mixer");
  389               close();
  390           }
  391   
  392           if (Printer.trace) Printer.trace("<< AbstractMixer: close(" + line + ") succeeded");
  393       }
  394   
  395   
  396       /**
  397        * Close all lines and then close this mixer.
  398        */
  399       public synchronized void close() {
  400           if (Printer.trace) Printer.trace(">> AbstractMixer: close()");
  401           if (isOpen()) {
  402               // close all source lines
  403               Line[] localLines = getSourceLines();
  404               for (int i = 0; i<localLines.length; i++) {
  405                   localLines[i].close();
  406               }
  407   
  408               // close all target lines
  409               localLines = getTargetLines();
  410               for (int i = 0; i<localLines.length; i++) {
  411                   localLines[i].close();
  412               }
  413   
  414               implClose();
  415   
  416               // set the open state to false and send events
  417               setOpen(false);
  418           }
  419           manuallyOpened = false;
  420           if (Printer.trace) Printer.trace("<< AbstractMixer: close() succeeded");
  421       }
  422   
  423       /**
  424        * Starts the mixer.
  425        */
  426       protected synchronized void start(Line line) {
  427   
  428           if (Printer.trace) Printer.trace(">> AbstractMixer: start(" + line + ")");
  429   
  430           // $$kk: 06.11.99: ignore ourselves for now
  431           if (this.equals(line)) {
  432               if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") nothing done");
  433               return;
  434           }
  435   
  436           // we just start the mixer regardless of anything else here.
  437           if (!started) {
  438               if (Printer.debug) Printer.debug("AbstractMixer: start(line): starting the mixer");
  439               implStart();
  440               started = true;
  441           }
  442   
  443           if (Printer.trace) Printer.trace("<< AbstractMixer: start(" + line + ") succeeded");
  444       }
  445   
  446   
  447       /**
  448        * Stops the mixer if this was the last running line.
  449        */
  450       protected synchronized void stop(Line line) {
  451   
  452           if (Printer.trace) Printer.trace(">> AbstractMixer: stop(" + line + ")");
  453   
  454           // $$kk: 06.11.99: ignore ourselves for now
  455           if (this.equals(line)) {
  456               if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") nothing done");
  457               return;
  458           }
  459   
  460           Vector localSourceLines = (Vector)sourceLines.clone();
  461           for (int i = 0; i < localSourceLines.size(); i++) {
  462   
  463               // if any other open line is running, return
  464   
  465               // this covers clips and source data lines
  466               if (localSourceLines.elementAt(i) instanceof AbstractDataLine) {
  467                   AbstractDataLine sourceLine = (AbstractDataLine)localSourceLines.elementAt(i);
  468                   if ( sourceLine.isStartedRunning() && (!sourceLine.equals(line)) ) {
  469                       if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running sourceLine: " + sourceLine);
  470                       return;
  471                   }
  472               }
  473           }
  474   
  475           Vector localTargetLines = (Vector)targetLines.clone();
  476           for (int i = 0; i < localTargetLines.size(); i++) {
  477   
  478               // if any other open line is running, return
  479               // this covers target data lines
  480               if (localTargetLines.elementAt(i) instanceof AbstractDataLine) {
  481                   AbstractDataLine targetLine = (AbstractDataLine)localTargetLines.elementAt(i);
  482                   if ( targetLine.isStartedRunning() && (!targetLine.equals(line)) ) {
  483                       if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") found running targetLine: " + targetLine);
  484                       return;
  485                   }
  486               }
  487           }
  488   
  489           // otherwise, stop
  490           if (Printer.debug) Printer.debug("AbstractMixer: stop(line): stopping the mixer");
  491           started = false;
  492           implStop();
  493   
  494           if (Printer.trace) Printer.trace("<< AbstractMixer: stop(" + line + ") succeeded");
  495       }
  496   
  497   
  498   
  499       /**
  500        * Determines whether this is a source line for this mixer.
  501        * Right now this just checks whether it's supported, but should
  502        * check whether it actually belongs to this mixer....
  503        */
  504       boolean isSourceLine(Line.Info info) {
  505   
  506           for (int i = 0; i < sourceLineInfo.length; i++) {
  507               if (info.matches(sourceLineInfo[i])) {
  508                   return true;
  509               }
  510           }
  511   
  512           return false;
  513       }
  514   
  515   
  516       /**
  517        * Determines whether this is a target line for this mixer.
  518        * Right now this just checks whether it's supported, but should
  519        * check whether it actually belongs to this mixer....
  520        */
  521       boolean isTargetLine(Line.Info info) {
  522   
  523           for (int i = 0; i < targetLineInfo.length; i++) {
  524               if (info.matches(targetLineInfo[i])) {
  525                   return true;
  526               }
  527           }
  528   
  529           return false;
  530       }
  531   
  532   
  533       /**
  534        * Returns the first complete Line.Info object it finds that
  535        * matches the one specified, or null if no matching Line.Info
  536        * object is found.
  537        */
  538       Line.Info getLineInfo(Line.Info info) {
  539           if (info == null) {
  540               return null;
  541           }
  542           // $$kk: 05.31.99: need to change this so that
  543           // the format and buffer size get set in the
  544           // returned info object for data lines??
  545           for (int i = 0; i < sourceLineInfo.length; i++) {
  546               if (info.matches(sourceLineInfo[i])) {
  547                   return sourceLineInfo[i];
  548               }
  549           }
  550   
  551           for (int i = 0; i < targetLineInfo.length; i++) {
  552               if (info.matches(targetLineInfo[i])) {
  553                   return targetLineInfo[i];
  554               }
  555           }
  556   
  557           return null;
  558       }
  559   
  560   }

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