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