Java原生不支持MP3播放,因AudioSystem仅内置PCM-WAV解码器;需用JLayer将MP3解码为PCM再交SourceDataLine输出,并在独立线程处理、EDT更新UI,避免依赖MediaPlayer以确保跨平台可控性。
Java 原生不支持现代音频格式(如 MP3、FLAC)的直接播放,javax.sound.sampled 仅可靠处理 WAV 和 AIF 等无压缩格式;想做实用音乐播放器,必须引入第三方库。
为什么 AudioSystem 无法直接播放 MP3
AudioSystem.getAudioInputStream() 对 MP3 文件通常抛出 UnsupportedAudioFileException,因为 JDK 自带的音频服务提供者(SPI)未内置 MP3 解码器。这不是代码写错,而是 JDK 设计限制——它只保证对 PCM-WAV 的开箱即用支持。
- 尝试用
AudioSystem.getAudioInputStream(new File("song.mp3"))必然失败 -
AudioFormat的encoding字段对 MP3 是AudioFormat.Encoding.ULAW或未知值,而非标准PCM_SIGNED - 即使绕过异常强行读取,后续
SourceDataLine写入会静音或崩溃
用 javazoom.jl 解码 MP3 并喂给 SourceDataLine
最轻量、最稳定的方案是使用 jl1.0.1(JLayer)解码 MP3 为 PCM 流,再交由 Java 声卡接口播放。注意:它只解码,不负责播放控制逻辑。
- 添加 Maven 依赖:
javazoomjl1.0.1 - 关键步骤:用
Player类解码 → 重写writeAudioData方法捕获 PCM 字节数组 → 转成AudioFormat(采样率 44100、16 位、立体声、小端)→ 推入SourceDataLine - 避免阻塞 UI:解码和写入必须放在单独线程,且需手动处理暂停/恢复(
Player本身无 pause 接口)
AudioFormat format = new AudioFormat(44100, 16, 2, true, false); DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info); line.open(format); line.start(); // 后续在循环中调用 line.write(decodedPcmBytes, 0, len)
Swing 界面中如何安全更新进度条与时间显示
音频解码线程不能直接操作 Swing 组件,否则触发 IllegalStateException: not on event dispatch thread。必须用 SwingUtilities.invokeLater() 包裹 UI 更新。