Search code examples
javajavasound

An IOexception when I try to get an InputStream connected with a file inside a jar Java Sound API


I am writting a simple method to play sounds using Java Sound API. My idea is to play only .wav files included in the jar. With images I can easily get an InputStream using ClassLoader.getResourceAsStream() and load an image from this stream. However, when I use the same approach with sounds, I get an IOException.

Caused by: java.io.IOException: mark/reset not supported
    at java.base/java.util.zip.InflaterInputStream.reset(InflaterInputStream.java:290)
    at java.base/java.io.FilterInputStream.reset(FilterInputStream.java:224)
    at java.desktop/com.sun.media.sound.SunFileReader.getAudioFileFormat(SunFileReader.java:59)
    at java.desktop/com.sun.media.sound.WaveExtensibleFileReader.getAudioInputStream(WaveExtensibleFileReader.java:259)
    at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1010)
    at ru.mrkefir.stepan.engine.sound.Audio.playImpl(Audio.java:34)

The cause is AudioSystem.getAudioInputStream() which I use from the following code:

AudioInputStream stream = AudioSystem.getAudioInputStream(
     Audio.class.getClassLoader().getResourceAsStream(path)
);
Clip clip = AudioSystem.getClip();
clip.open(stream);
clip.setFramePosition(0);
clip.start();

I check that resulting InputStream can be read and obviously it isn't null. As I understand from the description of exception, Java Sound API and particularly the AudioSystem class, which I use to get an instance of AudioInputStream, try to use mark or reset operations on underlaying InputStream. Seems like these operations are not allowed on such input streams.

I am completely confused. It's strange for me that javax.sound.sampled.AudioSystem reads an InputStream in completely different way than javax.imageio.ImageIO (with ImageIO I can read images from a jar without problems).

How can I fix it? I may obviously read a regular file, not from the jar, but if it is possible, I want to read sounds exactly from jars.

I tried to run this code with Java 8.0.302-open and Java 16.0.2-open. Besides, if this problem is platform specific, I use Desktop Ubuntu 20.04 with Linux Kernel version 5.11.0-41-generic and, unfortunatly, I don't have an opportunity to test this code on other platforms.

SOLVED Thanks for @filpa, the solution is to wrap a InputStream obtained by ClassLoader.getResourceAsStream() into BufferedInputStream or any other input stream which supported mark/reset operations.


Solution

  • A simpler way to bring in sound resources is to use getResource() instead of getResourceAsStream(). There is no need to wrap in that case. If you provide a URL to the getAudioInputStream() method instead of an InputStream, issues/errors pertaining to mark/reset capabilities are avoided.

    There are examples posted at Stackoverflow's info area for the javasound tag. Basically:

    URL url = YourClass.class.getResource("youraudio.wav");
    AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
    

    The above assumes the audio resource is in the same folder as the class YourClass.

    P.S. If you prefer the answer (using getResourceAsStream() and wrapping, please actually write this as an answer, and select it. Otherwise this question will lure in people who like to help others, thinking this question has not yet been answered. Alternatively, invite @filpa to post his info as an answer and select it.