Как я понял проблема была в том, что я несколько раз инициализировал AudioContext, поэтому в этот раз я сделал проверку на то, что он уже инициализирован.
Поместил всю работу с AudioContext в отдельный метод для разделения логики.
Сделал проверку состояния AudioContext (кому интересно, то вам сюда)
Также добавил gainNode, который потом изменяю, если меняется громкость аудио (эта работа происходит уже в другом методе, здесь его нет, кому интересно, то вам сюда)
Метод _setAudioBarsAnim не изменял.
В конечном итоге получилось это:
class Audioplayer {
constructor() {
this.elAudio = document.createElement("audio");
this.elCanvasAnim = document.querySelector(".audio-player__anim-canvas");
this.play = false;
this.animIsActive = false;
this.audioContext = null;
this.gainNode = null;
this.audioAnalyser = null;
}
playAudio(audioSrc) {
if (audioSrc !== this.elAudio.src) {
this.elAudio.src = audioSrc;
this.play = true;
}
const promise = this.elAudio.play();
if (promise instanceof Promise) {
promise
.then(() => {
if (this.audioContext instanceof AudioContext && this.audioContext.state === "suspended") {
this.audioContext.resume();
}
if (this.play) {
this.elAudio.play();
this._initAudioContext();
if (!this.animIsActive) {
this.animIsActive = true;
this._setAudioBarsAnim();
}
} else {
this.elAudio.pause();
}
}).catch((err) => {
throw err;
});
}
}
_initAudioContext() {
if (this.audioContext) {
return;
}
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.gainNode = this.audioContext.createGain();
this.audioAnalyser = this.audioContext.createAnalyser();
const source = this.audioContext.createMediaElementSource(this.elAudio);
this.audioAnalyser.fftSize = 2048;
source
.connect(this.gainNode)
.connect(this.audioAnalyser)
.connect(this.audioContext.destination);
}
_setAudioBarsAnim() {
const canvas = this.elCanvasAnim;
const ctx = canvas.getContext("2d");
const countLinesOnArea = 250;
const widthLine = canvas.offsetWidth / countLinesOnArea;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const drawBars = () => {
const fbcArray = new Uint8Array(this.audioAnalyser.frequencyBinCount);
this.audioAnalyser.getByteFrequencyData(fbcArray);
ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
fbcArray.slice(0, countLinesOnArea).forEach((n, i) => {
const x = i * widthLine;
const percent = Math.ceil((n / 255) * 100);
const height = (percent * canvas.offsetHeight) / 100;
ctx.fillStyle = "white";
ctx.fillRect(x, canvas.offsetHeight - height, widthLine, height);
});
(window.requestAnimationFrame || window.webkitRequestAnimationFrame)(drawBars);
};
drawBars();
}
}