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 依赖:
javazoom jl 1.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 更新。
立即学习“Java免费学习笔记(深入)”;
- 不要在解码循环里写:
progressBar.setValue(pos)或timeLabel.setText("2:34") - 正确做法:计算当前播放毫秒数(基于已解码帧数 × 每帧毫秒),然后封装进
Runnable提交到 EDT - 暂停时记得停止定时任务(如
Timer或ScheduledExecutorService),否则进度条会继续跑 - 拖动进度条时,需重新定位 MP3 文件指针(
InputStream.skip()不可靠,应重建FileInputStream+ 重新初始化Player)
为什么不要用 JavaFX MediaPlayer 替代 Swing 方案
MediaPlayer 看似简单,但它依赖系统本地媒体框架(Windows 上是 Media Foundation,macOS 是 AVFoundation),在 Linux 或无图形环境极易失效,且无法细粒度控制缓冲、解码线程或 PCM 数据流。调试时常见错误:MediaException: UNKNOWN : com.sun.media.jfxmedia.MediaException: Could not create player!。
- 打包成 JAR 后,在没有安装 GStreamer 插件的 Linux 上几乎必挂
- 无法获取实时 PCM 数据,做频谱分析或均衡器就无从下手
- 播放控制(如精确跳转到毫秒级位置)响应延迟高,且 API 不透明
真正可控的播放器,得从字节流开始管起——解码、重采样、混音、输出,每一步都暴露在外,才谈得上“设计”,而不是调个 play() 就完事。











