как остановить воспроизведение конструктора аудио js?

Написал сайт по воспроизведению аудиофайлов с визуализацией;

window.addEventListener('click', (e) => {
    const targetTrack = e.target.closest('.audio-block')
    if(e.target.closest('.audio-block')) {
        const srcAudio = targetTrack.querySelector('audio')
     
        let newAudio = new Audio()
        newAudio.src = srcAudio.getAttribute('src')
        context = new AudioContext()
        analyser = context.createAnalyser();
        analyser.connect(context.destination)
        if(newAudio.paused) {
            newAudio.play()
        } else {
            newAudio.pause()
        }

        src = context.createMediaElementSource(newAudio)
        src.connect(analyser)
    }
}

как остановить проигрывание аудиозаписи??? при повторном нажатии на блок, этот же аудиотрек воспроизводится поверх уже играющего


Ответы (2 шт):

Автор решения: Daniil Loban

Лучше всего, думаю сделать класс Player который будет заниматься воспроизведением и инкапсулировать всю логику.

В данном случае newAudio создается 1 раз, newAudio.src меняется только если это новый источник, так как установка этого свойства автоматически переводит аудио в режим проигрывания.

let newAudio = new Audio()

window.addEventListener('click', (e) => {
    const targetTrack = e.target.closest('.audio-block')
    if(e.target.closest('.audio-block')) {
        const srcAudio = targetTrack.querySelector('audio')
        if (newAudio.src !== srcAudio.getAttribute('src')){
          newAudio.src = srcAudio.getAttribute('src')
        }
        //context = new AudioContext()
        //analyser = context.createAnalyser()
        //analyser.connect(context.destination)
        if(newAudio.paused) {
            newAudio.play()
        } else {
            newAudio.pause()
        }
        //src = context.createMediaElementSource(newAudio)
        //src.connect(analyser)
    }
})
<div class="audio-block">file_example_OOG_1MG.ogg
<audio src ="https://file-examples.com/storage/fe7d3a0d44631509da1f416/2017/11/file_example_OOG_1MG.ogg"></audio>
</div>

Доработанный вариант ответа:

C учетом потенциальной утечки памяти сделаны ограничение на создание объектов а так же высвобождение ресурсов при необходимости

состояние памяти в браузере

На снимке видно, что освобождение памяти происходит. Тесты проводились на 2х аудиозаписях с быстрым переключением с одной на другую, что соответсвенно запускало функцию initSrc основной источник утечки памяти.

let srcAudio 
let src
let audioCtx
let analyser

function initSrc(item) {
  if (src){ 
    src.disconnect(); // освобождаем ресурс
  }
  if (!audioCtx) { // единожды создаем контекст и анализатор
    audioCtx = new AudioContext()
    analyser = audioCtx.createAnalyser()
    analyser.connect(audioCtx.destination)
  }
  src = new MediaElementAudioSourceNode(audioCtx, {
     mediaElement: item  // связываем контекст и аудио элемент  
  })
  src.connect(analyser) // пробрасываем данные в анализатор
}

window.addEventListener('click', (e) => {
  const targetTrack = e.target.closest('.audio-block')
  if(e.target.closest('.audio-block')) {
    const clickedAudio = targetTrack.querySelector('audio')
    if( srcAudio && !srcAudio.paused && srcAudio !== clickedAudio ){
      srcAudio.pause() // останавливает проигрывание из другого источника
    } 
    srcAudio = clickedAudio 
    if(srcAudio.paused) { 
      srcAudio.play()
      // создание контекста (инициируется только пользователем)  
      initSrc(srcAudio) 
    } else { 
      srcAudio.pause()
    }
  }
})
→ Ссылка
Автор решения: Noob

Ответ выше поможет с ошибкой, но создаст еще ошибку именно с audioContext(). В моем случае я еще должен обновлять Audio, иначе медиаэлемент будет выдавать ошибку:

HTMLMediaElement already connected previously to a different MediaElementSourceNode.

В общем смог решить проблему:

let audioArray = []; //создаем массив, в дальнейшем будем закладывать принцип работы AudioContext в нем. обновлять элемент, дабы обойти ошибку

let newAudio = new Audio();

window.addEventListener('click', (e) => {
    const targetTrack = e.target.closest('.audio-block')
    if(e.target.closest('.audio-block')) {
        const srcAudio = targetTrack.querySelector('audio')
     
        if(audioArray.length > 0) { //если длина массива больше одного элемента то....
            audioArray.shift() //.....удаляем первый элемент
        }
        audioArray.push(newAudio) //закидываем в конец массива аудио, по которому был совершен клик
        
        context = new AudioContext()
        

        audioArray.forEach((item) => {
                if(srcAudio.paused && item.paused) {
                    srcAudio.play()
                    item.play() 
                } else {
                    srcAudio.pause()
                    item.pause()
                }

                if(!src) {
                    src = context.createMediaElementSource(item)
                    analyser = context.createAnalyser()
                    src.connect(analyser)
                    
                }
                
            })
    }
}

У меня по крайней мере все заработало.

→ Ссылка