KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > sound > sampled > AudioInputStream


1 /*
2  * @(#)AudioInputStream.java 1.32 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.sound.sampled;
9
10 import java.io.InputStream JavaDoc;
11 import java.io.PushbackInputStream JavaDoc;
12 import java.io.IOException JavaDoc;
13
14
15 /**
16  * An audio input stream is an input stream with a specified audio format and
17  * length. The length is expressed in sample frames, not bytes.
18  * Several methods are provided for reading a certain number of bytes from
19  * the stream, or an unspecified number of bytes.
20  * The audio input stream keeps track of the last byte that was read.
21  * You can skip over an arbitrary number of bytes to get to a later position
22  * for reading. An audio input stream may support marks. When you set a mark,
23  * the current position is remembered so that you can return to it later.
24  * <p>
25  * The <code>AudioSystem</code> class includes many methods that manipulate
26  * <code>AudioInputStream</code> objects.
27  * For example, the methods let you:
28  * <ul>
29  * <li> obtain an
30  * audio input stream from an external audio file, stream, or URL
31  * <li> write an external file from an audio input stream
32  * <li> convert an audio input stream to a different audio format
33  * </ul>
34  *
35  * @author David Rivas
36  * @author Kara Kytle
37  * @author Florian Bomers
38  * @version 1.32, 03/12/19
39  *
40  * @see AudioSystem
41  * @see Clip#open(AudioInputStream) Clip.open(AudioInputStream)
42  * @since 1.3
43  */

