Звук в HLS, DASH и CMAF: как плеер на самом деле выбирает аудиодорожку

Автор: Николай СапуновОбновлено: август 202622 мин чтения
Содержание статьи +

Опубликовано: 2026-06-05 · Время чтения: 21 мин · Автор: Nikolay Sapunov, CEO в Фора Софт

Кратко

Когда видео идёт по интернету, плеер скачивает небольшой текстовый файл – манифест, – где перечислены все доступные аудиодорожки, и решение, какую из них играть, принимает плеер, а не сервер. В HLS от Apple аудиодорожки собраны в именованную «группу рендиций» с помощью тегов EXT-X-MEDIA, и каждое качество видео ссылается на ту группу, которую может использовать; в MPEG-DASH каждый язык или раскладка каналов – это отдельный AdaptationSet, содержащий несколько битрейтных Representation. CMAF – это общий формат файлов под обоими, поэтому один набор аудиосегментов может одновременно питать манифест HLS и манифест DASH. Большинство ошибок вида «приложение включило не тот язык» и «не могу переключиться на surround» возникает из того, как заданы эти группировки и их флаги DEFAULT / AUTOSELECT / Role, а не из самих аудиофайлов.

Почему это важно

Если вы отдаёте видео по запросу или в прямом эфире в браузер, на телефон, смарт-ТВ или приставку, ваш плеер выбирает аудиодорожку для зрителя в каждой сессии, и управляете вы этим выбором только через манифест. Эта статья для менеджера продукта, основателя или операционного руководителя без опыта в стриминге, которому нужно понять, почему испаноязычный зритель получил английский звук, почему дорожка 5.1 так и не появилась или почему рекламная вставка сбила синхронизацию, – и обсудить это с инженерами. К концу вы сможете прочитать аудиочасть манифеста HLS или DASH, назвать тег, который задаёт дорожку по умолчанию, и узнаете, какие ошибки вёрстки манифеста вызывают самые частые жалобы. Каждое правило опирается на управляющую спецификацию – спецификацию HLS, ISO/IEC 23009-1 для DASH, ISO/IEC 23000-19 для CMAF, – а не на пересказ вендора.

Одна идея, объясняющая всё: выбирает плеер

Начнём с модели, на которой держится вся остальная статья. В стриминговом видео сервер не передаёт зрителю выбранную аудиодорожку. Вместо этого сервер публикует меню – небольшой текстовый файл, называемый манифестом, – а плеер на устройстве зрителя читает это меню и решает, что скачать. Звук, который вы слышите, выбрал код, работающий на телефоне или телевизоре, по правилам, которые вы вписали в манифест неделями раньше.

Это противоположность телефонному звонку, где живое согласование выбирает кодек для обоих концов, и противоположность скачанному файлу, где звук – это просто то, что внутри. Стриминговый манифест больше похож на ресторанное меню с отмеченной «рекомендацией шефа»: кухня перечисляет все блюда, помечает одно как выбор по умолчанию, отмечает некоторые как доступные по запросу, а посетитель – здесь плеер – делает окончательный выбор. Если в меню рекомендацией помечено не то блюдо, каждый посетитель, который не выбирает сам, получает не то. Запомните это: почти каждая ошибка выбора звука – это ошибка вёрстки меню.

В открытом интернете 2026 года доминируют два формата манифеста. HTTP Live Streaming (HLS) от Apple использует плейлист в построчном текстовом формате. Dynamic Adaptive Streaming over HTTP (DASH) от MPEG использует XML-документ под названием Media Presentation Description, или MPD. Они описывают один и тот же контент на разных диалектах, и одна библиотека медиафайлов – упакованная как CMAF, который мы разберём в конце, – может описываться обоими сразу.

Рис. 1. Сервер публикует меню, плеер выбирает. Одна библиотека сегментов CMAF может описываться плейлистом HLS и MPD DASH сразу; плеер читает тот, который понимает его платформа, и выбирает из него аудиодорожку.

Как HLS описывает звук: группы рендиций

В HLS меню верхнего уровня называется мультивариантным плейлистом (в старых документах – master playlist). Он делает две вещи: перечисляет уровни качества видео и перечисляет альтернативные аудиодорожки. Аудиодорожки описываются тегом EXT-X-MEDIA, и приём, заставляющий HLS работать, в том, что эти дорожки собраны в именованный набор – группу рендиций.

