001 /*
002 * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.sound.sampled;
027
028 import java.io.InputStream;
029 import java.io.PushbackInputStream;
030 import java.io.IOException;
031
032 /**
033 * An audio input stream is an input stream with a specified audio format and
034 * length. The length is expressed in sample frames, not bytes.
035 * Several methods are provided for reading a certain number of bytes from
036 * the stream, or an unspecified number of bytes.
037 * The audio input stream keeps track of the last byte that was read.
038 * You can skip over an arbitrary number of bytes to get to a later position
039 * for reading. An audio input stream may support marks. When you set a mark,
040 * the current position is remembered so that you can return to it later.
041 * <p>
042 * The <code>AudioSystem</code> class includes many methods that manipulate
043 * <code>AudioInputStream</code> objects.
044 * For example, the methods let you:
045 * <ul>
046 * <li> obtain an
047 * audio input stream from an external audio file, stream, or URL
048 * <li> write an external file from an audio input stream
049 * <li> convert an audio input stream to a different audio format
050 * </ul>
051 *
052 * @author David Rivas
053 * @author Kara Kytle
054 * @author Florian Bomers
055 * @version 1.40, 07/05/05
056 *
057 * @see AudioSystem
058 * @see Clip#open(AudioInputStream) Clip.open(AudioInputStream)
059 * @since 1.3
060 */
061 public class AudioInputStream extends InputStream {
062
063 /**
064 * The <code>InputStream</code> from which this <code>AudioInputStream</code>
065 * object was constructed.
066 */
067 private InputStream stream;
068
069 /**
070 * The format of the audio data contained in the stream.
071 */
072 protected AudioFormat format;
073
074 /**
075 * This stream's length, in sample frames.
076 */
077 protected long frameLength;
078
079 /**
080 * The size of each frame, in bytes.
081 */
082 protected int frameSize;
083
084 /**
085 * The current position in this stream, in sample frames (zero-based).
086 */
087 protected long framePos;
088
089 /**
090 * The position where a mark was set.
091 */
092 private long markpos;
093
094 /**
095 * When the underlying stream could only return
096 * a non-integral number of frames, store
097 * the remainder in a temporary buffer
098 */
099 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 * Constructs an audio input stream that has the requested format and length in sample frames,
118 * using audio data from the specified input stream.
119 * @param stream the stream on which this <code>AudioInputStream</code>
120 * object is based
121 * @param format the format of this stream's audio data
122 * @param length the length in sample frames of the data in this stream
123 */
124 public AudioInputStream(InputStream stream, AudioFormat format,
125 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
136 || frameSize <= 0) {
137 this .frameSize = 1;
138 }
139
140 this .stream = stream;
141 framePos = 0;
142 markpos = 0;
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(
155 line);
156 format = line.getFormat();
157 frameLength = AudioSystem.NOT_SPECIFIED;
158 frameSize = format.getFrameSize();
159
160 if (frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {
161 frameSize = 1;
162 }
163 this .stream = tstream;
164 framePos = 0;
165 markpos = 0;
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 * Obtains the length of the stream, expressed in sample frames rather than bytes.
178 * @return the length in sample frames
179 */
180 public long getFrameLength() {
181 return frameLength;
182 }
183
184 /**
185 * Reads the next byte of data from the audio input stream. The audio input
186 * stream's frame size must be one byte, or an <code>IOException</code>
187 * will be thrown.
188 *
189 * @return the next byte of data, or -1 if the end of the stream is reached
190 * @throws IOException if an input or output error occurs
191 * @see #read(byte[], int, int)
192 * @see #read(byte[])
193 * @see #available
194 * <p>
195 */
196 public int read() throws IOException {
197 if (frameSize != 1) {
198 throw new IOException(
199 "cannot read a single byte if frame size > 1");
200 }
201
202 byte[] data = new byte[1];
203 int temp = read(data);
204 if (temp <= 0) {
205 // we have a weird situation if read(byte[]) returns 0!
206 return -1;
207 }
208 return data[0] & 0xFF;
209 }
210
211 /**
212 * Reads some number of bytes from the audio input stream and stores them into
213 * the buffer array <code>b</code>. The number of bytes actually read is
214 * returned as an integer. This method blocks until input data is
215 * available, the end of the stream is detected, or an exception is thrown.
216 * <p>This method will always read an integral number of frames.
217 * If the length of the array is not an integral number
218 * of frames, a maximum of <code>b.length - (b.length % frameSize)
219 * </code> bytes will be read.
220 *
221 * @param b the buffer into which the data is read
222 * @return the total number of bytes read into the buffer, or -1 if there
223 * is no more data because the end of the stream has been reached
224 * @throws IOException if an input or output error occurs
225 * @see #read(byte[], int, int)
226 * @see #read()
227 * @see #available
228 */
229 public int read(byte[] b) throws IOException {
230 return read(b, 0, b.length);
231 }
232
233 /**
234 * Reads up to a specified maximum number of bytes of data from the audio
235 * stream, putting them into the given byte array.
236 * <p>This method will always read an integral number of frames.
237 * If <code>len</code> does not specify an integral number
238 * of frames, a maximum of <code>len - (len % frameSize)
239 * </code> bytes will be read.
240 *
241 * @param b the buffer into which the data is read
242 * @param off the offset, from the beginning of array <code>b</code>, at which
243 * the data will be written
244 * @param len the maximum number of bytes to read
245 * @return the total number of bytes read into the buffer, or -1 if there
246 * is no more data because the end of the stream has been reached
247 * @throws IOException if an input or output error occurs
248 * @see #read(byte[])
249 * @see #read()
250 * @see #skip
251 * @see #available
252 */
253 public int read(byte[] b, int off, int len) throws IOException {
254
255 // make sure we don't read fractions of a frame.
256 if ((len % frameSize) != 0) {
257 len -= (len % frameSize);
258 if (len == 0) {
259 return 0;
260 }
261 }
262
263 if (frameLength != AudioSystem.NOT_SPECIFIED) {
264 if (framePos >= frameLength) {
265 return -1;
266 } else {
267
268 // don't try to read beyond our own set length in frames
269 if ((len / frameSize) > (frameLength - framePos)) {
270 len = (int) (frameLength - framePos) * frameSize;
271 }
272 }
273 }
274
275 int bytesRead = 0;
276 int this Off = off;
277
278 // if we've bytes left from last call to read(),
279 // use them first
280 if (pushBackLen > 0 && len >= pushBackLen) {
281 System.arraycopy(pushBackBuffer, 0, b, off, pushBackLen);
282 this Off += pushBackLen;
283 len -= pushBackLen;
284 bytesRead += pushBackLen;
285 pushBackLen = 0;
286 }
287
288 int this BytesRead = stream.read(b, this Off, len);
289 if (this BytesRead == -1) {
290 return -1;
291 }
292 if (this BytesRead > 0) {
293 bytesRead += this BytesRead;
294 }
295 if (bytesRead > 0) {
296 pushBackLen = bytesRead % frameSize;
297 if (pushBackLen > 0) {
298 // copy everything we got from the beginning of the frame
299 // to our pushback buffer
300 if (pushBackBuffer == null) {
301 pushBackBuffer = new byte[frameSize];
302 }
303 System.arraycopy(b, off + bytesRead - pushBackLen,
304 pushBackBuffer, 0, pushBackLen);
305 bytesRead -= pushBackLen;
306 }
307 // make sure to update our framePos
308 framePos += bytesRead / frameSize;
309 }
310 return bytesRead;
311 }
312
313 /**
314 * Skips over and discards a specified number of bytes from this
315 * audio input stream.
316 * @param n the requested number of bytes to be skipped
317 * @return the actual number of bytes skipped
318 * @throws IOException if an input or output error occurs
319 * @see #read
320 * @see #available
321 */
322 public long skip(long n) throws IOException {
323
324 // make sure not to skip fractional frames
325 if ((n % frameSize) != 0) {
326 n -= (n % frameSize);
327 }
328
329 if (frameLength != AudioSystem.NOT_SPECIFIED) {
330 // don't skip more than our set length in frames.
331 if ((n / frameSize) > (frameLength - framePos)) {
332 n = (frameLength - framePos) * frameSize;
333 }
334 }
335 long temp = stream.skip(n);
336
337 // if no error, update our position.
338 if (temp % frameSize != 0) {
339
340 // Throw an IOException if we've skipped a fractional number of frames
341 throw new IOException(
342 "Could not skip an integer number of frames.");
343 }
344 if (temp >= 0) {
345 framePos += temp / frameSize;
346 }
347 return temp;
348
349 }
350
351 /**
352 * Returns the maximum number of bytes that can be read (or skipped over) from this
353 * audio input stream without blocking. This limit applies only to the next invocation of
354 * a <code>read</code> or <code>skip</code> method for this audio input stream; the limit
355 * can vary each time these methods are invoked.
356 * Depending on the underlying stream,an IOException may be thrown if this
357 * stream is closed.
358 * @return the number of bytes that can be read from this audio input stream without blocking
359 * @throws IOException if an input or output error occurs
360 * @see #read(byte[], int, int)
361 * @see #read(byte[])
362 * @see #read()
363 * @see #skip
364 */
365 public int available() throws IOException {
366
367 int temp = stream.available();
368
369 // don't return greater than our set length in frames
370 if ((frameLength != AudioSystem.NOT_SPECIFIED)
371 && ((temp / frameSize) > (frameLength - framePos))) {
372 return (int) (frameLength - framePos) * frameSize;
373 } else {
374 return temp;
375 }
376 }
377
378 /**
379 * Closes this audio input stream and releases any system resources associated
380 * with the stream.
381 * @throws IOException if an input or output error occurs
382 */
383 public void close() throws IOException {
384 stream.close();
385 }
386
387 /**
388 * Marks the current position in this audio input stream.
389 * @param readlimit the maximum number of bytes that can be read before
390 * the mark position becomes invalid.
391 * @see #reset
392 * @see #markSupported
393 */
394
395 public void mark(int readlimit) {
396
397 stream.mark(readlimit);
398 if (markSupported()) {
399 markpos = framePos;
400 // remember the pushback buffer
401 markPushBackLen = pushBackLen;
402 if (markPushBackLen > 0) {
403 if (markPushBackBuffer == null) {
404 markPushBackBuffer = new byte[frameSize];
405 }
406 System.arraycopy(pushBackBuffer, 0, markPushBackBuffer,
407 0, markPushBackLen);
408 }
409 }
410 }
411
412 /**
413 * Repositions this audio input stream to the position it had at the time its
414 * <code>mark</code> method was last invoked.
415 * @throws IOException if an input or output error occurs.
416 * @see #mark
417 * @see #markSupported
418 */
419 public void reset() throws IOException {
420
421 stream.reset();
422 framePos = markpos;
423 // re-create the pushback buffer
424 pushBackLen = markPushBackLen;
425 if (pushBackLen > 0) {
426 if (pushBackBuffer == null) {
427 pushBackBuffer = new byte[frameSize - 1];
428 }
429 System.arraycopy(markPushBackBuffer, 0, pushBackBuffer, 0,
430 pushBackLen);
431 }
432 }
433
434 /**
435 * Tests whether this audio input stream supports the <code>mark</code> and
436 * <code>reset</code> methods.
437 * @return <code>true</code> if this stream supports the <code>mark</code>
438 * and <code>reset</code> methods; <code>false</code> otherwise
439 * @see #mark
440 * @see #reset
441 */
442 public boolean markSupported() {
443
444 return stream.markSupported();
445 }
446
447 /**
448 * Private inner class that makes a TargetDataLine look like an InputStream.
449 */
450 private class TargetDataLineInputStream extends InputStream {
451
452 /**
453 * The TargetDataLine on which this TargetDataLineInputStream is based.
454 */
455 TargetDataLine line;
456
457 TargetDataLineInputStream(TargetDataLine line) {
458 super ();
459 this .line = line;
460 }
461
462 public int available() throws IOException {
463 return line.available();
464 }
465
466 //$$fb 2001-07-16: added this method to correctly close the underlying TargetDataLine.
467 // fixes bug 4479984
468 public void close() throws IOException {
469 // the line needs to be flushed and stopped to avoid a dead lock...
470 // Probably related to bugs 4417527, 4334868, 4383457
471 if (line.isActive()) {
472 line.flush();
473 line.stop();
474 }
475 line.close();
476 }
477
478 public int read() throws IOException {
479
480 byte[] b = new byte[1];
481
482 int value = read(b, 0, 1);
483
484 if (value == -1) {
485 return -1;
486 }
487
488 value = (int) b[0];
489
490 if (line.getFormat().getEncoding().equals(
491 AudioFormat.Encoding.PCM_SIGNED)) {
492 value += 128;
493 }
494
495 return value;
496 }
497
498 public int read(byte[] b, int off, int len) throws IOException {
499 try {
500 return line.read(b, off, len);
501 } catch (IllegalArgumentException e) {
502 throw new IOException(e.getMessage());
503 }
504 }
505 }
506 }
|