2. Java音频播放API
Java在javax.sound
包中提供了两种音频播放方式,主要区别在于音频数据的处理机制:流式缓冲播放和内存非缓冲播放。最常用的两个API是Clip
和SourceDataLine
。
2.1. Clip API
Clip
是Java的非缓冲/内存音频API,位于javax.sound.sampled
包中。特别适合播放短音频文件,播放前会将整个音频加载到内存,提供完整的播放控制能力。
除了循环播放,还支持从任意位置开始播放。
首先创建实现LineListener
接口的SoundPlayerWithClip
类,用于监听播放事件(OPEN
、CLOSE
、START
、STOP
):
public class SoundPlayerUsingClip implements LineListener {
boolean isPlaybackCompleted;
@Override
public void update(LineEvent event) {
if (LineEvent.Type.START == event.getType()) {
System.out.println("Playback started.");
} else if (LineEvent.Type.STOP == event.getType()) {
isPlaybackCompleted = true;
System.out.println("Playback completed.");
}
}
}
接着从项目资源目录读取音频文件(包含WAV、MP3、MPEG三种格式):
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);
从文件流创建AudioInputStream
:
AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);
创建DataLine.Info
对象:
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
创建Clip
对象,打开流并开始播放:
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.addLineListener(this);
audioClip.open(audioStream);
audioClip.start();
最后关闭资源:
audioClip.close();
audioStream.close();
由于音频已预加载到内存,我们可以利用更多实用API:
使用Clip.loop
方法循环播放:
audioClip.loop(4); // 播放5次
或无限循环播放:
audioClip.loop(Clip.LOOP_CONTINUOUSLY);
使用setMicrosecondPosition
设置播放起始位置(例如从30秒开始):
audioClip.setMicrosecondPosition(30_000_000);
2.2. SourceDataLine API
SourceDataLine
是Java的缓冲/流式音频API,同样位于javax.sound.sampled
包中。适合播放无法预加载到内存的长音频文件,或实时流式音频数据。
当需要优化大文件内存占用,或无法预知音频时长时特别有用。
首先创建类并读取音频文件:
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(audioFilePath);
创建AudioInputStream
:
AudioInputStream audioStream = AudioSystem.getAudioInputStream(inputStream);
创建DataLine.Info
对象:
AudioFormat audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
创建SourceDataLine
对象并开始播放:
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
音频数据分块加载,需指定缓冲区大小:
private static final int BUFFER_SIZE = 4096;
从AudioInputStream
读取数据并写入播放缓冲区:
byte[] bufferBytes = new byte[BUFFER_SIZE];
int readBytes = -1;
while ((readBytes = audioStream.read(bufferBytes)) != -1) {
sourceDataLine.write(bufferBytes, 0, readBytes);
}
关闭资源:
sourceDataLine.drain();
sourceDataLine.close();
audioStream.close();
2.3. Clip与SourceDataLine对比
特性 | Clip | SourceDataLine |
---|---|---|
任意位置播放 | 支持(setMicrosecondPosition ) |
不支持 |
循环播放 | 支持(setLoopPoints /loop ) |
不支持 |
获取音频时长 | 支持(getFrameLength ) |
不支持 |
暂停/恢复 | 支持(stop /start ) |
不支持 |
大文件处理 | 低效(内存加载) | 高效(流式处理) |
线程阻塞 | 非阻塞(需LineListener ) |
阻塞(无需监听器) |
缓冲区控制 | 不可控 | 可控 |
2.4. MP3格式支持
目前Clip
和SourceDataLine
仅支持AIFC、AIFF、AU、SND、WAV格式。检查支持格式:
Type[] list = AudioSystem.getAudioFileTypes();
StringBuilder supportedFormat = new StringBuilder("Supported formats:");
for (Type type : list) {
supportedFormat.append(", " + type.toString());
}
System.out.println(supportedFormat.toString());
Java原生API不支持MP3/MPEG格式,尝试播放会抛出异常:
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1189)
3. 第三方音频播放库
3.1. JavaFX库
JavaFX的Media
和MediaPlayer
类支持MP3播放,也兼容WAV等格式:
String audioFilePath = "AudioFileWithMp3Format.mp3";
SoundPlayerUsingJavaFx soundPlayerWithJavaFx = new SoundPlayerUsingJavaFx();
try {
com.sun.javafx.application.PlatformImpl.startup(() -> {});
Media media = new Media(
soundPlayerWithJavaFx.getClass().getClassLoader().getResource(audioFilePath).toExternalForm());
MediaPlayer mp3Player = new MediaPlayer(media);
mp3Player.play();
} catch (Exception ex) {
System.out.println("Error occured during playback process:" + ex.getMessage());
}
优势:支持WAV、MP3、MPEG多种格式。
3.2. JLayer库
JLayer 支持MP3等MPEG格式,但不支持WAV:
String audioFilePath = "AudioFileWithMp3Format.mp3";
SoundPlayerUsingJavaZoom player = new SoundPlayerUsingJavaZoom();
try {
BufferedInputStream buffer = new BufferedInputStream(
player.getClass().getClassLoader().getResourceAsStream(audioFilePath));
Player mp3Player = new Player(buffer);
mp3Player.play();
} catch (Exception ex) {
System.out.println("Error occured during playback process:" + ex.getMessage());
}
4. 总结
本文系统介绍了Java音频播放技术:
- 掌握了
Clip
和SourceDataLine
两种核心API的使用场景 - 明确了二者在控制能力、内存占用、格式支持上的差异
- 通过对比表格快速选择适合的API
- 当需要播放MP3时,推荐使用JavaFX或JLayer等第三方库
实际开发中,短音频用Clip
更灵活,长音频或流式场景选SourceDataLine
,MP3需求则直接上第三方库。示例代码已上传至GitHub。