Failed to pass InputStream object to Java Sound API

It works with the object File

passed in AudioSystem#getAudioFileFormat

, but why doesn't it work with the object InputStream

below? Any suggestion?

import java.io.*;
import javax.sound.sampled.*;

public class Test {

    public static void main(String[] args) throws Exception {

        AudioSystem.getAudioFileFormat(new File(
                "myaudio.wav"));
        AudioSystem.getAudioFileFormat(new FileInputStream(
                "myaudio.wav"));

    }
}

      

Output:

Exception in thread "main" java.io.IOException: mark/reset not supported
    at java.io.InputStream.reset(InputStream.java:330)
    at com.sun.media.sound.WaveFileReader.getAudioFileFormat(WaveFileReader.java:88)
    at javax.sound.sampled.AudioSystem.getAudioFileFormat(AudioSystem.java:985)
    at Test.main(Test.java:10)

      

@EDIT

According to the answers @René Jeschke

, @Phil Freihofner

and @Andrew Thompson

where mark/reset

it is required as a mandatory protocol to Java Sound API

interact with IO stream

, IMHO, the type of buffered

stream raw

should instead be specifically , which is defined as the signature of the passed parameter. This will narrow down to a more desirable outcome than arbitrarily accept IO stream

and then resort to IOException

as an unfavorable indicator.

+3


source to share


3 answers


FileInputStream

doesn't support mark / reset (for random access), wrap it in BufferedInputStream

to get mark / reset support.

Edit: Why is this the case? getAudioFileFormat

iterates through each registered audio file. Each reader tries to identify the file format by reading some specific bytes. Therefore, each reader should undo their changes in the stream (so that other readers can re-read all the data, if necessary).

When you supply File

this is not a problem, because each reader just opens a new stream, but when you submit a stream, each reader has to mark the current position of the stream, do their readings, and reset the stream before it starts when it's finished.



That's why you need it BufferedInputStream

, because it adds an in-memory buffer to support the / reset label.

Edit2: Because the question is, "Why doesn't this work with FileInputStream?" I haven't offered any workarounds or replacements, but tried to explain why it fails if you are using FileInputStream

. There are also cases where you cannot use a URL or the like (consider, for example, a binary package file containing audio files).

+4


source


This works for me (with other Wavs).

AudioSystem.getAudioFileFormat(new File(
            "myaudio.wav").toURI().toURL());

      



Code in JavaSound info. the page also uses the url.

If you have something that is not File

or the URL

problem can be fixed by buffering it as mentioned by Rene Yeschke, or I generally just read everything byte[]

and installed it ByteArrayInputStream

. This positioned (supports mark / reset).

+1


source


The AudioSystem.getAudioFileFormat () methods call the abstract class "AudioFileReader" in the javax.sound.sampled.spi package.

The comments in the code of the method AudioFileFormat getAudioFileFormat(InputStream stream) throws UnsupportedAudioFileException, IOException;

say that a / reset may be required:

 * Obtains the audio file format of the input stream provided. The stream must
 * point to valid audio file data. In general, audio file readers may
 * need to read some data from the stream before determining whether they
 * support it. These parsers must
 * be able to mark the stream, read enough data to determine whether they
 * support the stream, and, if not, reset the stream read pointer to its original
 * position. If the input stream does not support this, this method may fail
 * with an <code>IOException</code>.

      

On the contrary, form public abstract AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException, IOException;

and public abstract AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException;

DO NOT make this requirement. Support for parsers only with InputStream as a parameter.

AudioSystem.getAudioInputStream () are similarly commented out for various overloads.

When the / reset tag error occurs in the context of working with audio files, the solution for the first try is to download the file from its url and thus avoid the / reset tag requirement (as mentioned by Andrew Thompson). If that doesn't work, of course use a BufferedInputStream, but it shouldn't come to this for valid audio files.

The issue is also documented in the Oracle Bug database as bug # 7095006.

+1


source







All Articles