Как воспроизводить медиафайлы последовательно без видимого перерыва? - PullRequest
1 голос
/ 17 октября 2019

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


Во-первых, общая картина:

Я отправляю аудио на несколькоP2P клиенты, которые будут подключать и отключать случайные интервалы. Аудио, которое я посылаю, является потоком, но каждому клиенту нужна только часть потока, откуда он подключен. Вот как я решил, что:

  • Каждый {тайм-аут} (например, 1000 мс) создайте новый звуковой BLOB-объект
    • BLOB-файл будет полным аудиофайлом со всеми метаданными, которые должны бытьиграбельно
  • Как только будет создан BLOB-объект, преобразуйте его в буфер массива (улучшенная поддержка браузера) и загрузите на клиент через WebRTC (или WebSockets, если они не поддерживают)

Это хорошо работает. Задержка есть, но если вы удерживаете тайм-аут достаточно низким, это нормально.


Теперь мой вопрос:

Как я могу воспроизводить свой «поток», не имеялюбая задержка звука?

Я говорю поток, но я не реализовал его с помощью API Streams, это очередь больших двоичных объектов, которая обновляется каждый раз, когда клиент получает новые данные.

Я пробовал много разных вещей, таких как:

  • Создание BufferSource и объединение двух BLOB-объектов (преобразованных в AudioBuffers) с последующим воспроизведением этого
  • Передача реального потока изПотоковый API для клиентов вместо BLOB-объектов
  • Последовательное воспроизведение BLOB-объектов, опираясь на ended событие
  • Загрузка следующего BLOB-объекта во время воспроизведения текущего BLOB-объекта

У каждого есть проблемы,трудности или все же приводят к звуковой задержке.

Вот моя самая последняя попытка:

let firstTime = true;
const chunks = [];
Events.on('audio-received', ({ detail: audioChunk }) => {
    chunks.push(audioChunk);

    if (firstTime && chunks.length > 2) {
        const currentAudio = document.createElement("audio");
        currentAudio.controls = true;
        currentAudio.preload = 'auto';
        document.body.appendChild(currentAudio);
        currentAudio.src = URL.createObjectURL(chunks.shift());
        currentAudio.play();

        const nextAudio = document.createElement("audio");
        nextAudio.controls = true;
        nextAudio.preload = 'auto';
        document.body.appendChild(nextAudio);
        nextAudio.src = URL.createObjectURL(chunks.shift());

        let currentAudioStartTime, nextAudioStartTime;

        currentAudio.addEventListener("ended", () => {
            nextAudio.play()
            nextAudioStartTime = new Date();
            if (chunks.length) {
                currentAudio.src = URL.createObjectURL(chunks.shift());
            }
        });
        nextAudio.addEventListener("ended", () => {
            currentAudio.play()
            currentAudioStartTime = new Date();
            console.log(currentAudioStartTime - nextAudioStartTime)
            if (chunks.length) {
                nextAudio.src = URL.createObjectURL(chunks.shift());
            }
        });

        firstTime = false;
    }
});

Событие audio-received вызывается каждые ~ 1000 мс. Этот код работает;он воспроизводит каждый «фрагмент» после того, как проигрывался последний, но в Chrome задержка ~ 300 мс очень слышна. Он воспроизводит первый фрагмент, затем замолкает, затем воспроизводит второй, и так далее. На Firefox задержка составляет 50 мс.

Вы можете мне помочь?

Я могу попытаться создать воспроизводимый пример, если это поможет.

...