根本原因是Tritonus的MP3服务提供者(SPI)未被JVM正确加载,需确保tritonus-share与tritonus-mp3版本一致、含正确META-INF/services配置,Java 9+还需额外模块参数或手动注册。

Java用Tritonus解码MP3时为什么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) - 检查这两个jar内是否包含
META-INF/services/javax.sound.sampled.spi.AudioFileReader文件,内容应为org.tritonus.share.sampled.file.AudioFileReader - 若用Maven,避免只引入
tritonus-share——它不含MP3解析逻辑,必须显式添加tritonus-mp3依赖 - Java 9+用户注意:模块系统默认不读取classpath下的SPI配置,需在启动参数加
--add-opens java.desktop/sun.audio=ALL-UNNAMED(仅调试用),或改用ServiceLoader.load()手动注册
如何用Tritonus把MP3转成16-bit PCM(LINEAR)格式
Tritonus默认输出的PCM格式可能不是你预期的AudioFormat.Encoding.PCM_SIGNED,尤其当原始MP3含VBR或非标准采样率时,AudioInputStream返回的AudioFormat常是Encoding.PCM_UNSIGNED或Encoding.ULAW,需显式重采样。
关键步骤:
立即学习“Java免费学习笔记(深入)”;
- 先用
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);
Tritonus解码MP3后读取PCM数据时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 - 注意:Tritonus的
read()可能一次只返回几百字节,尤其对低码率MP3,别假设能填满buffer
为什么同样代码在Windows能解码、Linux报No 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音频栈的所有不确定性。









