В настоящее время я нахожусь в приключении, на карту которого поставлено мое здравомыслие, когда я пытаюсь просто воспроизвести 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
и позволить ему воспроизводить звук оттуда, но я тоже не смог этого сделать.