У меня есть аудиоплеер JavaScript с вторыми кнопками перехода вперед / назад 10. Я делаю это, устанавливая currentTime своего аудиоэлемента:
function Player(skipTime)
{
this.skipTime = skipTime;
this.waitLoad = false;
// initialise main narration audio
this.narration = new Audio(getFileName(dynamicNarration));
this.narration.preload = "auto";
this.narration.addEventListener('canplaythrough', () => { this.loaded(); });
this.narration.addEventListener('timeupdate', () => { this.seek(); });
this.narration.addEventListener('ended', () => { this.ended(); });
this.narration.addEventListener('waiting', () => { this.audioWaiting(); });
this.narration.addEventListener('playing', () => { this.loaded(); });
}
Player.prototype = {
rew: function rew()
{
if (!this.waitLoad) {
this.skip(-this.skipTime);
}
},
ffw: function ffw()
{
if (!this.waitLoad) {
this.skip(this.skipTime);
}
},
skip: function skip(amount)
{
const curTime = this.narration.currentTime;
const newTime = curTime + amount;
console.info(`Changing currentTime (${curTime}) to ${newTime}`);
this.narration.currentTime = newTime;
console.info(`Result: currentTime = ${this.narration.currentTime}`);
},
loaded: function loaded()
{
if (this.waitLoad) {
this.waitLoad = false;
playButton.removeClass('loading');
}
},
audioWaiting: function audioWaiting()
{
if (!this.waitLoad) {
this.waitLoad = true;
playButton.addClass('loading');
}
},
}
(Я включаю сюда некоторые из прослушивателей событий, которые я прикрепляю, потому что раньше я отлаживал аналогичную проблему, связанную с конфликтами в прослушивателях событий. Однако, на этот раз тщательно отладив прослушиватели событий, я не считать, который является корневым проблемы.)
Хотя все это отлично работает на моей локальной копии, когда я тестирую онлайн-версию, я получаю следующие результаты:
0. Последняя строка консоли гласит Результат: currentTime = 0.console.info дает значение для currentTime, равное newTime (хотя позиция воспроизведения фактически не меняется).currentTime, равное newTime.Проблема должна быть связана со способом загрузки звука. Я попытался добавить еще одну строку журнала консоли, чтобы показать начальное и конечное значения для buffered.
В Chrome он увеличивается до 2 секунд после текущей позиции воспроизведения. В Safari он достигает ~170 секунд, а в Firefox он, кажется, буферизует полную длину звука.
Однако в каждом случае начало объекта buffered - это 0.
Кто-нибудь знает, что может пойти не так?
@lgid Можете ли вы предоставить образец файла, который вы используете? Что это за тип? Я пробовал ваш код с файлом mp3, который где-то размещен, и он работает, как ожидалось.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если ваш браузер не загрузил звук, звук не может быть воспроизведен. Браузер не знает ваш аудиофайл и из-за этого пытается воспроизвести его с самого начала. Может быть, ваш звук будет длиться всего 1 секунду или даже короче.
Решение
Вам нужно дождаться события loadedmetadata, и после него вы можете играть свою аудиторию из любой временной позиции. После этого события ваш браузер узнает всю необходимую информацию о вашем аудиофайле.
Пожалуйста, измените свой код следующим образом:
function Player(skipTime)
{
this.skipTime = skipTime;
// initialise main narration audio
this.narration = new Audio(getFileName(dynamicNarration));
this.narration.preload = "auto";
this.narration.addEventListener('canplaythrough', () => { this.loaded(); });
this.narration.addEventListener('timeupdate', () => { this.seek(); });
this.narration.addEventListener('ended', () => { this.ended(); });
this.narration.addEventListener('waiting', () => { this.audioWaiting(); });
this.narration.addEventListener('playing', () => { this.loaded(); });
this.narration.addEventListener('loadedmetadata', () => {playButton.removeClass('loading');});
playButton.addClass('loading');
}
Player.prototype =
{
rew: function()
{
this.skip(-this.skipTime);
},
ffw: function()
{
this.skip(this.skipTime);
},
skip: function(amount)
{
var curTime = this.narration.currentTime;
var newTime = curTime + amount;
console.info(`Changing currentTime (${curTime}) to ${newTime}`);
this.narration.currentTime = newTime;
console.info(`Result: currentTime = ${this.narration.currentTime}`);
}
};
Но если вы не хотите долго ждать загрузки звука, у вас есть только один вариант: преобразовать все ваши аудиофайлы в формат dataURL, который выглядит следующим образом:
var data = "data:audio/mp3;base64,...
Но в этом случае придется ждать загрузки страницы даже больше, чем загрузки одного аудиофайла. А при загрузке аудиофайла это только метаданные, и это быстрее.
Я также попытался добавить прослушиватель событий loadedmetadata. Однако, поскольку это происходит, когда звук уже воспроизводится, метаданные уже давно загружены. Фактически, я использую продолжительность в других частях логики игрока.
@Igid, я в твоем коде ничего не вижу с длительностью. Я правильно ответил на ваш вопрос или нет? Если вас устраивает мой ответ, отметьте его как принятый слева от моего ответа и / или проголосуйте за него.
Я имел в виду, что мой фактический производственный код также использует продолжительность, она не включена в мой упрощенный пример. Спасибо за ваш ответ, но нет, ожидание загрузки метаданных мне не помогает, поскольку они загружаются задолго до того, как я даже воспроизвожу файл.
@Igid, но это единственный способ воспроизвести файлы в Интернете. Вашим локальным файлам это не нужно, и вы можете воспроизводить их сразу после загрузки страницы, но с онлайн-файлами - у вас есть только один способ - вам нужно дождаться события loadedmetadata. И это долго, потому что ваша страница уже загружена в браузере и метаданные из файлов должны быть загружены с вашего сервера после загрузки страницы.
Я проверил это, добавив прослушиватель событий с журналом консоли. Событие loadedmetadata срабатывает до того, как я нажму кнопку воспроизведения. Так что ожидание этого события не решит мою проблему.
Я нашел решение своей проблемы, если не совсем объяснение.
Мой хостинг-провайдер использует CDN, для которого он должен заменить URL-адреса ресурсов на URL-адреса другого домена. URL-адреса моих аудиоресурсов динамически создаются JS, потому что в них есть случайный элемент; Таким образом, процесс развертывания, который заменяет URL-адреса, не улавливал их для моих аудиофайлов. Чтобы обойти это, я вручную исключил аудиофайлы из CDN, то есть я мог ссылаться на них, используя относительные пути к файлам.
Так было, когда у меня возникла эта проблема.
Затем, из-за отдельной проблемы, я применил другой подход: я получил аудиофайлы обратно в CDN и написал функцию для извлечения доменного имени, которое мне нужно было использовать для извлечения файлов. Когда я это сделал, я внезапно обнаружил, что все мои проблемы, связанные с настройкой currentTime, исчезли. Почему-то отсутствие файлов в CDN серьезно мешало браузеру загружать их упорядоченным образом.
Если кто-нибудь может добровольно объяснить, почему это могло быть, мне было бы очень любопытно это услышать ...
Я работал над другим проектом, который включает потоковую передачу звука, на этот раз также с поддержкой PWA, поэтому мне пришлось реализовать механизм кэширования в моем сервис-воркере для аудиофайлов. Благодаря это руководство я узнал все о подводных камнях диапазон запросов и теперь понимаю, что неспособность обслуживать правильные ответы на запросы с заголовками диапазонов нарушит поиск в некоторых браузерах.
Похоже, что в приведенном выше случае, когда я исключил свои файлы из CDN, они обслуживались откуда-то, что не поддерживало заголовки диапазонов. Когда я переместил их обратно в CDN, это было исправлено, так как он должен был быть построен с явной поддержкой потокового мультимедиа.
Здесь - хорошее объяснение правильных ответов на запросы диапазона. Но для тех, кто сталкивается с этой проблемой при использовании сторонней службы хостинга, достаточно знать, что они, вероятно, не поддерживают заголовки диапазонов для потокового мультимедиа. Если вы хотите убедиться, что это так, вы можете запросить продолжительность звукового объекта. По крайней мере, в случае Safari продолжительность установлена на бесконечность, когда он не может успешно выполнить запрос диапазона, и в этот момент поиск будет отключен.
Это решило мою проблему ...
private refreshSrc() {
const src = this.media.src;
this.media.src = '';
this.media.src = src;
}
Есть некоторые требования для правильной загрузки аудиофайла и использования свойств. Ваш ответ при обслуживании файла должен иметь следующие заголовки.
диапазоны приема: байты
Длина содержимого: BYTE_LENGTH_OF_YOUR_FILE
Content-Range: байты 0-BYTE_LENGTH_OF_YOUR_FILE / BYTE_LENGTH_OF_YOUR_FILE
тип содержимого: аудио / mp3
Мои коллеги и я боролись над этим несколько дней, и, наконец, это сработало.
Изображение заголовка ответа для аудиофайла
Какое совпадение, что вы добавляете этот ответ сейчас! Я только что погрузился в мир потокового аудио и, реализовав механизм кэширования сервис-воркеров для аудиофайлов на PWA, я узнал все о заголовках диапазонов за последние несколько дней. Я добавляю объяснение к своему собственному ответу и голосую за него.
Игид, если вас устраивает мой ответ ниже, отметьте его как принятый слева от моего ответа или напишите мне отзыв.