我目前正在致力于实现流音频功能,并且遇到了与使用
AudioContext
合并音频缓冲区相关的问题。我的目标是获取 5 秒的音频块并播放它们以创建连续的音频流。
这是我到目前为止所做的:
AudioBuffer
的类型。AudioBuffer
,我将其重新存储在同一变量中。在播放期间从一个块转换到另一个块时会出现问题。块之间有明显的停顿间隙。
我怀疑这个暂停间隙是由于将后续音频块与初始
AudioBuffer
合并的过程造成的。例如,当播放从 00:04 到 00:05 时,暂停变得明显。
如何有效地合并音频缓冲区,以消除或最小化块之间的这些暂停间隙?我想实现这个音频的流畅播放
这里还有 demo 此问题的示例,单击播放,您会注意到间隙
import audios, { preBuffer } from "./data";
import { fetchDecode, mergeAudioBuffers } from "./utils";
const playButton = document.getElementById("play") as HTMLButtonElement;
let ctx: AudioContext;
let combinedAudioBuffers: AudioBuffer;
let source: AudioBufferSourceNode;
let startTime = 0;
let playbackTime = 0;
// decode first buffer before starting streaming
window.onload = async () => {
ctx = new AudioContext();
const arrayBuffer: ArrayBuffer = await fetchDecode(preBuffer);
const audioBuffer: AudioBuffer = await ctx.decodeAudioData(arrayBuffer);
combinedAudioBuffers = audioBuffer;
const src: AudioBufferSourceNode = ctx.createBufferSource();
src.buffer = audioBuffer;
src.connect(ctx.destination);
source = src;
};
playButton.addEventListener("click", async () => {
startTime = Date.now();
source.start(0);
playButton.innerHTML = "Playing";
playButton.disabled = true;
// decode all the url chunks add to AudioBuffer and continue playing
for (let audio of audios) {
const arraybuffer = await fetchDecode(audio);
const decodeBuffer = await ctx.decodeAudioData(arraybuffer);
const mergeTwoBuffers = mergeAudioBuffers(
ctx,
combinedAudioBuffers,
decodeBuffer
);
combinedAudioBuffers = mergeTwoBuffers;
playbackTime = Date.now();
let playback = (playbackTime - startTime) / 1000;
source.stop();
source = ctx.createBufferSource();
source.buffer = combinedAudioBuffers;
source.connect(ctx.destination);
source.start(0, playback);
}
});
(我假设你的合并代码很好......你没有向我们展示它,所以我们不知道如何......)
一般来说,你不能用有损编解码器进行这种拆分和合并,至少在编码器端没有一些合作。
您使用的是 MP3,它具有“帧”的概念,可编码 576 个音频样本。因此,您至少需要在帧边界上进行分割,而不是任意的时间量。
但情况比这更糟糕,因为一个帧可能依赖于另一个帧中的一大块数据。这就是位存储库,这是一种技巧,可以为更复杂的段落使用更多的位,为简单的内容使用更少的位。类似于 CBR 流中的 VBR。无论如何,这意味着您无法单独正确解码任意帧。您可能需要周围的框架才能做到这一点。
此外,普通的 MP3 流没有任何方式向解码器发出延迟信号,因此如果不进行一些修改,就不可能实现 MP3 的无缝播放。编码器通常会插入几帧静默以允许初始化解码器。
所以,综上所述:
您真的确定需要分块执行此操作吗?浏览器擅长自行流式传输。即使您需要对流进行一些调整,您也可以使用 MediaSource 扩展。
如果您出于某种原因必须使用分块,请考虑重新使用 HLS。这是一个实施良好的标准,通常在 MP4/ISOBMFF 文件中使用 AAC 来处理音频。然后您不必重新实现任何这些,无论是在编码还是解码方面。