I am currently working on implementing a streaming audio feature, and I've encountered an issue related to merging audio buffers using the AudioContext
. My goal is to fetch 5-second audio chunks and play them to create a continuous audio stream.
Here's what I've done so far:
- I fetch the first 5-second audio chunk, decode it, and store it in an varriable
as type of
AudioBuffer
. - When the user clicks the "Play" button, I fetch other chunks and merge it to first
AudioBuffer
where I re-stored in same variable.
The problem arises when transitioning from one chunk to another during playback. There is a noticeable pause gap between the chunks.
I suspect that this pause gap is due to the process of merging subsequent audio chunks with the initial AudioBuffer
. As the playback progresses from, for instance, 00:04 to 00:05, the pause becomes evident.
How can I effectively merge audio buffers in a way that eliminates or minimizes these pause gaps between chunks? I want to achieve a smooth playing of this audio
also here is demo example of this issue, click play and you will notice that gaps
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);
}
});