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