Профили устройств¶
Не каждое устройство зрителя играет каждую дорожку стрима. Приставка не справляется с 720p60, телевизор не играет HEVC, плеер на webOS ломается на субтитрах. Профиль устройства прячет от такого устройства лишние дорожки и не трогает остальных зрителей.
Профиль — именованная запись с тремя частями:
- как узнать устройство — по
User-Agent, заголовку запроса или параметру адреса; - где профиль действует — режимы выдачи и стримы;
- какие дорожки оставить — ограничения видео, аудио и субтитров.
Набор профилей один на весь кластер. Его хранит central и доставляет каждому стримеру вместе с остальной конфигурацией; решение принимает тот стример, к которому пришёл зритель, без обращения к central.
Профиль только сужает: убирает дорожки и никогда не добавляет. Это не средство допуска — зритель, подделавший заголовок, получит тот набор, который положен этому заголовку, а «4K только премиуму» решает политика допуска.
Как устроен профиль¶
Раздел консоли Профили устройств показывает профили в том порядке, в котором стример их перебирает. Карточка профиля открывается щелчком.

В заголовке карточки:
- имя профиля и его адрес
p/<имя>/; - порядок, например порядок 10, а у профиля без условий — пометка только по адресу;
- пометка изменён, если в профиле есть несохранённые правки.
Новый профиль заводит кнопка Добавить профиль: в окне Новый профиль задайте имя и нажмите Добавить профиль. Имя профиля — строчные латинские буквы, цифры и знаки ., _, -, до 64 символов, первая — буква или цифра. Имя входит в адрес p/<имя>/ (см. адреса под профилем). Профилей не больше 64: когда их 64, кнопка Добавить профиль недоступна. Новый профиль, как и любая правка, вступает в силу только после Сохранить (см. правку).
Как узнать устройство¶
Профиль выбирается, если совпало хотя бы одно условие:
- User-Agent содержит — подстрока в заголовке
User-Agent, регистр не важен:Rokuсовпадёт сRoku/DVP-14.5. - Заголовки запроса — имя заголовка и подстрока его значения, регистр не важен ни у имени, ни у значения. Так узнают устройство по заголовку, который ставит ваш middleware (
X-CDN-DEV-MODEL: 4800X), или по готовому классу от CDN (CloudFront-Is-SmartTV-Viewer: true,X-UA-Device). Встроенной базы устройств у стримера нет. - Параметры адреса — имя параметра и список значений через запятую. Параметр совпал, если его значение целиком и с учётом регистра равно одному из значений:
?device_profile=arrisсовпадёт со значениемarris, но неarris-4205и неArris. Значения пишутся раскодированными:+в адресе — это пробел, поэтому?p=S10+совпадёт со значениемS10(с пробелом), а значениеS10+— только с?p=S10%2B.
Запрос без User-Agent с условием по User-Agent не совпадает.
Профиль без единого условия помечен только по адресу: стример выбирает его, только если адрес сам называет профиль (см. адреса под профилем).
Где действует¶
- Порядок — у профилей с условиями обязателен и уникален: стример перебирает их по возрастанию и берёт первый подходящий. У профиля без условий не действует.
- Режимы выдачи — на каких запросах профиль действует. По умолчанию — все три режима.
- Теги стримов и Имена стримов — на каких стримах профиль действует: стрим входит, если несёт хотя бы один из тегов или назван по имени. Пусто — все стримы. Имён на все профили вместе — не больше 1000, область на многих стримах задавайте тегом.
Режимы выдачи:
- Прямой эфир — запрос живого потока;
- Архив — запрос с
from; - Отмотка — адрес
rewind/<секунды>/.
Теги стримов вводятся по одному: напишите тег и нажмите Enter. Тег — латинские буквы, цифры и знаки _, ., -, до 40 символов. Консоль проверяет тег сразу: тег другого вида в список не попадает, а под полем появляется ошибка. Тег, который уже есть в списке, второй раз не добавляется.
Какие дорожки оставить¶
Ограничения сгруппированы по типу дорожки, и каждая группа судит только дорожки своего типа:
- Видео — Кодеки или Кроме кодеков, Ширина, Высота, Частота кадров.
- Аудио — Кодеки или Кроме кодеков, Языки или Кроме языков, переключатель Не отдавать аудио.
- Субтитры — Языки или Кроме языков, переключатель Не отдавать субтитры.
Поля одной секции влияют друг на друга:
- заполненное поле Кодеки выключает Кроме кодеков, и наоборот: оба списка в одной секции central не примет;
- так же заполненное поле Языки выключает Кроме языков, и наоборот;
- включённый переключатель Не отдавать аудио или Не отдавать субтитры убирает все дорожки этого типа и прячет остальные поля секции.
Дорожка остаётся, если проходит все заданные ограничения своей группы; внутри одного ограничения достаточно совпасть с любым значением. Ширина, высота и частота кадров пишутся через запятую — точными значениями и диапазонами; у диапазона может не быть одной из границ:
1080, 720 ровно 1080 или ровно 720
..720 не больше 720
720.. не меньше 720
480..1080 от 480 до 1080 включительно
..30 не больше 30 кадров в секунду
25, 29.97 частота целым или десятичным числом, через точку
30000/1001 частота дробью
Дорожку, у которой ограниченное свойство неизвестно (нет частоты кадров, нет языка), ограничение не убирает: судить не о чем. Языки сравниваются по стандартному тегу: eng в описании дорожки и en в профиле — один язык; und («не определён») считается отсутствием языка.
Профиль без единого ограничения выбирается, но ничего не убирает.

