




根本原因是Tritonus的MP3服务提供者(SPI)未被JVM正确加载,需确保tritonus-share与tritonus-mp3版本一致、含正确META-INF/services配置,Java 9+还需额外模块参数或手动注册。
AudioSystem.getAudioInputStream()抛出UnsupportedAudioFileException
根本原因是Tritonus的MP3服务提供者(SPI)未被JVM正确加载,不是代码写错了。Tritonus本身不自带MP3解码器,它依赖tritonus-share和tritonus-mp3两个jar,并且必须通过META-INF/services/javax.sound.sampled.spi.AudioFileReader声明实现类才能被AudioSystem发现。
实操建议:
tritonus-share-x.x.jar和tritonus-mp3-x.x.jar(版本需严格一致,如都用0.3.7)META-INF/services/javax.sound.sampled.spi.AudioFileReader文件,内容应为org.t
ritonus.share.sampled.file.AudioFileReader
tritonus-share——它不含MP3解析逻辑,必须显式添加tritonus-mp3依赖--add-opens java.desktop/sun.audio=ALL-UNNAMED(仅调试用),或改用ServiceLoader.load()手动注册Tritonus默认输出的PCM格式可能不是你预期的AudioFormat.Encoding.PCM_SIGNED,尤其当原始MP3含VBR或非标准采样率时,AudioInputStream返回的AudioFormat常是Encoding.PCM_UNSIGNED或Encoding.ULAW,需显式重采样。
关键步骤:
AudioSystem.getAudioInputStream(File)获取原始流getFormat()检查encoding字段,若不是AudioFormat.Encoding.PCM_SIGNED,必须用AudioSystem.getAudioInputStream(targetFormat, originalStream)转换AudioFormat推荐设为:new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false)(44.1kHz/16bit/stereo)frameRate和sampleRate要一致,否则AudioSystem可能静默降级为其他编码
File mp3File = new File("input.mp3");
AudioInputStream ais = AudioSystem.getAudioInputStream(mp3File);
AudioFormat baseFormat = ais.getFormat();
AudioFormat targetFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
44100.0f, 16, 2, 4, 44100.0f, false);
AudioInputStream pcmStream = AudioSystem.getAudioInputStream(targetFormat, ais);
read()返回-1或数据截断这不是解码失败,而是AudioInputStream的available()方法在Tritonus中不可靠——它常返回0或错误值,导致提前退出循环。必须依赖getFrameLength()和getFrameSize()计算总字节数,或用阻塞式读取直到返回-1。
安全读取方式:
while (stream.available() > 0)判断循环条件int totalFrames = (int) stream.getFrameLength()预估大小(若为AudioSystem.NOT_SPECIFIED,说明是流式源,只能边读边处理)byte[] buffer = new byte[8192],循环int len = stream.read(buffer),直到len == -1
read()可能一次只返回几百字节,尤其对低码率MP3,别假设能填满bufferNo line matches或静音这通常与底层ALSA/PulseAudio配置无关,而是Tritonus在不同JVM上对浮点型采样率(如44100.0000001)的处理差异导致格式匹配失败。Linux OpenJDK常将MP3元数据里的采样率解析为double近似值,而Tritonus的格式匹配器要求严格相等。
绕过办法:
Math.round(originalFormat.getSampleRate())再构造AudioFormat
AudioFormat.Encoding.PCM_SIGNED + originalFormat.getSampleSizeInBits() + originalFormat.getChannels(),只修正sampleRate和frameRate
ffmpeg -i input.mp3 -f s16le -ar 44100 -ac 2 output.pcm转成裸PCM,再用Java读二进制——比硬啃Tritonus兼容性更省时间ffmpeg-cli-wrapper或jave2这类进程调用方案,它们绕过了JVM音频栈的所有不确定性。