(По общему совету ShpuntiK, обратил внимание на статью специалиста по фронтенду и особенно, по медиаформатам, разработчика из нескольких опенсорсных проектов и happyworm.com. Статья написана в мае 2012 и отражает современное состояние дел с поддержкой браузерами новых медиатегов и форматов. --прим. перев.)
Это продолжение моей (автора, Марка Боаса --прим. перев.) статьи 2009 года "Native Audio in the browser" (англ., и дополненной в октябре 2010 --прим. перев.), которая объясняет основы работы аудио в HTML5. Возможно, стоит почитать сначала её, если вы хотите почувствовать работу тега <audio> и связанного с ним API.
Теперь, через 2.5 года, пришло время посмотреть, как идут дела. При том, что многие продвинутые аудио API активно разрабатываются, улучшается воодушевляющая нас нативная браузерная поддержка звука — самое время вернуться в увлекательный мир тега <audio>.
Хороший способ понять, как идут дела — посмотреть несколько примеров использования, что мы увидим далее.
Как же нам начать? Есть несколько понятий, которые надо освоить для подготовки. Давайте сначала разберёмся в типах MIME.
Типы MIME
Серверная часть
Их называют ещё интернет медиа-типами — это один из способов сделать так, чтобы ваша система знала, как работать с медиаданными.
Прежде всего, сервер должен быть настроен для правильной поддержки MIME-типов. В случае Apache это означает, что в .htaccess имеются строки:
# AddType TYPE/SUBTYPE EXTENSION
AddType audio/mpeg mp3
AddType audio/mp4 m4a
AddType audio/ogg ogg
AddType audio/ogg oga
AddType audio/webm webma
AddType audio/wav wav
Совет: Не делайте gzip-сжатие медиафайлов на сервере. Большинство форматов уже сжаты, и есть некоторая поддержка для остальных. Кроме того, в запасном решении с флешем, он не поддерживает сжатия медиаданных. |
Клиентская часть
При описании источников данных в коде или разметке можно указать MIME-тип, который позволит браузеру определить данные правильно.
Самый надежный способ описать аудио HTML5 — примерно такой:
<audio>
<source src="elvis.mp3" type='audio/mpeg; codecs="mp3"'>
<source src="elvis.oga" type='audio/ogg; codecs="vorbis"'>
<!-- здесь - добавить запасные варианты тегов -->
</audio>
Здесь определяется тег и используемые источники данных. Браузер выберет только один — он не будет проигрывать их два или больше. В этом же коде размещаются резервные варианты обработки.
Вместе с адресом данных в атрибуте src указан атрибут type. Он не обязателен, но помогает браузеру узнать MIME-тип и кодеки для отдаваемого файла до того как он его загрузит. Если его нет, браузер пытается узнать тип из файла возможными способами.
Замечание: можно пропустить в атрибуте название кодека, но для надежности и эффективности я рекомендую помогать браузеру, давая максимум возможной информации. |
Отлично. Теперь мы знаем, как определить адрес файла, и браузер преспокойно выберет первый поддерживаемый им формат. А можем ли мы подать файл динамически?
Заранее узнать тип аудио поможет .canPlayType (наверное)
К счастью, API показывает, поддерживается ли данный формат файла в браузере. Но вначале — краткое описание того, как мы управляем тегом <audio>.
Если объект Audio описывается в HTML, доступ к объекту можно получить через DOM:
var audio = document.getElementsByTagName('audio')[index];
или, если определён id,
var audio = document.getElementById('my-audio-id');
Как вариант, объект создаётся полностью на Javascript.
var audio = new Audio();
Если есть объект Audio, то есть доступ к его методам и свойствам. Для проверки поддержки форматов используют метод canPlayType с параметром — текстовым значением MIME-типа.
audio.canPlayType('audio/ogg');
Можно даже явно указать кодек:
audio.canPlayType('audio/ogg; codecs="vorbis"');
canPlayType возвращает одно из 3 значений:
1) probably,
2) maybe, или
3) "" (пустая строка).
Смысл получения этих странных типов истекает из общей странности ситуации, в которой находятся кодеки, пока мы судим о них по типу. Без реальной попытки воспроизведения браузер может только догадываться о применимости кодека.
Итого, для проверки поддержки делаем:
var audio = new Audio();
var canPlayOgg = !!audio.canPlayType
&& audio.canPlayType('audio/ogg; codecs="vorbis"') != "";
Здесь проверяется что canPlayType поддерживается ("!" просто превращает объект строки в логический тип) и затем проверяется, что canPlayType нашего формата — не пустая строка. (Как-то нелогично с первой частью. Наверное, автор забыл упомянуть, что может вернуть undefined? --прим. перев.)
Поддержка различных кодеков в браузере
Посмотрим, как поддерживаются кодеки в современных браузерах.
Кодеки десктопных браузеров:
Десктопные версии | Номер | Поддержка кодеков |
---|---|---|
Internet Explorer | 9.0+ | MP3, AAC |
Chrome | 6.0+ | Ogg Vorbis, MP3, WAV (начиная с Chrome 9) |
Firefox | 3.6+ | Ogg Vorbis, WAV |
Safari | 5.0+ | MP3, AAC, WAV |
Opera | 10.0+ | Ogg Vorbis, WAV |
Кодеки мобильных:
Мобильные браузеры | Версия | Поддержка кодеков |
---|---|---|
Opera Mobile | 11.0+ | Device-dependent |
Android | 2.3+ | Device-dependent |
Mobile Safari | (iPhone, iPad, iPod Touch) iOS 3.0+ | MP3, AAC |
Blackberry | 6.0+ | MP3, AAC |
Хорошая новость — в том, что на момент написания статьи около 80% браузеров поддерживают HTML5 Audio.
Плохая новость — до сих пор нет договорённости об универсальной поддержке какого-либо кодека, поэтому сервер должен поддерживать и MP3, и Ogg Vorbis, чтобы максимально полно поддержать HTML5 Audio в браузерах.
Забавно: Android 2.2 поддерживает <video>, но не <audio>. Чтобы воспроизводить аудио, нужно использовать тег <video>. |
Контейнеры, форматы и расширения файлов (и снова эти MIME-типы)
Выше я упоминал об известных аудиоформатах, но технически мы должны работать с их форматом контейнера. (Контейнер может содержать более одного формата — например, MP4 может содержать AAC и AAC+.)
Container | Format(s) | File Extensions | MIME Type | Codec String |
---|---|---|---|---|
MP3 | MP3 | .mp3 | audio/mpeg | mp3 |
MP4 | AAC, AAC+ | .mp4, .m4a, .aac | audio/mp4 | mp4a.40.5 |
OGA/OGG | Ogg Vorbis | .oga, .ogg | audio/ogg | vorbis |
WAV | PCM | .wav | audio/wav | 1 |
Мы имеем <audio> и не боимся его использовать!
Ладно, мы кое-как запустили аудио-теги — и это работает. Что ещё хотелось бы сделать? Сейчас в каждом браузере элементы работают немного по-разному из-за настроек по умолчанию. Хочется немного подогнать их к единому виду. Для этого есть несколько свойств элемента <audio>.
Несколько самых используемых атрибутов:
Свойство | Описание | Возвращаемое значение |
---|---|---|
currentTime | позиция курсора проигрывателя | double (секунды) |
duration | длительность воспроизведения | double (секунды); только чтение |
muted | заглушен ли звук | boolean |
paused | остановлено ли воспроизведение | boolean |
volume | уровень громкости | double (от 0 до 1) |
Использовать их крайне просто. Например:
var audio = new Audio();
var duration = audio.duration;
Переменной duration присвоено значение длительности (в секундах) аудиоклипа.
Буферизация, поиск и временны́е диапазоны
Ситуация на этом фронте улучшается, разработчики браузеров начинают делать основную часть спецификации.
API даёт нам атрибуты buffered и seekable, когда хотим узнать, какая часть медиафайла была буферизована или предзагружена для воспроизведения без задержек. Они оба возвращают объект TimeRanges, который есть список интервалов — числа начала и конца.
Атрибут buffered
Возвращает интервалы полностью загруженных участков файла. Небольшой пример:
// возвращает объект TimeRanges буферизованного файла
var buffered = audio.buffered;
// выделяет время в секундах из сохранённого объекта TimeRange
var bufferedEnd = audio.buffered.end();
Объект TimeRanges
The TimeRanges object contains data on the parts on buffered media in the form of one or more — you guessed it — time ranges. A TimeRanges object consists of these properties:
Содержит данные о частях буферизованных участков медиафайла (один или более — сколько успело буферизоваться) и имеет свойства:
length — число интервалов,
start(index) — начальное время указанного интервала,
end(index) — конечное время указанного интервала
(отсчитывается от начала воспроизведения).
Забавно: По умолчанию размерность времени в JS Audio API — секунды, хотя традиционные функции в JS используют миллисекунды. |
------------------------------------------------------ //пример
|=============| |===========| |
------------------------------------------------------
0 5 15 19 21
Таким образом, в этом примере:
audio.buffered.length //returns 2
audio.buffered.start(0) //returns 0
audio.buffered.end(0) //returns 5
audio.buffered.start(1) //returns 15
audio.buffered.end(1) //returns 19
audio.buffered.end() //returns 19
В каких случаях может быть больше одного буферизованного интервала? Пользователь кликает впереди, на небуферизованном участке шкалы на блоке проигрывателя. Объект начинает новую буферизацию от точки клика, и возникают 2 интервала буферизации.
Совет: Большинство аудио-проигрывателей позволяет перемещаться на новые позиции файла во время загрузки, выполняя ряд запросов на сервер. В Apache множественный доступ к файлу разрешён по умолчанию, но надо убедиться в этом для сервера с неизвестными настройками. |
Заметим, что если пользователь активно переключает точку воспроизведения, буферизация имеет мало смысла. Некоторые браузеры могут прочитать конец файла, чтобы установить длительность записи, почти сразу создавая 2 интервала буфера. Поэтому прогресс-бар в проигрывателе несколько сложнее обычного контрола прогресс-бара с 1 интервалом.
Вы можете проверить TimeRanges вашего браузера в с помощью этого удобного HTML5 Media Event Inspector.
Seeking и Seekable
Поиск — это заглядывание вперёд или назад в медиафайл. Обычно это происходит, когда ещё не закончена полная буферизация файла. Атрибут seeking используется для указания на то, что призошло событие "seeked". True означает, что часть файла ещё не загружена.
Продолжение следует...
Примечание на сайте оригинала, html5doctor.com :
Эта статья написана Марком Боасом. Марк разрабатывает / преподает / описывает и продвигает новые и открытые веб-технологии. Сооснователь Happyworm — небольшой вебстудии, разрабатывающей, в частности, jPlayer Media Framework, он раздвигает возможности браузера с помощью HTML5 и JavaScript. Будучи универсалом в сердце, Марк большую часть времени занимается веб-медиа и протоколами реального времени. Любитель всего, относящегося к аудио, он сейчас страстно работает над задачей «сделать что-то новое» в его экспериментах в проекте Hyperaudio. Вы можете следить за твиттером Марка.
Далее в статье на английском — ещё половина содержания. Марк пишет подробно и несложно, но объём чтения для вечно спешащих читателей уже приблизился к объёму непринуждённого восприятия, поэтому, чтобы не заставлять откладывать чтение, остальное будет через пару дней. Содержание следующей части:
Замечание о предзагрузке
Забавно: Мобильный Safari игнорирует атрибут preload, который всегда в нём равен "none". |
Атрибут played
События медиа-объекта
Потоковое аудио
Эволюция спецификаций или «Эй, это дело движется!»
Когда браузеры уходят от спецификаций
Одновременное проигрывание нескольких аудио
Зависимость от ОС
Что нового?
Фрагменты медиа
Расширенное Audio API: будущее браузеров
Автор: spmbt