逐块流式传输音频时,块之间有暂停间隔

问题描述 投票:0回答:1

我目前正在致力于实现流音频功能,并且遇到了与使用

AudioContext
合并音频缓冲区相关的问题。我的目标是获取 5 秒的音频块并播放它们以创建连续的音频流。

这是我到目前为止所做的:

  1. 我获取第一个 5 秒音频块,对其进行解码,并将其存储在变量中 作为
    AudioBuffer
    的类型。
  2. 当用户单击“播放”按钮时,我会获取其他块并将其合并到第一个
    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);
  }
});

javascript audio web-audio-api audiocontext audiobuffer
1个回答
0
投票

(我假设你的合并代码很好......你没有向我们展示它,所以我们不知道如何......)

一般来说,你不能用有损编解码器进行这种拆分和合并,至少在编码器端没有一些合作。

您使用的是 MP3,它具有“帧”的概念,可编码 576 个音频样本。因此,您至少需要在帧边界上进行分割,而不是任意的时间量。

但情况比这更糟糕,因为一个帧可能依赖于另一个帧中的一大块数据。这就是位存储库,这是一种技巧,可以为更复杂的段落使用更多的位,为简单的内容使用更少的位。类似于 CBR 流中的 VBR。无论如何,这意味着您无法单独正确解码任意帧。您可能需要周围的框架才能做到这一点。

此外,普通的 MP3 流没有任何方式向解码器发出延迟信号,因此如果不进行一些修改,就不可能实现 MP3 的无缝播放。编码器通常会插入几帧静默以允许初始化解码器。

所以,综上所述:

  • 您真的确定需要分块执行此操作吗?浏览器擅长自行流式传输。即使您需要对流进行一些调整,您也可以使用 MediaSource 扩展。

  • 如果您出于某种原因必须使用分块,请考虑重新使用 HLS。这是一个实施良好的标准,通常在 MP4/ISOBMFF 文件中使用 AAC 来处理音频。然后您不必重新实现任何这些,无论是在编码还是解码方面。

© www.soinside.com 2019 - 2024. All rights reserved.