Группа рендиций – это просто метка. Каждая аудиодорожка с одним и тем же значением GROUP-ID принадлежит одной группе. Затем каждый уровень качества видео – записанный тегом EXT-X-STREAM-INF – несёт атрибут AUDIO, называющий группу, из которой ему позволено брать звук. Видео как бы говорит: «для своей дорожки бери любую из группы под названием aac-stereo». Эта косвенность позволяет плееру переключать качество видео вверх-вниз по мере изменения сети, сохраняя играть тот же выбранный язык.

Вот минимальный мультивариантный плейлист с тремя языками стерео-AAC и двумя качествами видео:

#EXTM3U
#EXT-X-VERSION:7

# --- группа рендиций "aud-aac" ---
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud-aac",NAME="English",LANGUAGE="en",DEFAULT=YES,AUTOSELECT=YES,CHANNELS="2",URI="audio/en/main.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud-aac",NAME="Spanish",LANGUAGE="es",DEFAULT=NO,AUTOSELECT=YES,CHANNELS="2",URI="audio/es/main.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud-aac",NAME="Commentary",LANGUAGE="en",DEFAULT=NO,AUTOSELECT=NO,CHANNELS="2",URI="audio/commentary/main.m3u8"

# --- варианты видео, оба ссылаются на одну аудиогруппу ---
#EXT-X-STREAM-INF:BANDWIDTH=2200000,CODECS="avc1.640028,mp4a.40.2",AUDIO="aud-aac"
video/720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=6000000,CODECS="avc1.640028,mp4a.40.2",AUDIO="aud-aac"
video/1080p.m3u8

Читайте так, как читает плеер. Есть одна аудиогруппа aud-aac с тремя дорожками. Оба качества видео указывают на неё, поэтому на каком бы разрешении плеер ни оказался, у него те же три дорожки на выбор. Теперь посмотрите на три атрибута, решающих, какая дорожка играет.

DEFAULT помечает дорожку, которую плеер должен выбрать, когда пользователь не выразил предпочтения. Обычно ровно одна дорожка в группе помечена DEFAULT=YES; здесь это английский. AUTOSELECT помечает дорожки, на которые плеер вправе переключиться сам, чтобы удовлетворить системную настройку – например, если язык устройства испанский, плеер может сам выбрать испанскую дорожку, хотя по умолчанию стоит английский, потому что у испанской AUTOSELECT=YES. У дорожки комментария AUTOSELECT=NO, что значит: плеер никогда не должен выбирать её автоматически; зритель обязан запросить её по имени. Атрибут CHANNELS указывает число каналов – "2" для стерео, – а дорожка 5.1 несла бы CHANNELS="6".

«Ловушка – две дорожки с DEFAULT=YES или ни одной. Самая частая ошибка звука в HLS – пометить более одной дорожки в группе как DEFAULT=YES или забыть пометить хоть одну. Спецификация ожидает не более одной дорожки по умолчанию на группу; поставьте две – и разные плееры разрешают конфликт по-разному: одни берут первую, другие последнюю, третьи язык устройства, – и зрители получают невоспроизводимый разнобой. Помечайте ровно одну DEFAULT=YES на группу, а остальное доверьте AUTOSELECT и LANGUAGE.»

Почему surround обычно получает свою группу

Стерео и surround 5.1 – это не просто две дорожки в одном списке. Спецификация авторинга HLS от Apple прямо требует разбивать звук с разным числом каналов на отдельные группы, с отдельными атрибутами AUDIO у вариантов видео, которые им соответствуют. Причина – бюджет битрейта: дорожка 5.1 стоит куда больше бит, чем стереодорожка, поэтому группа 5.1 связывается с высокобитрейтными вариантами видео, а стереогруппа обслуживает нижние. Если положить стерео 192 kbit/s и surround 640 kbit/s в одну группу, плеер сможет спарить тяжёлый звук с лёгким видео и сломать арифметику битрейта, которую обещают варианты.

Практическая форма, таким образом, – две группы, aud-aac-stereo и aud-ac3-51, и каждый вариант видео перечисляет аудиогруппу, подходящую его битрейтному уровню. Сам компромисс по битрейту мы разбираем в статье аудио-лестницы адаптивного битрейта.

Как DASH описывает звук: AdaptationSet и Representation

DASH несёт ту же информацию в другом контейнере. Его манифест, MPD, – это XML, и он вкладывает медиа в три уровня, которые нужно держать раздельно.

