在 Harmony 开发中使用 AudioRenderer 播放 PCM 数据时只“滴”一下就没声音,播放流程应该怎么写?
harmonyos
使用 AudioKit 的 createAudioRenderer 播放一段本地 PCM 数据(S16LE,48kHz,双声道)。创建 AudioRenderer 成功,日志也打印了 start success,但实际效果是只听到很短的一点点声音或者完全没声音,好像只播放了几帧数据就结束了。
下面我代码:
import { audio } from '@kit.AudioKit';
import fileIo from '@ohos.file.fs';
let audioRenderer: audio.AudioRenderer | undefined;
async function playPcm(filePath: string) {
const options: audio.AudioRendererOptions = {
streamInfo: {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
channels: audio.AudioChannel.CHANNEL_2,
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
},
rendererInfo: {
usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
rendererFlags: 0
}
};
audioRenderer = await audio.createAudioRenderer(options);
await audioRenderer.start();
// 只读取一次数据就 stop
const fd = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
const buffer = new ArrayBuffer(4096);
fileIo.readSync(fd, buffer);
await audioRenderer.write(buffer);
await audioRenderer.stop();
await audioRenderer.release();
fileIo.closeSync(fd);
}
没有明显的报错,只是播放效果不对。
您需要先 登录 才能评论/回答
全部评论(1)
现象是只播放一次缓冲就立刻 stop,本质问题是:
-
只调用了一次
write(),数据量太少; -
播放结束前没有等渲染器把 buffer 播完就
stop/release。
一个更符合 AudioKit 推荐流程的写法是:
import { audio } from '@kit.AudioKit';
import { BusinessError } from '@kit.BasicServicesKit';
import fileIo from '@ohos.file.fs';
async function playPcmLoop(filePath: string) {
const options: audio.AudioRendererOptions = {
streamInfo: {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
channels: audio.AudioChannel.CHANNEL_2,
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
},
rendererInfo: {
usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
rendererFlags: 0
}
};
let renderer: audio.AudioRenderer;
try {
renderer = await audio.createAudioRenderer(options);
} catch (err) {
const be = err as BusinessError;
console.error(`createAudioRenderer error: code=${be.code}, msg=${be.message}`);
return;
}
const fd = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
const bufferSize = 4096;
const buffer = new ArrayBuffer(bufferSize);
await renderer.start();
while (true) {
const readLen = fileIo.readSync(fd, buffer);
if (readLen <= 0) {
break; // 文件读完
}
const realData = buffer.slice(0, readLen);
await renderer.write(realData);
}
// 等待内部缓冲播放完(不同版本可能有 drain()/flush(),按当前 SDK 文档为准)
await renderer.stop();
await renderer.release();
fileIo.closeSync(fd);
}
关键点:
-
播放必须循环调用
write,直到数据写完; -
不要在第一帧写完就立刻
stop,要等播放逻辑结束后再stop + release; -
若当前 SDK 提供
drain()或类似接口,可以在stop之前调用让渲染器把内部缓冲播放完。
按上述流程调整后,就不会只“滴”一下了,而是完整播放整个 PCM 文件。
2025-11-17 10:42:20