Save This Page
Home » openjdk-7 » javax.sound » sampled » [javadoc | source]
    1   /*
    2    * Copyright 1999-2005 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.sound.sampled;
   27   
   28   import java.io.InputStream;
   29   import java.io.PushbackInputStream;
   30   import java.io.IOException;
   31   
   32   
   33   /**
   34    * An audio input stream is an input stream with a specified audio format and
   35    * length.  The length is expressed in sample frames, not bytes.
   36    * Several methods are provided for reading a certain number of bytes from
   37    * the stream, or an unspecified number of bytes.
   38    * The audio input stream keeps track  of the last byte that was read.
   39    * You can skip over an arbitrary number of bytes to get to a later position
   40    * for reading. An audio input stream may support marks.  When you set a mark,
   41    * the current position is remembered so that you can return to it later.
   42    * <p>
   43    * The <code>AudioSystem</code> class includes many methods that manipulate
   44    * <code>AudioInputStream</code> objects.
   45    * For example, the methods let you:
   46    * <ul>
   47    * <li> obtain an
   48    * audio input stream from an external audio file, stream, or URL
   49    * <li> write an external file from an audio input stream
   50    * <li> convert an audio input stream to a different audio format
   51    * </ul>
   52    *
   53    * @author David Rivas
   54    * @author Kara Kytle
   55    * @author Florian Bomers
   56    *
   57    * @see AudioSystem
   58    * @see Clip#open(AudioInputStream) Clip.open(AudioInputStream)
   59    * @since 1.3
   60    */
   61   public class AudioInputStream extends InputStream {
   62   
   63       /**
   64        * The <code>InputStream</code> from which this <code>AudioInputStream</code>
   65        * object was constructed.
   66        */
   67       private InputStream stream;
   68   
   69       /**
   70        * The format of the audio data contained in the stream.
   71        */
   72       protected AudioFormat format;
   73   
   74       /**
   75        * This stream's length, in sample frames.
   76        */
   77       protected long frameLength;
   78   
   79       /**
   80        * The size of each frame, in bytes.
   81        */
   82       protected int frameSize;
   83   
   84       /**
   85        * The current position in this stream, in sample frames (zero-based).
   86        */
   87       protected long framePos;
   88   
   89       /**
   90        * The position where a mark was set.
   91        */
   92       private long markpos;
   93   
   94       /**
   95        * When the underlying stream could only return
   96        * a non-integral number of frames, store
   97        * the remainder in a temporary buffer
   98        */
   99       private byte[] pushBackBuffer = null;
  100   
  101       /**
  102        * number of valid bytes in the pushBackBuffer
  103        */
  104       private int pushBackLen = 0;
  105   
  106       /**
  107        * MarkBuffer at mark position
  108        */
  109       private byte[] markPushBackBuffer = null;
  110   
  111       /**
  112        * number of valid bytes in the markPushBackBuffer
  113        */
  114       private int markPushBackLen = 0;
  115   
  116   
  117       /**
  118        * Constructs an audio input stream that has the requested format and length in sample frames,
  119        * using audio data from the specified input stream.
  120        * @param stream the stream on which this <code>AudioInputStream</code>
  121        * object is based
  122        * @param format the format of this stream's audio data
  123        * @param length the length in sample frames of the data in this stream
  124        */
  125       public AudioInputStream(InputStream stream, AudioFormat format, long length) {
  126   
  127           super();
  128   
  129           this.format = format;
  130           this.frameLength = length;
  131           this.frameSize = format.getFrameSize();
  132   
  133           // any frameSize that is not well-defined will
  134           // cause that this stream will be read in bytes
  135           if( this.frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {
  136               this.frameSize = 1;
  137           }
  138   
  139           this.stream = stream;
  140           framePos = 0;
  141           markpos = 0;
  142       }
  143   
  144   
  145       /**
  146        * Constructs an audio input stream that reads its data from the target
  147        * data line indicated.  The format of the stream is the same as that of
  148        * the target data line, and the length is AudioSystem#NOT_SPECIFIED.
  149        * @param line the target data line from which this stream obtains its data.
  150        * @see AudioSystem#NOT_SPECIFIED
  151        */
  152       public AudioInputStream(TargetDataLine line) {
  153   
  154           TargetDataLineInputStream tstream = new TargetDataLineInputStream(line);
  155           format = line.getFormat();
  156           frameLength = AudioSystem.NOT_SPECIFIED;
  157           frameSize = format.getFrameSize();
  158   
  159           if( frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {
  160               frameSize = 1;
  161           }
  162           this.stream = tstream;
  163           framePos = 0;
  164           markpos = 0;
  165       }
  166   
  167   
  168       /**
  169        * Obtains the audio format of the sound data in this audio input stream.
  170        * @return an audio format object describing this stream's format
  171        */
  172       public AudioFormat getFormat() {
  173           return format;
  174       }
  175   
  176   
  177       /**
  178        * Obtains the length of the stream, expressed in sample frames rather than bytes.
  179        * @return the length in sample frames
  180        */
  181       public long getFrameLength() {
  182           return frameLength;
  183       }
  184   
  185   
  186       /**
  187        * Reads the next byte of data from the audio input stream.  The audio input
  188        * stream's frame size must be one byte, or an <code>IOException</code>
  189        * will be thrown.
  190        *
  191        * @return the next byte of data, or -1 if the end of the stream is reached
  192        * @throws IOException if an input or output error occurs
  193        * @see #read(byte[], int, int)
  194        * @see #read(byte[])
  195        * @see #available
  196        * <p>
  197        */
  198       public int read() throws IOException {
  199           if( frameSize != 1 ) {
  200               throw new IOException("cannot read a single byte if frame size > 1");
  201           }
  202   
  203           byte[] data = new byte[1];
  204           int temp = read(data);
  205           if (temp <= 0) {
  206               // we have a weird situation if read(byte[]) returns 0!
  207               return -1;
  208           }
  209           return data[0] & 0xFF;
  210       }
  211   
  212   
  213       /**
  214        * Reads some number of bytes from the audio input stream and stores them into
  215        * the buffer array <code>b</code>. The number of bytes actually read is
  216        * returned as an integer. This method blocks until input data is
  217        * available, the end of the stream is detected, or an exception is thrown.
  218        * <p>This method will always read an integral number of frames.
  219        * If the length of the array is not an integral number
  220        * of frames, a maximum of <code>b.length - (b.length % frameSize)
  221        * </code> bytes will be read.
  222        *
  223        * @param b the buffer into which the data is read
  224        * @return the total number of bytes read into the buffer, or -1 if there
  225        * is no more data because the end of the stream has been reached
  226        * @throws IOException if an input or output error occurs
  227        * @see #read(byte[], int, int)
  228        * @see #read()
  229        * @see #available
  230        */
  231       public int read(byte[] b) throws IOException {
  232           return read(b,0,b.length);
  233       }
  234   
  235   
  236       /**
  237        * Reads up to a specified maximum number of bytes of data from the audio
  238        * stream, putting them into the given byte array.
  239        * <p>This method will always read an integral number of frames.
  240        * If <code>len</code> does not specify an integral number
  241        * of frames, a maximum of <code>len - (len % frameSize)
  242        * </code> bytes will be read.
  243        *
  244        * @param b the buffer into which the data is read
  245        * @param off the offset, from the beginning of array <code>b</code>, at which
  246        * the data will be written
  247        * @param len the maximum number of bytes to read
  248        * @return the total number of bytes read into the buffer, or -1 if there
  249        * is no more data because the end of the stream has been reached
  250        * @throws IOException if an input or output error occurs
  251        * @see #read(byte[])
  252        * @see #read()
  253        * @see #skip
  254        * @see #available
  255        */
  256       public int read(byte[] b, int off, int len) throws IOException {
  257   
  258           // make sure we don't read fractions of a frame.
  259           if( (len%frameSize) != 0 ) {
  260               len -= (len%frameSize);
  261               if (len == 0) {
  262                   return 0;
  263               }
  264           }
  265   
  266           if( frameLength != AudioSystem.NOT_SPECIFIED ) {
  267               if( framePos >= frameLength ) {
  268                   return -1;
  269               } else {
  270   
  271                   // don't try to read beyond our own set length in frames
  272                   if( (len/frameSize) > (frameLength-framePos) ) {
  273                       len = (int) (frameLength-framePos) * frameSize;
  274                   }
  275               }
  276           }
  277   
  278           int bytesRead = 0;
  279           int thisOff = off;
  280   
  281           // if we've bytes left from last call to read(),
  282           // use them first
  283           if (pushBackLen > 0 && len >= pushBackLen) {
  284               System.arraycopy(pushBackBuffer, 0,
  285                                b, off, pushBackLen);
  286               thisOff += pushBackLen;
  287               len -= pushBackLen;
  288               bytesRead += pushBackLen;
  289               pushBackLen = 0;
  290           }
  291   
  292           int thisBytesRead = stream.read(b, thisOff, len);
  293           if (thisBytesRead == -1) {
  294               return -1;
  295           }
  296           if (thisBytesRead > 0) {
  297               bytesRead += thisBytesRead;
  298           }
  299           if (bytesRead > 0) {
  300               pushBackLen = bytesRead % frameSize;
  301               if (pushBackLen > 0) {
  302                   // copy everything we got from the beginning of the frame
  303                   // to our pushback buffer
  304                   if (pushBackBuffer == null) {
  305                       pushBackBuffer = new byte[frameSize];
  306                   }
  307                   System.arraycopy(b, off + bytesRead - pushBackLen,
  308                                    pushBackBuffer, 0, pushBackLen);
  309                   bytesRead -= pushBackLen;
  310               }
  311               // make sure to update our framePos
  312               framePos += bytesRead/frameSize;
  313           }
  314           return bytesRead;
  315       }
  316   
  317   
  318       /**
  319        * Skips over and discards a specified number of bytes from this
  320        * audio input stream.
  321        * @param n the requested number of bytes to be skipped
  322        * @return the actual number of bytes skipped
  323        * @throws IOException if an input or output error occurs
  324        * @see #read
  325        * @see #available
  326        */
  327       public long skip(long n) throws IOException {
  328   
  329           // make sure not to skip fractional frames
  330           if( (n%frameSize) != 0 ) {
  331               n -= (n%frameSize);
  332           }
  333   
  334           if( frameLength != AudioSystem.NOT_SPECIFIED ) {
  335               // don't skip more than our set length in frames.
  336               if( (n/frameSize) > (frameLength-framePos) ) {
  337                   n = (frameLength-framePos) * frameSize;
  338               }
  339           }
  340           long temp = stream.skip(n);
  341   
  342           // if no error, update our position.
  343           if( temp%frameSize != 0 ) {
  344   
  345               // Throw an IOException if we've skipped a fractional number of frames
  346               throw new IOException("Could not skip an integer number of frames.");
  347           }
  348           if( temp >= 0 ) {
  349               framePos += temp/frameSize;
  350           }
  351           return temp;
  352   
  353       }
  354   
  355   
  356       /**
  357        * Returns the maximum number of bytes that can be read (or skipped over) from this
  358        * audio input stream without blocking.  This limit applies only to the next invocation of
  359        * a <code>read</code> or <code>skip</code> method for this audio input stream; the limit
  360        * can vary each time these methods are invoked.
  361        * Depending on the underlying stream,an IOException may be thrown if this
  362        * stream is closed.
  363        * @return the number of bytes that can be read from this audio input stream without blocking
  364        * @throws IOException if an input or output error occurs
  365        * @see #read(byte[], int, int)
  366        * @see #read(byte[])
  367        * @see #read()
  368        * @see #skip
  369        */
  370       public int available() throws IOException {
  371   
  372           int temp = stream.available();
  373   
  374           // don't return greater than our set length in frames
  375           if( (frameLength != AudioSystem.NOT_SPECIFIED) && ( (temp/frameSize) > (frameLength-framePos)) ) {
  376               return (int) (frameLength-framePos) * frameSize;
  377           } else {
  378               return temp;
  379           }
  380       }
  381   
  382   
  383       /**
  384        * Closes this audio input stream and releases any system resources associated
  385        * with the stream.
  386        * @throws IOException if an input or output error occurs
  387        */
  388       public void close() throws IOException {
  389           stream.close();
  390       }
  391   
  392   
  393       /**
  394        * Marks the current position in this audio input stream.
  395        * @param readlimit the maximum number of bytes that can be read before
  396        * the mark position becomes invalid.
  397        * @see #reset
  398        * @see #markSupported
  399        */
  400   
  401       public void mark(int readlimit) {
  402   
  403           stream.mark(readlimit);
  404           if (markSupported()) {
  405               markpos = framePos;
  406               // remember the pushback buffer
  407               markPushBackLen = pushBackLen;
  408               if (markPushBackLen > 0) {
  409                   if (markPushBackBuffer == null) {
  410                       markPushBackBuffer = new byte[frameSize];
  411                   }
  412                   System.arraycopy(pushBackBuffer, 0, markPushBackBuffer, 0, markPushBackLen);
  413               }
  414           }
  415       }
  416   
  417   
  418       /**
  419        * Repositions this audio input stream to the position it had at the time its
  420        * <code>mark</code> method was last invoked.
  421        * @throws IOException if an input or output error occurs.
  422        * @see #mark
  423        * @see #markSupported
  424        */
  425       public void reset() throws IOException {
  426   
  427           stream.reset();
  428           framePos = markpos;
  429           // re-create the pushback buffer
  430           pushBackLen = markPushBackLen;
  431           if (pushBackLen > 0) {
  432               if (pushBackBuffer == null) {
  433                   pushBackBuffer = new byte[frameSize - 1];
  434               }
  435               System.arraycopy(markPushBackBuffer, 0, pushBackBuffer, 0, pushBackLen);
  436           }
  437       }
  438   
  439   
  440       /**
  441        * Tests whether this audio input stream supports the <code>mark</code> and
  442        * <code>reset</code> methods.
  443        * @return <code>true</code> if this stream supports the <code>mark</code>
  444        * and <code>reset</code> methods; <code>false</code> otherwise
  445        * @see #mark
  446        * @see #reset
  447        */
  448       public boolean markSupported() {
  449   
  450           return stream.markSupported();
  451       }
  452   
  453   
  454       /**
  455        * Private inner class that makes a TargetDataLine look like an InputStream.
  456        */
  457       private class TargetDataLineInputStream extends InputStream {
  458   
  459           /**
  460            * The TargetDataLine on which this TargetDataLineInputStream is based.
  461            */
  462           TargetDataLine line;
  463   
  464   
  465           TargetDataLineInputStream(TargetDataLine line) {
  466               super();
  467               this.line = line;
  468           }
  469   
  470   
  471           public int available() throws IOException {
  472               return line.available();
  473           }
  474   
  475           //$$fb 2001-07-16: added this method to correctly close the underlying TargetDataLine.
  476           // fixes bug 4479984
  477           public void close() throws IOException {
  478               // the line needs to be flushed and stopped to avoid a dead lock...
  479               // Probably related to bugs 4417527, 4334868, 4383457
  480               if (line.isActive()) {
  481                   line.flush();
  482                   line.stop();
  483               }
  484               line.close();
  485           }
  486   
  487           public int read() throws IOException {
  488   
  489               byte[] b = new byte[1];
  490   
  491               int value = read(b, 0, 1);
  492   
  493               if (value == -1) {
  494                   return -1;
  495               }
  496   
  497               value = (int)b[0];
  498   
  499               if (line.getFormat().getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) {
  500                   value += 128;
  501               }
  502   
  503               return value;
  504           }
  505   
  506   
  507           public int read(byte[] b, int off, int len) throws IOException {
  508               try {
  509                   return line.read(b, off, len);
  510               } catch (IllegalArgumentException e) {
  511                   throw new IOException(e.getMessage());
  512               }
  513           }
  514       }
  515   }

Save This Page
Home » openjdk-7 » javax.sound » sampled » [javadoc | source]