Period – это отрезок таймлайна: основной фильм – один Period; вставленная рекламная пауза обычно другой Period. Внутри Period сидят AdaptationSet, и AdaptationSet группирует взаимозаменяемые версии одного компонента. Внутри каждого AdaptationSet сидят Representation – собственно закодированные файлы на разных битрейтах. Важное для звука правило: каждый язык и каждая отдельная раскладка каналов получает свой AdaptationSet. Английское стерео – один AdaptationSet; испанское стерео – другой; английский 5.1 – третий. Внутри англо-стерео AdaptationSet может быть три Representation на 96, 128 и 192 kbit/s, и плеер адаптируется между ними по мере изменения сети – это аудиоаналог переключения разрешения видео.

<Period>
  <!-- Английское стерео: один AdaptationSet, три битрейтных Representation -->
  <AdaptationSet contentType="audio" lang="en" audioSamplingRate="48000">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
    <Representation id="en-96"  codecs="mp4a.40.2" bandwidth="96000"/>
    <Representation id="en-128" codecs="mp4a.40.2" bandwidth="128000"/>
    <Representation id="en-192" codecs="mp4a.40.2" bandwidth="192000"/>
  </AdaptationSet>

  <!-- Испанское стерео: отдельный AdaptationSet -->
  <AdaptationSet contentType="audio" lang="es" audioSamplingRate="48000">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="alternate"/>
    <Representation id="es-128" codecs="mp4a.40.2" bandwidth="128000"/>
  </AdaptationSet>

  <!-- Английский авторский комментарий -->
  <AdaptationSet contentType="audio" lang="en" audioSamplingRate="48000">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="commentary"/>
    <Representation id="comm-96" codecs="mp4a.40.2" bandwidth="96000"/>
  </AdaptationSet>
</Period>

DASH заменяет флаги HLS DEFAULT / AUTOSELECT дескриптором Role. Элемент Role со значением value="main" играет роль DEFAULT=YES в HLS: помечает основную дорожку. value="alternate" помечает вторичную дорожку, например другой язык; value="commentary" – комментарий; value="dub" – дублированную дорожку; value="description" – аудиоописание для незрячих зрителей, о котором мы пишем в многоязычном и описательном звуке. Атрибут lang несёт язык, ровно как LANGUAGE в HLS.

Соответствие между двумя форматами достаточно близко, чтобы свести в таблицу, – это самый быстрый способ для неспециалиста прочитать любой из них:

ЗадачаHLSDASH
Сгруппировать один логический выбор звукагруппа рендиций (GROUP-ID)AdaptationSet
Одна битрейтная версия этого звукаMedia Playlist (URI)Representation
«Играй это, если нет предпочтения»DEFAULT=YES<Role value="main">
«Можешь сам выбрать под настройку»AUTOSELECT=YES<Role value="alternate"> + lang
Тег языкаLANGUAGE="es"lang="es"
Число каналовCHANNELS="6"audioChannelConfiguration / отдельный set
Не выбирать сам; пусть просит пользовательAUTOSELECT=NO<Role value="commentary">
Отрезок таймлайна (например, реклама)discontinuity / отдельный плейлистотдельный Period

Таблица 1. Те же понятия звука на диалектах HLS и DASH. Источник: спецификация HLS (атрибуты EXT-X-MEDIA) и ISO/IEC 23009-1:2022 (AdaptationSet, Representation, Role).

«Ловушка – surround и стерео в одном AdaptationSet. Зеркально правилу HLS, плееры DASH не должны переключаться между разными раскладками каналов внутри одного AdaptationSet, и рекомендации DASH-IF держат стерео и 5.1 в отдельных set. Если положить стерео- и 5.1-Representation в один AdaptationSet, плеер, адаптируясь под полосу, может посреди сцены перескочить с surround на стерео – это звучит так, будто комната вдруг схлопнулась к передним колонкам. Разделяйте раскладки; пусть плеер выберет раскладку один раз, а потом адаптирует битрейт внутри неё.»

CMAF: один набор файлов под обоими манифестами

Пока HLS и DASH выглядят как два отдельных мира, и исторически так и было: сервису, хотевшему оба, приходилось упаковывать звук дважды, удваивая хранилище и стоимость CDN. Common Media Application Format, стандартизованный как ISO/IEC 23000-19, покончил с этим дублированием для большинства современных сервисов.

CMAF – не третий манифест. Это формат файлов медиасегментов, на которые указывают манифесты. CMAF определяет своё медиа как фрагментированный MP4 – то же семейство ISO base media file format, что разобрано в звуке в контейнерах, – построенный так, что один физический набор аудио- и видеосегментов может ссылаться плейлист HLS и MPD DASH одновременно. Вы кодируете и храните звук один раз; вы пишете поверх него два маленьких текстовых манифеста. Байты на CDN общие.

