Защищённое медиа-аудио не воспроизводится в Safari при первом нажатии

(Вероятно, после обновления до версии 2.5.0 stable) защищённые аудиофайлы не воспроизводятся в Safari при первом нажатии. Чтобы запустить аудио, требуется два или три клика по значку воспроизведения. При первых кликах запрос на веб-сервер не отправляется. Запрос отправляется только примерно на третий клик.

Кажется, что это проблема браузера, так как она возникает только в Safari, но подозрительно, что это началось после обновления до версии 2.5.0.

У кого-нибудь был похожий опыт?

Не уверен, связано ли это с этим или нет. Срок действия защищённых медиафайлов истекает

@martin есть какие-то идеи?

Я займусь этим завтра. Если там требуется два-три клика, похоже, это проблема Safari. Проверю на своём iPhone.

Я могу подтвердить, что у меня это работает с ошибками на iOS как в Safari, так и в Firefox. Аудио не воспроизводится, пока не выполнить несколько нажатий на воспроизведение/паузу. Компонент виджета выглядит одинаково в обоих браузерах (я думаю, что мобильный Firefox — это просто обёртка вокруг движка рендеринга Safari для мобильных устройств). Я проверял это на iOS 13.5.1.

В трекере ошибок WebKit есть множество довольно свежих проблем, связанных с аудио, но я не уверен, относятся ли они к нашему случаю: https://bugs.webkit.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=product&field0-0-1=component&field0-0-2=alias&field0-0-3=short_desc&field0-0-4=status_whiteboard&field0-0-5=content&no_redirect=1&order=changeddate%20DESC%2Cbug_status%2Cpriority%2Cassigned_to%2Cbug_id&query_format=advanced&type0-0-0=substring&type0-0-1=substring&type0-0-2=substring&type0-0-3=substring&type0-0-4=substring&type0-0-5=matches&value0-0-0=audio&value0-0-1=audio&value0-0-2=audio&value0-0-3=audio&value0-0-4=audio&value0-0-5="audio".

Аудиофрагмент с w3schools у меня работает в Safari и Firefox для iOS: W3Schools Tryit Editor. Возможно, проблема в том, что мы используем preload="none"? Это единственное отличие, которое я могу вспомнить… или же проблема вызвана нашим редиректом 302 с защищённого URL медиафайла на фактический URL аудио?

Некоторые возможные подсказки, которые заставляют меня думать, что проблема именно в редиректе:

Похоже, что при первых кликах запрос на сервер не отправляется, значит проблема возникает до редиректа 302…

@martin, удалось ли тебе найти что-либо по этому вопросу?

К сожалению, нет, я был занят другими проектами. Однако это есть в моем списке, и я надеюсь скоро начать более тщательно его изучать. Мы также кратко обсуждали подобные вопросы внутри компании.

Пока это было настоящим приключением… Мне удалось настроить удалённую отладку между Chrome на моём компьютере с Ubuntu и Safari на iOS на iPhone, несмотря на множество трудностей. Однако, что раздражает, вкладка «Network» (Сеть) остаётся пустой, хотя именно она для этой задачи наиболее важна.

Я обнаружил, что установка атрибута preload="metadata" позволяет аудио воспроизводиться при первом нажатии в Safari на iOS, тогда как при preload="none" требуется последовательность «Воспроизвести > Пауза > Воспроизвести», чтобы аудио действительно началось.

Я проверил это на теге video, и похоже, что здесь возникает аналогичная проблема.