Как выбирается профиль¶
Стример выбирает профиль на каждом запросе HLS master playlist (fMP4 и MPEG-TS, с LL-HLS и без) и DASH-манифеста во всех режимах выдачи:
- Прямой эфир;
- Архив;
- Отмотка.
Выбор идёт так:
- Если адрес содержит сегмент профиля
p/<имя>/— выбран названный профиль, условия не проверяются. - Иначе стример перебирает профили с условиями по возрастанию порядка и берёт первый, у которого совпало условие, а режим выдачи и стрим входят в его область.
На запрос действует ровно один профиль: ограничения разных профилей не складываются. Если профиль не выбран, зритель получает полный набор дорожек — ровно тот плейлист, что и без профилей.
Из master убранная дорожка исчезает вместе со своим вариантом или рендишеном; группа аудио или субтитров, в которой ничего не осталось, исчезает целиком. Если профиль убрал аудиодорожку по умолчанию, ею становится первая оставшаяся дорожка той же группы: группа — это дорожки одного кодека (см. звук разных кодеков).
Звук разных кодеков в HLS¶
HLS master собирает аудиодорожки в группы по кодеку. У стрима с AAC и AC-3 master даёт плееру две аудиогруппы, aac и ac3, и каждое качество видео — в паре с каждой из них. Плеер без декодера AC-3 пропускает варианты группы ac3 и играет AAC, а не теряет стрим целиком.
Профиль, у которого в секции Аудио в поле Кодеки выбран только aac, убирает AC-3 целиком: в master не остаётся ни группы ac3, ни её вариантов.
Плеер предлагает зрителю языки той группы, которую играет. Язык, который есть только в AC-3, плеер без декодера AC-3 не увидит.
Адреса под профилем¶
Решение принимается один раз, на master playlist, и дальше передаётся в адресе. Master, для которого профиль выбран по условиям, ведёт плеер на дочерние плейлисты под сегментом профиля:
/playback/v/<стрим>/index.m3u8 запрос плеера
/playback/v/<стрим>/p/<профиль>/variant/v2/... куда ведёт master
Плейлисты, части и сегменты под p/<профиль>/ на заголовки и параметры запроса не смотрят и одинаковы для любого зрителя этого адреса. Плейлист дорожки, которую профиль убрал, под p/ отвечает 404. Без сегмента профиля плейлист дорожки отдаётся любому зрителю: условия проверяются только на master.
Адрес с сегментом профиля можно поставить плееру и напрямую — так выбирает профиль витрина или middleware, которые знают устройство сами:
/playback/v/<стрим>/p/<профиль>/index.m3u8
/playback/v/<стрим>/p/<профиль>/Manifest.mpd
/playback/v/<стрим>/p/<профиль>/ts/index.m3u8
/playback/v/<стрим>/p/<профиль>/rewind/600/index.m3u8
Профиль, которого стример не знает (удалён, переименован или стример ещё не применил правку), или чья область не покрывает запрос, ничего не убирает: адрес под ним отдаёт полный набор, без ошибки.
Заголовок посредника и редирект. Когда central проксирует запрос, он передаёт стримеру заголовки плеера. Когда central отвечает редиректом на публичный адрес стримера, заголовок, который поставил посредник перед central (CDN, middleware), до стримера не доходит: плеер его не повторяет. В такой схеме выбирайте профиль адресом p/<профиль>/.
Адреса Flussonic¶
Адрес master по-старому (/<стрим>/index.m3u8?device_profile=arris) уводит на master /streaming/v/<стрим>/index.m3u8 с теми же параметрами, и профиль выбирается как обычно. Адрес одной дорожки (/<стрим>/tracks-v1/index.m3u8) ведёт прямо на её плейлист, без профиля.
Выбор дорожек по номерам Flussonic — параметр filter.tracks и адрес с набором дорожек вроде tracks-v1a1/index.m3u8 — Catena не выполняет: номера дорожек у неё другие, и зритель получает полный набор. Заведите профиль под это устройство; счётчик device_profile_track_numbers_total (см. диагностику) покажет, сколько таких запросов профилем не закрыто.
DASH¶
В DASH решение тоже принимается на манифесте: профиль убирает Representation с неподходящими дорожками, а AdaptationSet без единой Representation выпадает целиком. Манифест, выбранный по условиям, оставляет адреса сегментов в корне стрима; манифест под p/<профиль>/ ссылается на сегменты под тем же сегментом профиля.
Живой DASH-манифест плеер перечитывает, и каждое перечитывание выбирает профиль заново — по действующей редакции профилей. Правка профиля посреди просмотра может убрать Representation, которую плеер играет, и многие плееры на этом останавливаются. Радикальную правку делайте новым профилем (см. правку).
У DASH нет отмотки: профиль, который действует только на Отмотке, на манифест не влияет.
Пустой результат¶
Если после отбора не осталось ни одной дорожки ведущего типа — видео, а у стрима без видео — аудио, — стример отвечает на master 400 с кодом device_profile_empty и пишет предупреждение в журнал. Полного набора зритель не получит: это ровно то, от чего профиль прятал устройство. Только аудио стриму с видео тоже не отдаётся: плеер устройства такой master за видео не примет.
Так же отвечает и адрес p/<профиль>/: его увидит витрина, которая этот адрес поставила. Исправляется пустой результат областью профиля (теги, режимы) или более мягкими ограничениями.
Правка, удаление и переименование¶
Удаляет профиль кнопка Удалить в карточке, переименовывает — Переименовать. Новый профиль, удаление и переименование, как и правка полей, вступают в силу только после Сохранить: до этого они есть только в форме. Кнопка Отмена сбрасывает все несохранённые правки вместе с недописанными полями.
Кнопка Сохранить отправляет только изменённые поля. Если профили правили параллельно, форма покажет конфликт; ваши правки остаются в форме — Показать актуальное перечитает документ без ваших правок, Перенести мои правки применит их к актуальной версии. Результат остаётся в форме несохранённым: проверьте его — например, профиль, который другой оператор удалил, а вы правили, вернётся только с вашими полями — и сохраните. Пока в форме есть недописанное поле (граница, которая не разобралась, условие без имени или значения, повтор имени), Сохранить недоступна.
Правка доходит до стримеров без рестарта и без пересчёта размещения. Плеер HLS читает master редко, поэтому правка, скрывшая дорожку, которую он играет, приведёт к 404 на её плейлист, и плеер переключится на другую. В DASH живой манифест перечитывается, и правка действует сразу. Поэтому:
- мелкая правка (сузить диапазон, добавить кодек в Кроме кодеков) — правьте профиль;
- радикальная правка (убрать целое качество, сменить кодек) — заведите профиль с новым именем и переведите на него условия или адреса витрины.
Переименование — это удаление и создание. Плееры, открывшие поток под прежним именем, получат полный набор дорожек, пока не перечитают master. Удаление работает так же: адрес под удалённым профилем отдаёт всё.
Если профиль не действует¶
Стример может не применить профиль, если central записал значение, которого версия стримера не знает. Остальные профили и вся конфигурация стримера при этом применяются. Где это видно:
- в разделе Профили устройств — пометка Не применён на стримерах в заголовке карточки: имена стримеров, причина в скобках и путь до поля, например
e1 (parse) video.codecs[1]; имя ведёт на страницу стримера. В раскрытой карточке — тексты отказов, которые прислали стримеры; - на странице стримера — блок рядом с ошибкой применения конфигурации: имя профиля, причина, путь до поля и сообщение;
- в API — поле
rejected_profilesвGET /central/api-v4/nodes/stats; - в метриках стримера —
device_profile_rejected{reason}.
Причины:
- parse — поле не разобралось: незнакомое значение или тип;
- invalid — профиль разобрался, но не прошёл проверку;
- limit — профиль сверх 64.
Стример версии, которая профилей не знает вовсе, отдаёт все дорожки любому зрителю, а central на правку профиля отвечает успехом. Консоль предупреждает об этом в двух местах:
- в разделе Профили устройств — общий баннер над списком «Профили не действуют на стримерах, версия которых их не поддерживает…» со ссылками на такие стримеры;
- на странице стримера — подпись «Профили на стримере не действуют: его версия их не поддерживает…».
Пометка появляется, только когда в документе профилей есть хотя бы один профиль. Отозванным стримерам и стримеру, который после старта ещё не применил конфигурацию, она не ставится.

