Path: blob/master/src/java.desktop/share/classes/javax/sound/sampled/AudioInputStream.java
41159 views
/*1* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sound.sampled;2627import java.io.IOException;28import java.io.InputStream;2930/**31* An audio input stream is an input stream with a specified audio format and32* length. The length is expressed in sample frames, not bytes. Several methods33* are provided for reading a certain number of bytes from the stream, or an34* unspecified number of bytes. The audio input stream keeps track of the last35* byte that was read. You can skip over an arbitrary number of bytes to get to36* a later position for reading. An audio input stream may support marks. When37* you set a mark, the current position is remembered so that you can return to38* it later.39* <p>40* The {@code AudioSystem} class includes many methods that manipulate41* {@code AudioInputStream} objects. For example, the methods let you:42* <ul>43* <li>obtain an audio input stream from an external audio file, stream, or44* {@code URL}45* <li>write an external file from an audio input stream46* <li>convert an audio input stream to a different audio format47* </ul>48*49* @author David Rivas50* @author Kara Kytle51* @author Florian Bomers52* @see AudioSystem53* @see Clip#open(AudioInputStream)54* @since 1.355*/56public class AudioInputStream extends InputStream {5758/**59* The {@code InputStream} from which this {@code AudioInputStream} object60* was constructed.61*/62private final InputStream stream;6364/**65* The format of the audio data contained in the stream.66*/67protected AudioFormat format;6869/**70* This stream's length, in sample frames.71*/72protected long frameLength;7374/**75* The size of each frame, in bytes.76*/77protected int frameSize;7879/**80* The current position in this stream, in sample frames (zero-based).81*/82protected long framePos;8384/**85* The position where a mark was set.86*/87private long markpos;8889/**90* When the underlying stream could only return a non-integral number of91* frames, store the remainder in a temporary buffer.92*/93private byte[] pushBackBuffer = null;9495/**96* number of valid bytes in the pushBackBuffer.97*/98private int pushBackLen = 0;99100/**101* MarkBuffer at mark position.102*/103private byte[] markPushBackBuffer = null;104105/**106* number of valid bytes in the markPushBackBuffer.107*/108private int markPushBackLen = 0;109110/**111* Constructs an audio input stream that has the requested format and length112* in sample frames, using audio data from the specified input stream.113*114* @param stream the stream on which this {@code AudioInputStream} object115* is based116* @param format the format of this stream's audio data117* @param length the length in sample frames of the data in this stream118*/119public AudioInputStream(InputStream stream, AudioFormat format, long length) {120121super();122123this.format = format;124this.frameLength = length;125this.frameSize = format.getFrameSize();126127// any frameSize that is not well-defined will128// cause that this stream will be read in bytes129if( this.frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {130this.frameSize = 1;131}132133this.stream = stream;134framePos = 0;135markpos = 0;136}137138/**139* Constructs an audio input stream that reads its data from the target data140* line indicated. The format of the stream is the same as that of the141* target data line, and the length is {@code AudioSystem#NOT_SPECIFIED}.142*143* @param line the target data line from which this stream obtains its data144* @see AudioSystem#NOT_SPECIFIED145*/146public AudioInputStream(TargetDataLine line) {147148TargetDataLineInputStream tstream = new TargetDataLineInputStream(line);149format = line.getFormat();150frameLength = AudioSystem.NOT_SPECIFIED;151frameSize = format.getFrameSize();152153if( frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {154frameSize = 1;155}156this.stream = tstream;157framePos = 0;158markpos = 0;159}160161/**162* Obtains the audio format of the sound data in this audio input stream.163*164* @return an audio format object describing this stream's format165*/166public AudioFormat getFormat() {167return format;168}169170/**171* Obtains the length of the stream, expressed in sample frames rather than172* bytes.173*174* @return the length in sample frames175*/176public long getFrameLength() {177return frameLength;178}179180/**181* Reads the next byte of data from the audio input stream. The audio input182* stream's frame size must be one byte, or an {@code IOException} will be183* thrown.184*185* @return the next byte of data, or -1 if the end of the stream is reached186* @throws IOException if an input or output error occurs187* @see #read(byte[], int, int)188* @see #read(byte[])189* @see #available190*/191@Override192public int read() throws IOException {193if( frameSize != 1 ) {194throw new IOException("cannot read a single byte if frame size > 1");195}196197byte[] data = new byte[1];198int temp = read(data);199if (temp <= 0) {200// we have a weird situation if read(byte[]) returns 0!201return -1;202}203return data[0] & 0xFF;204}205206/**207* Reads some number of bytes from the audio input stream and stores them208* into the buffer array {@code b}. The number of bytes actually read is209* returned as an integer. This method blocks until input data is available,210* the end of the stream is detected, or an exception is thrown.211* <p>212* This method will always read an integral number of frames. If the length213* of the array is not an integral number of frames, a maximum of214* {@code b.length - (b.length % frameSize)} bytes will be read.215*216* @param b the buffer into which the data is read217* @return the total number of bytes read into the buffer, or -1 if there is218* no more data because the end of the stream has been reached219* @throws IOException if an input or output error occurs220* @see #read(byte[], int, int)221* @see #read()222* @see #available223*/224@Override225public int read(byte[] b) throws IOException {226return read(b,0,b.length);227}228229/**230* Reads up to a specified maximum number of bytes of data from the audio231* stream, putting them into the given byte array.232* <p>233* This method will always read an integral number of frames. If {@code len}234* does not specify an integral number of frames, a maximum of235* {@code len - (len % frameSize)} bytes will be read.236*237* @param b the buffer into which the data is read238* @param off the offset, from the beginning of array {@code b}, at which239* the data will be written240* @param len the maximum number of bytes to read241* @return the total number of bytes read into the buffer, or -1 if there is242* no more data because the end of the stream has been reached243* @throws IOException if an input or output error occurs244* @see #read(byte[])245* @see #read()246* @see #skip247* @see #available248*/249@Override250public int read(byte[] b, int off, int len) throws IOException {251// make sure we don't read fractions of a frame.252final int reminder = len % frameSize;253if (reminder != 0) {254len -= reminder;255if (len == 0) {256return 0;257}258}259260if( frameLength != AudioSystem.NOT_SPECIFIED ) {261if( framePos >= frameLength ) {262return -1;263} else {264265// don't try to read beyond our own set length in frames266if( (len/frameSize) > (frameLength-framePos) ) {267len = (int) (frameLength-framePos) * frameSize;268}269}270}271272int bytesRead = 0;273int thisOff = off;274275// if we've bytes left from last call to read(),276// use them first277if (pushBackLen > 0 && len >= pushBackLen) {278System.arraycopy(pushBackBuffer, 0,279b, off, pushBackLen);280thisOff += pushBackLen;281len -= pushBackLen;282bytesRead += pushBackLen;283pushBackLen = 0;284}285286int thisBytesRead = stream.read(b, thisOff, len);287if (thisBytesRead == -1) {288return -1;289}290if (thisBytesRead > 0) {291bytesRead += thisBytesRead;292}293if (bytesRead > 0) {294pushBackLen = bytesRead % frameSize;295if (pushBackLen > 0) {296// copy everything we got from the beginning of the frame297// to our pushback buffer298if (pushBackBuffer == null) {299pushBackBuffer = new byte[frameSize];300}301System.arraycopy(b, off + bytesRead - pushBackLen,302pushBackBuffer, 0, pushBackLen);303bytesRead -= pushBackLen;304}305// make sure to update our framePos306framePos += bytesRead/frameSize;307}308return bytesRead;309}310311/**312* Skips over and discards a specified number of bytes from this audio input313* stream.314* <p>315* This method will always skip an integral number of frames. If {@code n}316* does not specify an integral number of frames, a maximum of317* {@code n - (n % frameSize)} bytes will be skipped.318*319* @param n the requested number of bytes to be skipped320* @return the actual number of bytes skipped321* @throws IOException if an input or output error occurs322* @see #read323* @see #available324*/325@Override326public long skip(long n) throws IOException {327// make sure not to skip fractional frames328final long reminder = n % frameSize;329if (reminder != 0) {330n -= reminder;331}332if (n <= 0) {333return 0;334}335336if (frameLength != AudioSystem.NOT_SPECIFIED) {337// don't skip more than our set length in frames.338if ((n / frameSize) > (frameLength - framePos)) {339n = (frameLength - framePos) * frameSize;340}341}342long remaining = n;343while (remaining > 0) {344// Some input streams like FileInputStream can return more bytes,345// when EOF is reached.346long ret = Math.min(stream.skip(remaining), remaining);347if (ret == 0) {348// EOF or not? we need to check.349if (stream.read() == -1) {350break;351}352ret = 1;353} else if (ret < 0) {354// the skip should not return negative value, but check it also355break;356}357remaining -= ret;358}359final long temp = n - remaining;360361// if no error, update our position.362if (temp % frameSize != 0) {363// Throw an IOException if we've skipped a fractional number of frames364throw new IOException("Could not skip an integer number of frames.");365}366framePos += temp/frameSize;367return temp;368}369370/**371* Returns the maximum number of bytes that can be read (or skipped over)372* from this audio input stream without blocking. This limit applies only to373* the next invocation of a {@code read} or {@code skip} method for this374* audio input stream; the limit can vary each time these methods are375* invoked. Depending on the underlying stream, an {@code IOException} may376* be thrown if this stream is closed.377*378* @return the number of bytes that can be read from this audio input stream379* without blocking380* @throws IOException if an input or output error occurs381* @see #read(byte[], int, int)382* @see #read(byte[])383* @see #read()384* @see #skip385*/386@Override387public int available() throws IOException {388389int temp = stream.available();390391// don't return greater than our set length in frames392if( (frameLength != AudioSystem.NOT_SPECIFIED) && ( (temp/frameSize) > (frameLength-framePos)) ) {393return (int) (frameLength-framePos) * frameSize;394} else {395return temp;396}397}398399/**400* Closes this audio input stream and releases any system resources401* associated with the stream.402*403* @throws IOException if an input or output error occurs404*/405@Override406public void close() throws IOException {407stream.close();408}409410/**411* Marks the current position in this audio input stream.412*413* @param readlimit the maximum number of bytes that can be read before the414* mark position becomes invalid415* @see #reset416* @see #markSupported417*/418@Override419public void mark(int readlimit) {420421stream.mark(readlimit);422if (markSupported()) {423markpos = framePos;424// remember the pushback buffer425markPushBackLen = pushBackLen;426if (markPushBackLen > 0) {427if (markPushBackBuffer == null) {428markPushBackBuffer = new byte[frameSize];429}430System.arraycopy(pushBackBuffer, 0, markPushBackBuffer, 0, markPushBackLen);431}432}433}434435/**436* Repositions this audio input stream to the position it had at the time437* its {@code mark} method was last invoked.438*439* @throws IOException if an input or output error occurs440* @see #mark441* @see #markSupported442*/443@Override444public void reset() throws IOException {445446stream.reset();447framePos = markpos;448// re-create the pushback buffer449pushBackLen = markPushBackLen;450if (pushBackLen > 0) {451if (pushBackBuffer == null) {452pushBackBuffer = new byte[frameSize - 1];453}454System.arraycopy(markPushBackBuffer, 0, pushBackBuffer, 0, pushBackLen);455}456}457458/**459* Tests whether this audio input stream supports the {@code mark} and460* {@code reset} methods.461*462* @return {@code true} if this stream supports the {@code mark} and463* {@code reset} methods; {@code false} otherwise464* @see #mark465* @see #reset466*/467@Override468public boolean markSupported() {469470return stream.markSupported();471}472473/**474* Private inner class that makes a TargetDataLine look like an InputStream.475*/476private class TargetDataLineInputStream extends InputStream {477478/**479* The TargetDataLine on which this TargetDataLineInputStream is based.480*/481TargetDataLine line;482483TargetDataLineInputStream(TargetDataLine line) {484super();485this.line = line;486}487488@Override489public int available() throws IOException {490return line.available();491}492493//$$fb 2001-07-16: added this method to correctly close the underlying TargetDataLine.494// fixes bug 4479984495@Override496public void close() throws IOException {497// the line needs to be flushed and stopped to avoid a dead lock...498// Probably related to bugs 4417527, 4334868, 4383457499if (line.isActive()) {500line.flush();501line.stop();502}503line.close();504}505506@Override507public int read() throws IOException {508509byte[] b = new byte[1];510511int value = read(b, 0, 1);512513if (value == -1) {514return -1;515}516517value = (int)b[0];518519if (line.getFormat().getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) {520value += 128;521}522523return value;524}525526@Override527public int read(byte[] b, int off, int len) throws IOException {528try {529return line.read(b, off, len);530} catch (IllegalArgumentException e) {531throw new IOException(e.getMessage());532}533}534}535}536537538