So my following code snippet (the concat method) mainly tries to do two things:
- Concatenate multiple AudioInputStream, read from a list of source files, into one final long stream
Write that stream into a destination WAV file
public static void concat(ArrayList<String> sourceFiles, String targetFile) { AudioInputStream targetBuilder = null; String file; AudioInputStream nextSource; for (int i = 0; i < sourceFiles.size(); i++) { file = sourceFiles.get(i); if(targetBuilder == null) { targetBuilder = AudioSystem.getAudioInputStream(new File(file)); continue; } nextSource = AudioSystem.getAudioInputStream(new File(file)); AudioInputStream appendedFiles = new AudioInputStream( new SequenceInputStream(targetBuilder, nextSource), targetBuilder.getFormat(), targetBuilder.getFrameLength() + nextSource.getFrameLength()); targetBuilder = appendedFiles; nextSource.close(); } AudioSystem.write(targetBuilder, AudioFileFormat.Type.WAVE, new File(targetFile)); targetBuilder.close(); }
This idea is borrowed from this thread: Join two WAV files from Java. Now the problem is after executing this snippet consecutively several times, eventually it will throw IO Exception on "stream closed" on the line of AudioSystem.write(). The stack trace looks like this:
java.io.IOException: Stream Closed
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:272)
at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
at java.io.SequenceInputStream.read(SequenceInputStream.java:211)
at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
......//with the exact same two lines repeating lots of times
at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
at javax.sound.sampled.AudioInputStream.read(AudioInputStream.java:292)
at com.sun.media.sound.SunFileWriter$NoCloseInputStream.read(SunFileWriter.java:198)
at java.io.SequenceInputStream.read(SequenceInputStream.java:208)
at java.io.InputStream.read(InputStream.java:101)
at com.sun.media.sound.WaveFileWriter.writeWaveFile(WaveFileWriter.java:239)
at com.sun.media.sound.WaveFileWriter.write(WaveFileWriter.java:137)
at javax.sound.sampled.AudioSystem.write(AudioSystem.java:1354)
at com.mycompany.mypackage.AudioUtils.concat(AudioUtils.java:324)
......
So looks to me it's when the program still attempts to read more bytes from the AudioInputStream to the file but at some point the stream (targetBuilder) just closes itself. Which doesn't make sense to me because I only close this stream AFTER my AudioSystem.write() method.
Now if I actually comment on this line inside the for loop:
//nextSource.close();
This stream close exception seems going away, with the replace of "FilesNotFoundException: too many open files", which makes sense to me because in every iteration of the loop I am creating a new AudioInputStream and assign reference to nextSource, but if I never close it eventually I run out of open file descriptors.
However what I don't understand is how come closing this nextSource stream would affect in any way how targetBuilder stream behaves? Why would this stream abruptly getting closed if I close nextSource stream? (I am assuming there is a connection between the two, please correct me if I am wrong).
Thanks!