CMAF организует альтернативные кодировки в CMAF Switching Set: набор дорожек, которые можно переключать и склеивать на границах фрагментов, – именно это нужно делать дорожкам группы рендиций HLS или Representation в AdaptationSet DASH. Дорожки одного switching set должны разделять ограничения кодирования и упаковки, чтобы декодер никогда не видел разрыв, с которым не справится, при смене битрейта. Единица переключения – CMAF Fragment; CMAF Chunk – меньший кусок фрагмента, используемый для снижения задержки, что важно для стриминга с низкой задержкой.

Одна тонкость, к которой стандарт строг, – режим шифрования. Common Encryption в CMAF предлагает две схемы – cenc (AES в режиме счётчика) и cbcs (AES в режиме CBC с шаблонным шифрованием). HLS на платформах Apple требует cbcs. Презентация CMAF должна использовать одну схему целиком; смешивать cenc и cbcs в одной презентации нельзя. Если хотите, чтобы одна библиотека CMAF питала и плеер HLS (которому нужен cbcs), и устаревший плеер DASH, зашифрованный cenc, вы снова упаковываете дважды – поэтому большинство сервисов, перешедших целиком на CMAF, стандартизуются на cbcs, чтобы держать одну зашифрованную копию. Правило для звука простое: выбирайте cbcs, шифруйте один раз.

Рис. 2. Switching set CMAF держит битрейтные версии одной аудиодорожки, выровненные так, чтобы плеер мог переключаться на любой границе фрагмента без щелчка. Зашифруйте один раз с cbcs – и HLS, и DASH используют те же байты.

Как плеер на самом деле решает – алгоритм выбора по шагам

Сложите всё вместе – и решение плеера превращается в короткую предсказуемую последовательность. Точный порядок чуть различается между плеерами, но логика одна на iOS AVPlayer, ExoPlayer на Android, Shaka Player, hls.js и dash.js.

Сначала плеер читает манифест и находит аудиогруппу (HLS) или аудио-AdaptationSet (DASH). Во-вторых, проверяет, задал ли пользователь или приложение явное предпочтение звука для этой сессии – «играй на испанском», «включи комментарий». Если да и подходящая дорожка есть – побеждает она, точка. В-третьих, при отсутствии явного выбора плеер смотрит на язык и локаль системы устройства; если дорожка совпадает и ей разрешён автовыбор (AUTOSELECT=YES в HLS, Role alternate-или-main с совпадающим lang в DASH), он берёт её. В-четвёртых, не найдя совпадения по языку, он откатывается к дорожке по умолчанию (DEFAULT=YES / Role=main). В-пятых, выбрав какую дорожку, он затем выбирает, с какого битрейта начать, и адаптируется вверх-вниз по мере изменения сети – но не меняет язык или раскладку каналов при этом.

Отсюда два следствия, объясняющие большинство обращений в поддержку. Зритель в Мексике, чей телефон выставлен на испанский, получит испанский звук только если вы пометили испанскую дорожку AUTOSELECT=YES и тегом LANGUAGE="es"; пометьте неверно – и он получит английский по умолчанию. А зритель никогда не доберётся до дорожки 5.1, если вы забыли дать высокобитрейтным вариантам видео группу AUDIO, содержащую рендицию 5.1, – surround-дорожка лежит в библиотеке, но недостижима из меню.

Рис. 3. Порядок решения плеера: явный выбор пользователя, затем совпадение по языку устройства, если дорожку можно автовыбрать, затем дорожка по умолчанию. Язык и раскладка каналов выбираются один раз; дальше адаптируется только битрейт.

Разбор с числами: во сколько обходятся несколько дорожек

Числа делают компромисс осязаемым. Возьмём 90-минутный фильм, отдаваемый на трёх языках как стерео-AAC плюс одна surround-дорожка 5.1 на языке оригинала. Стерео-AAC на 128 kbit/s и 5.1 E-AC-3 на 384 kbit/s. Арифметика для одной полной копии каждой дорожки:

Длительность         = 90 мин = 5 400 секунд
Размер стереодорожки = 128 kbit/s ÷ 8 × 5 400 с = 86 400 kbit ÷ 8
                     = 86 400 килобайт ≈ 86,4 МБ на язык
