currentTime устанавливается в другое значение после события loadmetadata во время поиска

В настоящее время я нахожусь в приключении, на карту которого поставлено мое здравомыслие, когда я пытаюсь просто воспроизвести mp3-файл в своем веб-приложении. Этот mp3 загружается по частям, чтобы сделать его более отзывчивым.

Несмотря на то, что документация MediaSource API просто удивительно, почти невероятно полезна, и сотни хорошо объясненных примеров прокладывают путь к спасению, я не могу заставить все работать правильно.

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

Все пока работает, за исключением одного последнего момента: currentTime получает другое значение после того, как я установил время, запрошенное пользователем.

Трек продолжает воспроизводиться, как и ожидалось, но проблема заключается в том, что currentTime используется для визуализации текущего местоположения в треке для пользователя.

Вот как происходят события до и после того, как пользователь ищет

[play-click]    <--- User clicks play button
 :
[timeupdate]    currentTime: 00.01
[timeupdate]    currentTime: 00.02
[timeupdate]    currentTime: 00.03
[seek-click]    <--- User seeks, stop() is called and then playFrom(seconds)
[loadstart]     currentTime: 33.33  # This is the (correct) time set in playFrom(seconds)
[loadmetadata]  currentTime: 10.12  # Now the time gets set to this (wrong) value
[seek]          currentTime: 10.12  # The triggered seek event comes in
[seeked]        currentTime: 10.12  
[canplay]       currentTime: 10.12
[playing]       currentTime: 10.12
[timeupdate]    currentTime: 10.13  # Track continues to play correctly but this value is still wrong
 :

Вот как происходит поиск:

public play(track: Track) {
  this.track = track;
  this.playFrom(0);
}

public seekTo(seconds: number) {
  this.stop();
  this.playFrom(seconds);
}

public stop() {
  this.logger.debug('Stop ..');
  this.sourceBuffer.abort();
  this.audioObj.pause();
  this.removeEvents(this.audioObj, this.audioEvents, this.audioEventsHandler);
  this.audioObj = null;
  this.sourceBuffer = null;
  this.mediaSource = null;
}

Теперь метод playFrom(seconds) немного сложнее, но все, что он на самом деле делает, это воссоздает все, что я только что уничтожил:

private playFrom(seconds: number) {

  this.logger.debug(`Start playing from ${seconds.toFixed(2)} seconds`)

  // [:] (collapsed some less important code here)

  // Create the media source object
  this.mediaSource = new MediaSource();
  this.mediaSource.addEventListener('sourceopen', this.onSourceOpen);

  // Create audio element
  this.audioObj = document.createElement('audio');
  this.audioObj.src = URL.createObjectURL(this.mediaSource);
  this.audioObj.currentTime = seconds;
  this.addEvents(this.audioObj, this.audioEvents, this.audioEventsHandler);

  this.logger.debug(`Object-url: ${this.audioObj.src}`);

  this.state = {currentTime: seconds, playing: true};
}

Как я могу получить правильное текущее время здесь?

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


person Stefan Falk    schedule 27.09.2020    source источник


Ответы (1)


Какова продолжительность, сообщаемая MediaSource (или медиа-элементом) во время выполнения поиска к медиа-элементу? Если он бесконечен, вам может потребоваться использовать API-интерфейсы {set,clear}LiveSeekableRange в MSE, чтобы сообщить реализации, хотите ли вы, чтобы проигрыватель выполнял поиск за пределами максимального времени окончания представления текущего буферизованного мультимедиа. В качестве альтернативы вы могли бы установить продолжительность MediaSource, прежде чем стремиться к чему-то конечному, но, по крайней мере, столь же высокому, как время окончания самого высокого в настоящее время буферизованного мультимедийного представления.

person Matt Wolenetz    schedule 28.09.2020
comment
Это также может помочь не сжечь все дотла; в расширенном HTMLMediaElement есть сложность в том, как обрабатывать поиск, когда readyState не = HAVE_METADATA. Если все, что вы хотите сделать, это прервать текущее добавление и начать буферизацию заново, затем выполните abort(), затем удалите все (sourceBuffer.remove(0,MediaSource.duration)), затем продолжите. Игроки обычно не удаляют медиаданные явно, а оставляют это MSE для удаления при необходимости в начале каждого appendBuffer(). Так что выяснить, почему вам нужно сжигать его в начале каждого поиска, вероятно, также было бы хорошо. - person Matt Wolenetz; 29.09.2020