Java需用ByteArrayInputStream包装byte[]并配准AudioFormat构造AudioInputStream,否则抛UnsupportedAudioFileException;Clip适合短音频,SourceDataLine适合长音频或流式播放。
Java用
从
字节
数组构造音频流
Java标准库不支持直接把
丢给播放器,必须先包装成
。核心是用
套一层,再结合
描述音频元信息——缺一不可,否则
或
会抛
。
参数必须与原始音频数据严格匹配:采样率、位深(如16)、声道数(1=单声道/2=立体声)、是否带符号、是否大端序
常见错误是忽略
和
——对PCM数据,
=
,
通常等于采样率
若字节数组来自网络或文件,确认它不含WAV/MP3等容器头;Java的
只认裸PCM或标准WAV头,纯MP3需第三方解码
用
播放短音频(≤1MB)
适合播放内存中已加载完毕的小段音频(如音效),它预加载全部数据到内存并支持循环、定位,但不适合长音频或实时流——会OOM。
注意
是
,不能传
或
,否则
可能静默失败
播放前务必调用
再
释放资源,否则下次
可能报
若音频是单声道但误设
,会听到严重失真或无声
用
播放任意长度音频
需要手动分块写入、控制缓冲区,适合长音频、动态生成音频或低延迟场景。它不缓存全部数据,但要求你管理线程和写入节奏。
是阻塞调用,写入量超过缓冲区会等待,所以循环里不用
缓冲区大小(第二个参数)太小会导致频繁系统调用,太大则增加延迟;实测4096–16384字节较稳
若
是浮点PCM(如-1.0~+1.0),Java原生不支持,必须先转为16位有符号整型(
)
绕不开的兼容性坑:WAV头、
编码
格式、JVM音频后端
即使字节数组内容正确,仍可能无声——问题常出在音频格式本身或系统音频栈。
Trae win
Trae Windows 官方版本现已全面支持 Win10 和 Win11 系统(64位)。国内开发者可直接访问 Trae 中文官网(trae.cn 或 trae.com.cn),一键下载官方正版 .exe 安装包,享受国内直连的高速稳定体验。安装过程极其简便,双击即可运行,并支持一键无缝导入 VS Code 或 Cursor 的原有主题、快捷键及插件配置。登录支持手机号、微信或稀土掘金账号。内置免费的豆包与 DeepSeek 等顶级大模型,让你开箱即用,轻松开启高效的 AI 智能编程之旅。
下载
立即学习
“
Java免费学习笔记(深入)
”;
Java内置仅支持PCM/WAV/ULAW/ALAW;若字节数组是AAC/MP3/OGG,
直接返回
,必须用
(MP3)或
等库先解码
Linux下默认
后端可能禁用Java音频,启动JVM时加
或改用
Windows上若用USB声卡或蓝牙
耳机
,部分设备不支持特定采样率(如48kHz),硬设44100更稳妥
最易被忽略的是:音频字节数组的起始位置。WAV文件前44字节是头,裸PCM才可直用;若误把WAV头当PCM数据传入,
会尝试解析头为音频样本,结果必然是刺耳噪音或崩溃。
AudioInputStreambyte[]AudioInputStreamByteArrayInputStreamAudioFormatClipSourceDataLineUnsupportedAudioFileExceptionAudioFormatframeSizeframeRateframeSizechannels × bitsPerSample / 8frameRateAudioSystem.getAudioInputStream()ClipClipAudioFormat format = new AudioFormat(44100, 16, 2, true, false);
AudioInputStream ais = new AudioInputStream(
new ByteArrayInputStream(audioBytes), format, audioBytes.length / format.getFrameSize()
);
Clip clip = AudioSystem.getClip();
clip.open(ais);
clip.start();audioBytes.length / format.getFrameSize()frameLength-10Clip.open()clip.drain()close()open()LineUnavailableExceptionchannels=2SourceDataLineAudioFormat 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, 4096); // 缓冲区大小建议为帧大小的整数倍
line.start();
int offset = 0;
int remaining = audioBytes.length;
while (remaining > 0) {
int toWrite = Math.min(remaining, 4096);
line.write(audioBytes, offset, toWrite);
offset += toWrite;
remaining -= toWrite;
}
line.drain();
line.close();
line.write()Thread.sleep()audioBytes(short)(sample * 32767)AudioSystem.getAudioInputStream()nulljavazoom.jl.player.Playerorg.tritonus.share.sampled.convert.TarsosAudioConverter PulseAudio-Djavax.sound.sampled.provider=org.classpath.icedtea.pulseaudio.PulseAudioMixerProviderALSAClip