Рекордер MediaRecorder API не будет вызывать остановку при записи нескольких треков

У меня очень странная проблема с API MediaRecorder, которую я не мог исправить последние два дня.

Этот упрощенный пример отлично работает: когда я нажимаю кнопку «Прекратить совместное использование» пользовательского интерфейса Chrome, все останавливается соответствующим образом:

desktopStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: true,
});

let rec = new MediaRecorder(desktopStream, {
    mimeType: "video/webm; codecs=vp8,opus",
});

rec.onstop = async () => {
  desktopStream.getTracks().forEach((s) => s.stop());
  desktopStream = null;

  //blobs.push(MediaRecorder.requestData());
  blob = new Blob(blobs, {
    type: "video/webm",
  });
};

Однако это не так, он продолжает запись (или некоторые MediaTracks продолжают работать, не совсем уверен):

desktopStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: true,
});

voiceStream = await navigator.mediaDevices.getUserMedia({
    video: false,
    audio: true,
  });

// this is the culprit, when commented everything works as expected
desktopStream.addTrack(voiceStream.getAudioTracks()[0]);

let rec = new MediaRecorder(desktopStream, {
    mimeType: "video/webm; codecs=vp8,opus",
});

rec.onstop = async () => {
  //explicitly stop tracks
  desktopStream.getTracks().forEach((s) => s.stop();
  voiceStream.getTracks().forEach((s) => s.stop());

  desktopStream = null;
  voiceStream = null;

  //blobs.push(MediaRecorder.requestData());
  blob = new Blob(blobs, {
    type: "video/webm",
  });
};

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

Вот полный сценарий: https://jsfiddle.net/agcty/xhb0c4o3/19/

Действия по воспроизведению:

  1. Нажмите "Начать запись"
  2. Выбрать экран
  3. Сделайте что-нибудь в течение нескольких секунд
  4. Нажмите кнопку Chrome "Остановить совместный доступ", а не кнопку на скрипке.
  5. Красный значок записи по-прежнему будет отображаться, и вы не сможете загрузить запись, нажав «Загрузить».
  6. Нажмите «Остановить запись» (кнопка на скрипке), теперь запись правильно остановлена.
  7. Теперь прокомментируйте строку «desktopStream.addTrack (voiceStream.getAudioTracks () [0]);»
  8. Все работает

введите описание изображения здесь


person Alex Gogl    schedule 23.05.2020    source источник


Ответы (1)


Хорошо, после очень и очень обширной отладки я обнаружил, что когда вы нажимаете кнопку «Прекратить совместное использование», рекордер фактически не останавливается. Это было неправильное предположение, которое я сделал из-за формулировки.

Согласно документации (https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/onstop) рекордер останавливается, когда останавливаются все записываемые потоки MediaStream или когда рекордер останавливается вручную.

«Stop Sharing» останавливает только screenStream MediaTracks. Никаких перегрузок не происходит. Первый пример сработал, потому что это был единственный захваченный поток, поэтому его остановка означала, что onstop вызывается автоматически.

Визуально это выглядит так:

введите описание изображения здесь

Обходной путь несколько скрыт, но работает прекрасно:

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

screenStream.getTracks().forEach((track) =>
      track.addEventListener("ended", () => {
        voiceStream.getAudioTracks().forEach((audio) => audio.stop());
        if (recorder) recorder.stop();
        recorder = null;
      })
    ); 
person Alex Gogl    schedule 23.05.2020