44 public class AudioInputStream extends InputStream JavaDoc {
45
46     /**
47      * The <code>InputStream</code> from which this <code>AudioInputStream</code>
48      * object was constructed.
49      */

50     private InputStream JavaDoc stream;
51
52     /**
53      * The format of the audio data contained in the stream.
54      */

55     protected AudioFormat JavaDoc format;
56
57     /**
58      * This stream's length, in sample frames.
59      */

60     protected long frameLength;
61
62     /**
63      * The size of each frame, in bytes.
64      */

65     protected int frameSize;
66
67     /**
68      * The current position in this stream, in sample frames (zero-based).
69      */

70     protected long framePos;
71
72     /**
73      * The position where a mark was set.
74      */

75     private long markpos;
76     
77     /**
78      * When the underlying stream could only return
79      * a non-integral number of frames, store
80      * the remainder in a temporary buffer
81      */

82     private byte[] pushBackBuffer = null;
83     
84     /**
85      * number of valid bytes in the pushBackBuffer
86      */

87     private int pushBackLen = 0;
88     
89     /**
90      * MarkBuffer at mark position
91      */

92     private byte[] markPushBackBuffer = null;
93     
94     /**
95      * number of valid bytes in the markPushBackBuffer
96      */

97     private int markPushBackLen = 0;
98     
99
100     /**
101      * Constructs an audio input stream that has the requested format and length in sample frames,
102      * using audio data from the specified input stream.
103      * @param stream the stream on which this <code>AudioInputStream</code>
104      * object is based
105      * @param format the format of this stream's audio data
106      * @param length the length in sample frames of the data in this stream
107      */

108     public AudioInputStream(InputStream JavaDoc stream, AudioFormat JavaDoc format, long length) {
109
110     super();
111
112     this.format = format;
113     this.frameLength = length;
114     this.frameSize = format.getFrameSize();
115
116     // any frameSize that is not well-defined will
117
// cause that this stream will be read in bytes
118
if( this.frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {
119         this.frameSize = 1;
120     }
121
122     this.stream = stream;
123     framePos = 0;
124     markpos = 0;
125     }
126
127
128     /**
129      * Constructs an audio input stream that reads its data from the target
130      * data line indicated. The format of the stream is the same as that of
131      * the target data line, and the length is AudioSystem#NOT_SPECIFIED.
132      * @param line the target data line from which this stream obtains its data.
133      * @see AudioSystem#NOT_SPECIFIED
134      */

135     public AudioInputStream(TargetDataLine JavaDoc line) {
136
137     TargetDataLineInputStream tstream = new TargetDataLineInputStream(line);
138     format = line.getFormat();
139     frameLength = AudioSystem.NOT_SPECIFIED;
140     frameSize = format.getFrameSize();
141
142     if( frameSize == AudioSystem.NOT_SPECIFIED || frameSize <= 0) {
143         frameSize = 1;
144     }
145     this.stream = tstream;
146     framePos = 0;
147     markpos = 0;
148     }
149
150
151     /**
152      * Obtains the audio format of the sound data in this audio input stream.
153      * @return an audio format object describing this stream's format
154      */

155     public AudioFormat JavaDoc getFormat() {
156     return format;
157     }
158
159
160     /**
161      * Obtains the length of the stream, expressed in sample frames rather than bytes.
162      * @return the length in sample frames
163      */

164     public long getFrameLength() {
165     return frameLength;
166     }
167
168
169     /**
170      * Reads the next byte of data from the audio input stream. The audio input
171      * stream's frame size must be one byte, or an <code>IOException</code>
172      * will be thrown.
173      *
174      * @return the next byte of data, or -1 if the end of the stream is reached
175      * @throws IOException if an input or output error occurs
176      * @see #read(byte[], int, int)
177      * @see #read(byte[])
178      * @see #available
179      * <p>
180      */

181     public int read() throws IOException JavaDoc {
182     if( frameSize != 1 ) {
183         throw new IOException JavaDoc("cannot read a single byte if frame size > 1");
184     }
185
186     byte[] data = new byte[1];
187     int temp = read(data);
188     if (temp <= 0) {
189         // we have a weird situation if read(byte[]) returns 0!
190
return -1;
191     }
192         return temp & 0xFF;
193     }
194
195
196     /**
197      * Reads some number of bytes from the audio input stream and stores them into
198      * the buffer array <code>b</code>. The number of bytes actually read is
199      * returned as an integer. This method blocks until input data is
200      * available, the end of the stream is detected, or an exception is thrown.
201      * <p>This method will always read an integral number of frames.
202      * If the length of the array is not an integral number
203      * of frames, a maximum of <code>b.length - (b.length % frameSize)
204      * </code> bytes will be read.
205      *
206      * @param b the buffer into which the data is read
207      * @return the total number of bytes read into the buffer, or -1 if there
208      * is no more data because the end of the stream has been reached
209      * @throws IOException if an input or output error occurs
210      * @see #read(byte[], int, int)
211      * @see #read()
212      * @see #available
213      */

214     public int read(byte[] b) throws IOException JavaDoc {
215     return read(b,0,b.length);
216     }
217
218
219     /**
220      * Reads up to a specified maximum number of bytes of data from the audio
221      * stream, putting them into the given byte array.
222      * <p>This method will always read an integral number of frames.
223      * If <code>len</code> does not specify an integral number
224      * of frames, a maximum of <code>len - (len % frameSize)
225      * </code> bytes will be read.
226      *
227      * @param b the buffer into which the data is read
228      * @param off the offset, from the beginning of array <code>b</code>, at which
229      * the data will be written
230      * @param len the maximum number of bytes to read
231      * @return the total number of bytes read into the buffer, or -1 if there
232      * is no more data because the end of the stream has been reached
233      * @throws IOException if an input or output error occurs
234      * @see #read(byte[])
235      * @see #read()
236      * @see #skip
237      * @see #available
238      */

239     public int read(byte[] b, int off, int len) throws IOException JavaDoc {
240
241     // make sure we don't read fractions of a frame.
242
if( (len%frameSize) != 0 ) {
243         len -= (len%frameSize);
244         if (len == 0) {
245             return 0;
246         }
247     }
248
249     if( frameLength != AudioSystem.NOT_SPECIFIED ) {
250         if( framePos >= frameLength ) {
251         return -1;
252         } else {
253
254         // don't try to read beyond our own set length in frames
255
if( (len/frameSize) > (frameLength-framePos) ) {
256             len = (int) (frameLength-framePos) * frameSize;
257         }
258         }
259     }
260     
261     int bytesRead = 0;
262     int thisOff = off;
263     
264     // if we've bytes left from last call to read(),
265
// use them first
266
if (pushBackLen > 0 && len >= pushBackLen) {
267         System.arraycopy(pushBackBuffer, 0,
268                          b, off, pushBackLen);
269         thisOff += pushBackLen;
270         len -= pushBackLen;
271         bytesRead += pushBackLen;
272         pushBackLen = 0;
273     }
274     
275     int thisBytesRead = stream.read(b, thisOff, len);
276     if (thisBytesRead == -1) {
277         return -1;
278     }
279     if (thisBytesRead > 0) {
280         bytesRead += thisBytesRead;
281     }
282     if (bytesRead > 0) {
283         pushBackLen = bytesRead % frameSize;
284         if (pushBackLen > 0) {
285         // copy everything we got from the beginning of the frame
286
// to our pushback buffer
287
if (pushBackBuffer == null) {
288             pushBackBuffer = new byte[frameSize];
289         }
290         System.arraycopy(b, off + bytesRead - pushBackLen,
291                          pushBackBuffer, 0, pushBackLen);
292         bytesRead -= pushBackLen;
293         }
294         // make sure to update our framePos
295
framePos += bytesRead/frameSize;
296     }
297     return bytesRead;
298     }
299
300
301     /**
302      * Skips over and discards a specified number of bytes from this
303      * audio input stream.
304      * @param n the requested number of bytes to be skipped
305      * @return the actual number of bytes skipped
306      * @throws IOException if an input or output error occurs
307      * @see #read
308      * @see #available
309      */

310     public long skip(long n) throws IOException JavaDoc {
311
312     // make sure not to skip fractional frames
313
if( (n%frameSize) != 0 ) {
314         n -= (n%frameSize);
315     }
316
317     if( frameLength != AudioSystem.NOT_SPECIFIED ) {
318         // don't skip more than our set length in frames.
319
if( (n/frameSize) > (frameLength-framePos) ) {
320         n = (frameLength-framePos) * frameSize;
321         }
322     }
323     long temp = stream.skip(n);
324
325     // if no error, update our position.
326
if( temp%frameSize != 0 ) {
327
328         // Throw an IOException if we've skipped a fractional number of frames
329
throw new IOException JavaDoc("Could not skip an integer number of frames.");
330     }
331     if( temp >= 0 ) {
332         framePos += temp/frameSize;
333     }
334     return temp;
335
336     }
337
338
339     /**
340      * Returns the maximum number of bytes that can be read (or skipped over) from this
341      * audio input stream without blocking. This limit applies only to the next invocation of
342      * a <code>read</code> or <code>skip</code> method for this audio input stream; the limit
343      * can vary each time these methods are invoked.
344      * Depending on the underlying stream,an IOException may be thrown if this
345      * stream is closed.
346      * @return the number of bytes that can be read from this audio input stream without blocking
347      * @throws IOException if an input or output error occurs
348      * @see #read(byte[], int, int)
349      * @see #read(byte[])
350      * @see #read()
351      * @see #skip
352      */

353     public int available() throws IOException JavaDoc {
354
355     int temp = stream.available();
356
357     // don't return greater than our set length in frames
358
if( (frameLength != AudioSystem.NOT_SPECIFIED) && ( (temp/frameSize) > (frameLength-framePos)) ) {
359         return (int) (frameLength-framePos) * frameSize;
360     } else {
361         return temp;
362     }
363     }
364
365
366     /**
367      * Closes this audio input stream and releases any system resources associated
368      * with the stream.
369      * @throws IOException if an input or output error occurs
370      */

371     public void close() throws IOException JavaDoc {
372     stream.close();
373     }
374
375
376     /**
377      * Marks the current position in this audio input stream.
378      * @param readlimit the maximum number of bytes that can be read before
379      * the mark position becomes invalid.
380      * @see #reset
381      * @see #markSupported
382      */

383
384     public void mark(int readlimit) {
385
386     stream.mark(readlimit);
387     if (markSupported()) {
388         markpos = framePos;
389         // remember the pushback buffer
390
markPushBackLen = pushBackLen;
391         if (markPushBackLen > 0) {
392         if (markPushBackBuffer == null) {
393             markPushBackBuffer = new byte[frameSize];
394         }
395         System.arraycopy(pushBackBuffer, 0, markPushBackBuffer, 0, markPushBackLen);
396         }
397     }
398     }
399
400
401     /**
402      * Repositions this audio input stream to the position it had at the time its
403      * <code>mark</code> method was last invoked.
404      * @throws IOException if an input or output error occurs.
405      * @see #mark
406      * @see #markSupported
407      */

408     public void reset() throws IOException JavaDoc {
409
410     stream.reset();
411     framePos = markpos;
412     // re-create the pushback buffer
413
pushBackLen = markPushBackLen;
414     if (pushBackLen > 0) {
415         if (pushBackBuffer == null) {
416         pushBackBuffer = new byte[frameSize - 1];
417         }
418         System.arraycopy(markPushBackBuffer, 0, pushBackBuffer, 0, pushBackLen);
419     }
420     }
421
422
423     /**
424      * Tests whether this audio input stream supports the <code>mark</code> and
425      * <code>reset</code> methods.
426      * @return <code>true</code> if this stream supports the <code>mark</code>
427      * and <code>reset</code> methods; <code>false</code> otherwise
428      * @see #mark
429      * @see #reset
430      */

431     public boolean markSupported() {
432
433     return stream.markSupported();
434     }
435
436
437     /**
438      * Private inner class that makes a TargetDataLine look like an InputStream.
439      */

440     private class TargetDataLineInputStream extends InputStream JavaDoc {
441
442     /**
443      * The TargetDataLine on which this TargetDataLineInputStream is based.
444      */

445     TargetDataLine JavaDoc line;
446
447
448     TargetDataLineInputStream(TargetDataLine JavaDoc line) {
449         super();
450         this.line = line;
451     }
452
453
454     public int available() throws IOException JavaDoc {
455         return line.available();
456     }
457
458     //$$fb 2001-07-16: added this method to correctly close the underlying TargetDataLine.
459
// fixes bug 4479984
460
public void close() throws IOException JavaDoc {
461         // the line needs to be flushed and stopped to avoid a dead lock...
462
// Probably related to bugs 4417527, 4334868, 4383457
463
if (line.isActive()) {
464         line.flush();
465         line.stop();
466         }
467         line.close();
468     }
469
470     public int read() throws IOException JavaDoc {
471         
472         byte[] b = new byte[1];
473         
474         int value = read(b, 0, 1);
475         
476         if (value == -1) {
477         return -1;
478         }
479         
480         value = (int)b[0];
481         
482         if (line.getFormat().getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) {
483         value += 128;
484         }
485
486         return value;
487     }
488
489
490     public int read(byte[] b, int off, int len) throws IOException JavaDoc {
491         try {
492         return line.read(b, off, len);
493         } catch (IllegalArgumentException JavaDoc e) {
494         throw new IOException JavaDoc(e.getMessage());
495         }
496     }
497     }
498 }
499
Popular Tags