Обновление и откат¶
- Заводите профили после обновления всех стримеров. Стример прежней версии не знает адресов
p/и ответит на них 404, если master пришёл с обновлённого стримера, а дочерний плейлист — со старого. - Откат central на версию без профилей выключает их на всём кластере до возврата: стримеры получают конфигурацию без профилей. Документ профилей остаётся в базе, и возврат central доставит его без правки.
- Откат central на одну версию назад доставку не ломает: стримеры получают профили как есть. Поле, которое знает только новая версия, мешает лишь правке, в которой это поле есть: она отвечает 422. Незнакомое значение (например, новый кодек) приводит к 422 на любую правку документа, пока это значение не удалят.
- После отката central сохраните конфиг каждого стримера любой правкой: стример, который был офлайн во время отката, иначе может остаться с прежней конфигурацией.
Ограничения¶
- Частота кадров в архиве не ограничивает: в описании записи её нет, и неизвестное свойство дорожку не убирает. В эфире и при отмотке ограничение работает, высота, ширина и кодек работают и в архиве.
- Профилей — не больше 64, имён стримов в областях всех профилей — не больше 1000.
- Профиль действует только на HLS (включая LL-HLS и MPEG-TS) и DASH; выдачу, перечисленную ниже, он не трогает.
- Формата Flussonic
720p60нет: высота и частота — независимые ограничения, и «убрать 720p60, оставить 1080p60» одним профилем не выражается.
Выдача, на которую профиль не действует:
- MSE;
- MPEG-TS по HTTP;
- fMP4-поток;
- MSS;
- VOD.
Диагностика¶
Счётчики стримера (Prometheus) по каждому профилю:
| Счётчик | Что считает |
|---|---|
device_profile_checks_total{profile} |
master и манифесты, где стример сверял условия профиля |
device_profile_input_absent_total{profile} |
из них — запросы без единого заголовка и параметра, названных в условиях |
device_profile_selected_total{profile, by} |
профиль выбран: by="match" — по условиям, by="path" — адресом |
device_profile_noop_total{profile} |
выбран, но ничего не убрал |
device_profile_empty_total{profile} |
ответы 400 пустого результата |
device_profile_undescribed_total{profile} |
плейлисты архива под профилем, где у записи нет описания дорожек и отбор не сработал |
device_profile_unknown_total |
запросы под профилем, которого стример не знает |
device_profile_track_numbers_total{covered} |
запросы с выбором дорожек по номерам Flussonic; covered="false" — профиль их не закрыл |
Как читать:
checksиinput_absentрастут вместе,selected— нет. Заголовок или параметр до стримера не доходит: его срезает CDN, прокси или редирект. Выбирайте профиль адресомp/<профиль>/.checksне растёт. До профиля в переборе не доходит: раньше выбирается другой профиль, или запрос не попадает в его режимы и стримы.selectedрастёт вместе сnoop. Профиль выбирается, но у стрима нет дорожек под его ограничения.
Профили через API¶
Документ профилей — GET и PATCH (JSON Merge Patch) на /central/api-v4/device_profiles. PATCH меняет только названные профили, null под именем удаляет профиль; передайте If-Match с ETag из чтения, чтобы параллельная правка вернулась 412, а не перезаписалась:
curl -X PATCH http://<адрес central>/central/api-v4/device_profiles \
-H 'Content-Type: application/merge-patch+json' -H 'If-Match: "<etag>"' \
-d '{
"roku-4800x": {
"priority": 10,
"match": {"headers": {"x-cdn-dev-model": "4800x"}},
"video": {"fps": [{"max": 30}]}
},
"arris": {
"priority": 20,
"match": {"query": {"device_profile": ["arris", "arris-4205"]}},
"video": {"codecs": ["h264"]}
},
"webos": {
"priority": 30,
"match": {"user_agent": "Web0S"},
"text": {"exclude_all": true}
}
}'
Ошибка в документе возвращается 422 с путём до поля — тем же, что подсвечивает консоль. Стример отдаёт применённые им профили по GET /streamer/api-v4/device_profiles.