Три стереоязыка      = 3 × 86,4 МБ ≈ 259 МБ
Surround-дорожка 5.1 = 384 kbit/s ÷ 8 × 5 400 с ≈ 259 МБ
Итого звук (по одному битрейту) ≈ 259 МБ + 259 МБ ≈ 518 МБ

Эти 518 МБ соседствуют с видеофайлом в несколько гигабайт, так что звук – малая доля хранилища, но он умножается с каждым языком и каждой ступенью битрейта, которую вы добавляете, а на популярном тайтле трафик CDN оплачивается за гигабайт на каждом просмотре. С CMAF вы платите за это хранилище один раз и обслуживаете клиентов HLS и DASH из него; без CMAF – платите дважды. Полную модель хранилища и CDN, включая то, когда отрезать редко смотримые языковые дорожки, мы даём в статье хранилище и арифметика CDN для звука.

Многопериодный DASH и ловушка вставки рекламы

Самые трудные ошибки звука в стриминге живут на швах между Period. Вспомните, что вставленная рекламная пауза обычно – отдельный Period DASH. Аудио-AdaptationSet основного контента и аудио-AdaptationSet рекламы описаны независимо, и ничто не заставляет их совпадать. Если основной контент предлагает английский, испанский и комментарий, а рекламный Period – лишь одну непомеченную английскую дорожку, плеер, дойдя до рекламы, не найдёт испанскую дорожку, которую слушал зритель, – и либо умолкнет, либо упадёт на английский, либо в худших реализациях вовсе не запустит рекламу.

Тот же класс проблем возникает в HLS через EXT-X-DISCONTINUITY – тег, помечающий точку склейки, где тайминг и кодирование могут измениться. Звук, бывший чистым 48 kHz стерео-AAC до разрыва, может встретить рекламу 44,1 kHz по ту сторону, и смена частоты дискретизации заставляет плеер переинициализировать аудиодекодер – момент, в который пробираются щелчки, провалы и рассинхрон губ. Лечение – дисциплина на этапе упаковки: каждый Period и каждый сегмент в границах discontinuity должны показывать одинаковую структуру аудиодорожек – те же языки, те же Role, ту же частоту дискретизации, те же раскладки каналов, – чтобы плеер пронёс выбор зрителя через шов, не переспрашивая. Серверная вставка рекламы, согласующая кодирование рекламы с конфигурацией звука основного контента, – это решение производственного уровня.

«Ловушка – рекламная пауза, сбрасывающая язык. Зритель смотрит на испанском, попадает на рекламную паузу, а реклама – свёрстанная другой командой или рекламным сервером – несёт только английский. После рекламы одни плееры сохраняют испанский, но многие сбрасываются на язык по умолчанию нового Period и не возвращаются обратно. Зрителю кажется, что приложение случайно сменило ему язык. Проверяйте каждый рекламный Period на ту же структуру языков и Role, что у основного контента, прежде чем винить плеер.»

Где здесь Фора Софт

Мы строим продукты OTT и прямого эфира, где аудиоменю – это разница между продуктом, который выходит, и тем, что собирает одну звезду с отзывами про «не тот язык» и «нет surround». В стриминговых проектах – видео по запросу, e-learning, прямые трансляции – дефекты звука, которые нас зовут чинить, почти никогда не аудиофайлы, а манифест: пропущенный AUTOSELECT, surround-дорожка без группы, достижимой из высокобитрейтных вариантов, рекламный Period, чьи AdaptationSet не зеркалят основной контент. Мы стандартизуем клиентов на CMAF с cbcs, чтобы одна упакованная библиотека обслуживала HLS и DASH, и тестируем логику выбора на реальных плеерах iOS, Android и ТВ, а не на десктопном браузере, потому что плееры по-разному разрешают неоднозначные манифесты. Правильно собрать меню один раз и проверить его на нужных устройствах – это предотвращает целую категорию жалоб.

Главные выводы

  • Аудиодорожку выбирает плеер, а не сервер, – из манифеста, который вы свёрстали.
  • HLS собирает дорожки в группы рендиций; варианты видео указывают на группу через AUDIO.
  • DASH кладёт каждый язык и раскладку каналов в свой AdaptationSet.
  • Ровно одна дорожка по умолчанию на группу: DEFAULT=YES в HLS, Role=main в DASH.
  • CMAF позволяет одной библиотеке с cbcs питать и HLS, и DASH.
  • Большинство ошибок «не тот язык» и «нет surround» – ошибки вёрстки манифеста.
  • Рекламные Period должны зеркалить структуру звука основного контента, иначе язык сбросится.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.