Una excepción de IO cuando intento obtener un InputStream conectado con un archivo dentro de un archivo jar en la API de Java Sound
Estoy escribiendo un método simple para reproducir sonidos utilizando Java Sound API. Mi idea es reproducir solo archivos .wav incluidos en el archivo JAR. Con imágenes, puedo obtener fácilmente un InputStream utilizando ClassLoader.getResourceAsStream() y cargar una imagen desde este flujo. Sin embargo, cuando uso el mismo enfoque con sonidos, obtengo una 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)
La causa es AudioSystem.getAudioInputStream() que uso desde el siguiente código:
AudioInputStream stream = AudioSystem.getAudioInputStream(
Audio.class.getClassLoader().getResourceAsStream(path)
);
Clip clip = AudioSystem.getClip();
clip.open(stream);
clip.setFramePosition(0);
clip.start();
Verifico que el InputStream resultante se pueda leer y obviamente no es nulo. Según entiendo por la descripción de la excepción, Java Sound API y en particular la clase AudioSystem, que uso para obtener una instancia de AudioInputStream, intentan utilizar operaciones de marca o reinicio en el InputStream subyacente. Parece que estas operaciones no están permitidas en dichos flujos de entrada.
Estoy completamente confundido. Me resulta extraño que javax.sound.sampled.AudioSystem lea un InputStream de manera completamente diferente a javax.imageio.ImageIO (con ImageIO puedo leer imágenes de un archivo JAR sin problemas).
¿Cómo puedo solucionarlo? Obviamente, puedo leer un archivo regular, no desde el archivo JAR, pero si es posible, quiero leer los sonidos exactamente desde los archivos JAR.
He intentado ejecutar este código con Java 8.0.302-open y Java 16.0.2-open. Además, si este problema es específico de la plataforma, estoy usando Desktop Ubuntu 20.04 con Linux Kernel version 5.11.0-41-generic y, desafortunadamente, no tengo la oportunidad de probar este código en otras plataformas.
RESUELTO: Gracias a @filpa, la solución es envolver un InputStream obtenido por ClassLoader.getResourceAsStream() en un BufferedInputStream o cualquier otro InputStream que admita operaciones mark/reset.
davy.ai
Para solucionar el problema con
mark/reset not supported
al utilizarAudioSystem.getAudioInputStream()
para reproducir archivos.wav
incluidos en un archivo jar, puedes intentar envolver elInputStream
obtenido porClassLoader.getResourceAsStream()
en unBufferedInputStream
.Aquí tienes un ejemplo de código:
Al envolver el
InputStream
en unBufferedInputStream
, proporciona las funcionalidades necesarias demark/reset
que elAudioInputStream
requiere para leer correctamente los datos de audio del recurso en el archivo jar.Esto te permitirá reproducir archivos de audio desde el jar utilizando la API de Java Sound.