AudioContext компрометирует производительность приложения, тем больше аудио файлов я играю - PullRequest
0 голосов
/ 16 мая 2019

Хорошо, я разрабатываю приложение Elecron (javascript) для аудио-визуализации. Существует экземпляр Playlist(), который получает пути к аудиофайлам, которые пользователь хочет воспроизвести. Когда первый звук заканчивается, он воспроизводит следующий. Все идет нормально. Приложение выполняет интенсивную вычислительную работу, извлекая аудиофункции из каждого канала, перерисовывая холсты и анимируя сюжеты. Это делает это красиво. Проблема в том, что каждый раз, когда приложение воспроизводит следующий файл, он становится все медленнее, как будто все аудиоданные до этого еще где-то. Я нашел в документации метод close() из AudioContext():

"Метод close () интерфейса AudioContext закрывает аудиоконтент, высвобождая любые системные аудиоресурсы, которые он использует."

«Теперь AudioContext может быть явно закрыт, тем самым высвобождая любые аппаратные ресурсы, связанные с AudioContext. Без этого разработчикам приходилось полагаться на сборку мусора AudioContext для освобождения аппаратных ресурсов.»

Я также нашел этот пример закрытия и перезапуска звукового контекста:

https://github.com/mdn/webaudio-examples/blob/master/audiocontext-states/index.html

https://mdn.github.io/webaudio-examples/audiocontext-states/

Проблема в том, что я использую audioContext.createMediaElementSource(HTMLelementID), и он не позволяет мне перезапустить все, воссоздав все узлы, как в примере. Упрощенный код, который представляет то, что я делал раньше:


class Audio() {
   constructor(audioElementID, playlistObj) {
      this.audioContext = new AudioContext();
      this.audioElement = document.getElementById(audioElementID);
      this.track = this.audioContext.createMediaElementSource(this.audioElement);
      this.gainNode = this.audioContext.createGain();
      this.track.connect(this.gainNode);
      this.gainNode.connect(this.audioContext.destination);

      this.audioElement.addEventListener('ended', () => {
         playlistObj.playnextTrack() // changes the src from the html element (audioElementID) and sets this.audioElement.currentTime to 0
      }
   }
 // everything is a property here for debugging reasons 
}

const audio = new Audio('audioID', playlist);

// playlist defined somewhere else


Чтобы реализовать метод close(), мне пришлось изменить (в точности пример, функцию, которая воссоздает все заново):

class Audio() {
   constructor(audioElementID, playlistObj) {
      this.createAudioContext = () => {
         this.audioContext = new AudioContext();
         this.audioElement = document.getElementById(audioElementID);
         this.track = this.audioContext.createMediaElementSource(this.audioElement);
         this.gainNode = this.audioContext.createGain();
         this.track.connect(this.gainNode);
         this.gainNode.connect(this.audioContext.destination);

         this.audioElement.addEventListener('ended', () => {
            playlistObj.playNextTrack() // changes the src from the html element (audioElementID) and sets this.audioElement.currentTime to 0
         }
      }

      this.createAudioContext();
   } 
}

и в playlist.playNextTrack() я приостанавливаю audioElement, звоню audio.audioContext.close(), жду его (это обещание), звоню audio.createAudioContext(), чтобы воссоздать все и воспроизвести. Логика возвращает ошибку на this.track = this.audioContext.createMediaElementSource(this.audioElement) с:

"Не удалось выполнить 'createMediaElementSource' для 'BaseAudioContext': HTMLMediaElement, ранее уже подключенный к другому MediaElementSourceNode, в Audio.createAudioContext"

В данном примере источник звука - это просто случайный генератор, а не аудиофайл в формате mp3.

Я действительно застрял здесь. Не знаю что делать. Я даже не уверен, действительно ли AudioContext() хранит данные из всех аудиофайлов до возникновения проблемы с производительностью. И если да, то как я могу восстановить HTMLMediaElement в новый узел, созданный audio.createAudioContext()? Я уже пробовал audio.track.disconnect(), но это не работает (поскольку это не так, потому что здесь я отключаю track от gainNode). Кроме того, audioElement не имеет disconnect() метода, так как это всего лишь элемент HTML.

Есть идеи?

ОБНОВЛЕНИЕ:

Я решил проблему воссоздания звукового контекста, удаления и повторного создания элемента html. Но проблема сохраняется: чем больше новых аудиофайлов воспроизводится, тем медленнее приложение. Точнее теперь: чем больше создается новый AudioContext (), тем медленнее он становится (даже если я закрою предыдущий).

1 Ответ

0 голосов
/ 16 мая 2019

Я действительно застрял здесь. Не знаю что делать. Я даже не уверен, действительно ли AudioContext () хранит данные из всех аудиофайлов до возникновения проблемы с производительностью.

Нет, это действительно маловероятно. AudioContext устанавливает такие вещи, как частота дискретизации, место назначения вывода и график. Вот и все.

Метод close () интерфейса AudioContext закрывает аудиоконтент, высвобождая любые системные аудиоресурсы, которые он использует.

Вы неправильно понимаете, что это значит. Эти «системные аудио ресурсы» являются звуковыми устройствами. Во время работы AudioContext запрашивается аудиоустройство. Это особенно важно в условиях низкого энергопотребления, таких как мобильные Другим примером будет Bluetooth. Если AudioContext продолжает работать, ваша Bluetooth-гарнитура может просто оставаться включенной. Если AudioContext разрешено закрывать, гарнитура Bluetooth может перейти в спящий режим.

И если это так, как я могу повторно соединить элемент HTMLMedia с новым узлом audio.createAudioContext ()?

Вы нет. Хотя было бы неплохо, если бы API поддерживал это, похоже, что нет. Просто создайте новый HTMLMediaElement.

Что вы должны сделать, это правильно профилировать ваше приложение, чтобы выяснить, где происходит замедление. Используйте ваши инструменты разработчика. Может быть быстрее, хотя бы просто закомментировать разделы, которые работают. Мы определенно не можем сказать вам, где проблема, в частности, из кода, который вы показали.

...