Переход на preload="none" был сделан из-за вашего сообщения об ошибке здесь: Secure media uploads expire. Сейчас мы находимся в некой неприятной серой зоне: если вернуть preload к значению metadata, вышеописанная проблема вернётся. Недавно мы увеличили срок действия подписанных URL до 5 минут (FIX: Increase time of DOWNLOAD_URL_EXPIRES_AFTER_SECONDS to 5 minutes by martin-brennan · Pull Request #10160 · discourse/discourse · GitHub), поэтому исходная ошибка станет менее актуальной… но всё ещё останется проблемой.

Я всё ещё обдумываю это и экспериментирую с настройками… Не уверен, что сможем получить лучшее из обоих миров. Для защищённых медиафайлов требование нескольких нажатий для просмотра — не идеальный опыт.

Редактирование: мне удалось заставить вкладку «Network» в отладчике работать. Пример на нашем внутреннем экземпляре Discourse для тега audio с preload="none":

  1. Нажать «Воспроизвести»: GET /secure-media-uploads/dev/original/4X/6/1/8/618a6b19a07de18205cc9889cb604e414b30372b.mp3, статус — Finished (Завершено).

  2. Нажать «Пауза».

  3. Нажать «Воспроизвести»: GET presigned_url_here, статус — 206 Partial Content, аудио загружается корректно.

Странность в том, что с preload=“metadata” мы получаем точно такую же последовательность запросов, но при одном нажатии «Воспроизвести». Получается, что Safari сначала загружает метаданные при первом нажатии «Воспроизвести», а затем требует паузу и повторное нажатие «Воспроизвести», чтобы начать воспроизведение аудио.

Не уверен, происходит ли это на других устройствах, например, на Android? У меня нет устройства для тестирования там.

Это впечатляющая сессия отладки!

Один вопрос:

Как выглядит этот ответ? Finished — это не код HTTP-ответа, верно?

Спасибо!

Отличный вопрос! Да, вы правы: Finished — это не код статуса. В вкладке «Сеть» я не получаю никакой дополнительной информации:

Размер составляет 0 Б, а время — 0 мс.

Это побудило меня настроить mitmproxy и ещё раз внимательно посмотреть, что здесь происходит. Похоже, что первый запрос «Finished» не покидает устройство iOS / браузер Safari. Прокси mitm не регистрирует ничего до тех пор, пока не будет нажата кнопка PLAY во второй раз.

Имеет ли смысл использовать preload="metadata" только для Safari (и на iOS, и на десктопе — я могу воспроизвести это на десктопе тоже), а preload="none" — в остальных случаях?

(Кроме того, у меня это не наблюдается на Android, я тестировал в PWA.)

Да, я думаю, нам придётся пойти этим путём. Спасибо за тестирование на Android и Safari для десктопа. Атрибут preload в данный момент не работает, так что, полагаю, нам понадобится клиентский код для определения Safari и замены атрибута preload. Сегодня проведу несколько экспериментов с этим.

Чтобы убедиться, что я всё правильно понял, ошибка проявится в аудиофайлах, когда Safari создаст точку разделения загрузки после истечения 5 минут?

Да, но с этим новым исправлением я, думаю, могу обойти проблему, меняя атрибут preload только тогда, когда пост с медиафайлом появляется на экране (например, при прокрутке). Проблема в том, что как только метаданные загружаются с защищённого URL медиафайла, генерируется предподписанный URL, который используется в плеере и истекает через 5 минут. Таким образом, если вы не нажмёте «Воспроизвести» в течение этих 5 минут, URL устареет.

Мне интересно, можно ли с помощью JavaScript воспроизвести, а затем поставить медиафайл на паузу, и повлияет ли это на последующие запросы частичного контента (206), которые, похоже, не зависят от срока действия предподписанного URL. Хотя я могу ошибаться, нужно ещё немного поэкспериментировать.

Редактирование: Я сам подтвердил на устройстве Android с браузером Chrome, что этой проблемы там нет.

С благословения @martinwoodward сегодня я сделал несколько коммитов, в которых для всех элементов аудио/видео во всех контекстах, включая защищённые медиа, теперь используется preload="metadata". Это должно устранить описанную здесь проблему.

Обратите внимание: если пользователь останется на странице дольше 5 минут, он, скорее всего, не сможет воспроизвести аудио или видео, так как защищённые URL-адреса в настоящее время действительны только в течение 5 минут.

Извините за поздний ответ — эта проблема действительно исправлена :tada:

Спасибо @pmusaraj и @martin!