Приём публикации: RTMP и WHIP
Как принять поток, который кодировщик или браузер публикует на сервер: адрес публикации, RTMPS, WHIP и авторизация в строке запроса.
Иногда к источнику нельзя подключиться снаружи: он за NAT, за мобильным оператором или это вкладка
браузера. Тогда роли меняются — сервер ждёт, а источник приходит сам. Такой поток объявляется
источником publish://:
rtmp 1935; stream studio { input publish://; }
Суффикс после схемы игнорируется: publish://, publish://rtmp и publish://whip — одно и то же.
Сервер решает не по суффиксу, а по пути потока, на который пришёл публикатор.
Публикация не создаёт потоки. Публикатор, пришедший на путь, для которого нет блока stream с
источником publish://, отвергается. Это относится и к блокам template с директивой prefix —
они не материализуют потоки по факту публикации.
Что нужно включить#
Поток publish:// требует хотя бы одного слушателя, через который публикация возможна:
rtmp 1935; # приём RTMP rtmps 1936; # то же поверх TLS, общая с сервером TLS-идентичность webrtc 40000; # медиа-порт UDP для WHIP и WHEP
| Параметр | Тип и допустимые значения | По умолчанию | Применение |
|---|---|---|---|
rtmp |
номер порта; 0 — выключено |
0 |
рестарт |
rtmps |
номер порта; 0 — выключено |
0 |
рестарт |
webrtc |
номер UDP-порта; 0 — выключено |
0 |
рестарт |
Приём и раздача по RTMP выключены, пока вы не напишете rtmp <порт>;. Обычно это 1935.
Если ни одного подходящего слушателя нет, конфигурация отвергается:
stream "studio": a publish:// source needs an `rtmp`/`rtmps` listener (RTMP publish) or a `webrtc_udp_port` (WHIP)
Публикация по RTMP#
Адрес публикации собирается так:
rtmp://media.example.com:1935/<приложение>/<поток>
Сервер сначала пробует найти поток с путём <приложение>/<поток>, затем — с голым <поток>.
Поэтому плоское имя в конфигурации принимает публикатора, отправляющего в любое приложение:
stream cam1 { input publish://; }
| Адрес, куда публикует кодировщик | Какой поток будет найден |
|---|---|
rtmp://media.example.com/live/cam1 |
cam1 (по голому имени) |
rtmp://media.example.com/cam1 |
cam1 |
rtmp://media.example.com/live/cam1 при stream live/cam1 { … } |
live/cam1 (совпадение полного пути) |
Многие кодировщики просят «адрес сервера» и «ключ потока» отдельно. Разложите адрес так:
| Поле в кодировщике | Значение |
|---|---|
| адрес (URL) | rtmp://media.example.com:1935/live |
| ключ потока | cam1 |
Для TLS замените схему и порт: rtmps://media.example.com:1936/live.
Шифрование и авторизация — разные вещи. Права на публикацию проверяются отдельно, как описано ниже.
Авторизация публикации#
Если авторизация медиа настроена, публикация проверяется до захвата потока: неавторизованный публикатор не может занять место и запереть законного.
У RTMP нет заголовков, поэтому учётные данные едут в строке запроса адреса. Хвост ?…
отрезается и от имени приложения, и от ключа потока, ещё до поиска потока, — так что имя находится
независимо от того, к какой части кодировщик прицепил запрос:
rtmp://media.example.com:1935/live/cam1?token=$TOKEN
Если кодировщик позволяет добавить запрос только к ключу потока, работает и такая форма:
| Поле в кодировщике | Значение |
|---|---|
| адрес (URL) | rtmp://media.example.com:1935/live |
| ключ потока | cam1?token=$TOKEN |
При отказе кодировщик получает статус NetStream.Publish.Denied с причиной отказа, а в журнале
сервера появляется строка вида [cam1] rtmp publish denied — <причина>.
Поля токена, права на публикацию и режимы проверки описаны в Авторизации публикации. Если авторизация медиа не настроена, публикация принимается без учётных данных — это осознанное «шлюза нет, значит открыто», а не сбой.
Пока авторизация не настроена, опубликовать поток может любой, кто знает путь. Не выставляйте порт RTMP в интернет до того, как настроите авторизацию, либо ограничьте его сетевыми средствами.
Публикация из браузера: WHIP#
WHIP — публикация по WebRTC поверх обычного HTTP-запроса.
| Метод и путь | Назначение |
|---|---|
POST /s/<поток>/whip |
тело — SDP-предложение, не более 64 КиБ; ответ 201, application/sdp, заголовок Location: /s/<поток>/whip/<идентификатор сессии> |
DELETE /s/<поток>/whip/<идентификатор сессии> |
завершение сессии |
Учётные данные передаются заголовком Authorization или параметром ?token=. Проверка выполняется
до чтения тела SDP и до захвата места публикатора.
webrtc 40000; stream studio { input publish://; }
Готовая страница публикации есть во встроенном плеере:
https://media.example.com/studio/embed.html?proto=whip
Она запрашивает камеру и микрофон у браузера и публикует поток на сервер. Отдельная вкладка для
публикации в списке протоколов не показывается — открывайте её параметром ?proto=whip. См.
Встраиваемый плеер.
Видео — только H.264. Звук — Opus или G.711 (µ-law и A-law); AAC по WebRTC не согласуется.
Один публикатор на поток#
Место публикатора занимает тот, кто пришёл первым. Второй публикатор на том же пути отвергается, а не перехватывает поток:
NetStream.Publish.BadName — already publishing
Публикатор, пришедший на путь, для которого публикация не настроена, получает подсказку:
NetStream.Publish.BadName — no publish gate on this node — a publisher must target the stream's host node
Это означает: на этом сервере нет потока с источником publish:// для такого пути. Проверьте
написание пути и имя приложения.
Когда публикатор уходит, поток снова паркуется, без задержки на переподключение. Кольцевые буферы, зрительские сессии и запись в каталоге сохраняются, поэтому следующий публикатор продолжает в ту же сессию, и зрители не отключаются.
Что происходит с кадрами на приёме#
Очередь приёма ограничена 512 единицами доступа. При переполнении отбрасывается самый старый
кадр — так удерживается живой край; параметры кодека (Setup) не отбрасываются никогда. Число
отброшенных кадров видно в API как потери на входе (input_loss).
Директива media_timeout не применяется к потоку, в цепочке источников которого есть publish://:
живой, но временно молчащий публикатор не должен отключаться. По той же причине флаг on_demand на
таком потоке игнорируется.
Что принимается по RTMP#
| Тип | Кодеки |
|---|---|
| Видео | H.264, H.265 |
| Звук | AAC, G.711 (µ-law и A-law) |
Перекодирования нет: что опубликовали, то и раздаётся. Какие кодеки дойдут до какого зрителя — см. Протоколы раздачи.
Полный пример#
http 8080; https 8443; rtmp 1935; rtmps 1936; webrtc 40000; auth { admin_password "смените-этот-пароль"; } storage archive /var/lib/hastreamer/dvr; # Кодировщик публикует на rtmp://media.example.com:1935/live/studio stream studio { input publish://; dvr archive 7d; } # Публикация из браузера по WHIP на тот же сервер stream talk { input publish://; }
curl -sS "https://media.example.com/api/v1/streams/studio" \ -H "Authorization: Bearer $TOKEN" \ | python3 -c 'import sys, json s = json.load(sys.stdin) print("alive =", s["alive"], "| health =", s["health"]) print("tracks:", [(t["kind"], t["codec"]) for t in s["tracks"]])'
alive = True | health = ok
tracks: [('video', 'H.264'), ('audio', 'AAC')]
Пока публикатора нет, поток отвечает alive = False, и это нормальное состояние ожидания.
Куда двигаться дальше#
- Авторизация публикации — как выпустить и проверить учётные данные.
- RTSP, HLS, DASH, MPEG-TS — если к источнику всё-таки можно подключиться.
- Протоколы раздачи — как опубликованный поток дойдёт до зрителя.
- Порты и сеть — какие порты и куда открывать.