功能概述
实时解码并播放 Base64 编码的 PCM 音频数据,支持多线程处理,确保音频播放流畅。
相关依赖
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.5.4</version>
</dependency>
核心组件
1. 成员变量
-
sampleRate:音频采样率(如 24000 Hz) -
line:音频输出线路(SourceDataLine) -
audioFormat:音频格式(采样率、位深、声道等) -
decoderThread:解码线程(Base64 → 原始音频) -
playerThread:播放线程(写入音频设备) -
stopped:原子布尔值,控制线程退出 -
b64AudioBuffer:Base64 音频队列 -
RawAudioBuffer:原始音频队列
2. 构造函数
public RealtimePcmPlayer(int sampleRate) throws LineUnavailableException {
this.sampleRate = sampleRate;
this.audioFormat = new AudioFormat(this.sampleRate, 16, 1, true, false);
// 打开音频线路
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
// 启动解码和播放线程
startThreads();
}
3. 解码线程
decoderThread = new Thread(() -> {
while (!stopped.get()) {
String b64Audio = b64AudioBuffer.poll();
if (b64Audio != null) {
byte[] rawAudio = Base64.getDecoder().decode(b64Audio);
RawAudioBuffer.add(rawAudio);
} else {
Thread.sleep(100); // 队列为空时休眠
}
}
});
4. 播放线程
playerThread = new Thread(() -> {
while (!stopped.get()) {
byte[] rawAudio = RawAudioBuffer.poll();
if (rawAudio != null) {
playChunk(rawAudio);
} else {
Thread.sleep(100);
}
}
});
5. playChunk 方法
private void playChunk(byte[] chunk) throws IOException, InterruptedException {
if (chunk == null || chunk.length == 0) return;
int bytesWritten = 0;
while (bytesWritten < chunk.length) {
bytesWritten += line.write(chunk, bytesWritten, chunk.length - bytesWritten);
}
int audioLength = chunk.length / (this.sampleRate * 2 / 1000); // 计算音频时长(ms)
Thread.sleep(audioLength - 10); // 等待播放完成
}
-
将音频数据写入音频设备
-
计算音频时长并休眠,确保播放完成
6. 其他方法
-
write(String b64Audio):写入 Base64 音频数据 -
cancel():清空音频队列(用于打断播放) -
waitForComplete():等待所有音频播放完成 -
shutdown():停止线程并关闭音频设备
2584

被折叠的 条评论
为什么被折叠?



