Когда Роман Арутюнян (rarutyunyan) выпустил модуль nginx-rtmp-module, это сильно перевернуло взгляд на доступность организации видеовещания. До этого, это казалось каким-то дорогим и сложным делом.

31 декабря Adobe официально хоронит флешплеер и убирает ссылки на скачивание с сайта. Это, конечно, не может не радовать. Эти засранцы то и дело подсовывали включенные по умолчанию галочки, так что даже продвинутому пользователю прилетал вместе с флешплеером еще и какой-то антивирус в лучшем случае. То, что это чудовище бесконечно просило обновлений ручками через браузер, знают все. Ходил даже анекдот, предлагающий создателям флешплеера законодательно ограничить паспорта сроком на 1 неделю с возможностью бесконечной перевыдачи.

Кому сдался флешплеер в конце 2020-го, вы хотите сказать? Да дело в том, что флеш плеер единственный поддерживал воспроизведение протокола rtmp в браузере с относительно низкой задержкой. Да и он не так уж и плох, учитывая, что по умолчанию все стриминговые сервисы, youtube или twitch из кодировщика просят передавать им видео по протоколу rtmp. Конечно, приходит более свежий SRT но разговор не об ��том.

Вы убрали возможность играть видео в браузере по rtmp, а где альтернативы-то?

Форматы, работающие по http требуют хорошей буферизации. Задержка выливается в 15 секунд. Если вы общаетесь со своей аудиторией онлайн, это неприемлемо. WebRTC решения плохо дружат с реализацией один ко многим. Ну как плохо, плати, и будет хорошо. Cофт есть на рынке. Только беда еще с покрытием, по моим ощущениям, WebRTC только только нащупал какую-то стабильную фазу, при которой его можно использовать. Но все равно есть небольшие проблемы с форматами видео на разных платформах. Раньше все это выглядело так ужасно, что проще было просить ставить флешплеер только ради малой задержки.

В issue к nginx-rtmp-module не я один [1] [2] оставлял вопросы о поддержке форматов передачи видео по http с низкой задержкой (2-3 секунды). Ведь если бы можно было вещать в формате dash и hls до 3 секунд на nginx-rtmp-module, меня бы это полностью устроило. Но ответов на эти вопросы нет. Низкая задержка нужна в 2020 году и без нее ну никак. К сожалению, проект c 2017 года не развивается.

Медиасервер OvenMediaEngine.


Прекрасной альтернативой, отвечающей порывам всех моих желаний, является корейская морковка опенсорсный проект OvenMediaEngine, предлагающий не только средства кодирования и кластеризации (как у nginx-rtmp-module) но и средства воспроизведения т.е. свой html5 плеер OvenPlayer.  Именно то, чего я так искал, зарелизили наши южнокорейские братья. С большим интересом я крутил его неделю и полностью перебрался на него.

  • Задержка по WebRTC полсекунды.
  • Задержка по dash low latency 2 секунды.
  • HLS low latency скоро обещают.

Возможности:

  • RTMP Push, MPEG2-TS Push, RTSP Pull Input
  • WebRTC sub-second streaming
  • Embedded WebRTC Signalling Server (WebSocket based)
  • ICE (Interactive Connectivity Establishment)
  • DTLS (Datagram Transport Layer Security)
  • SRTP (Secure Real-time Transport Protocol)
  • ULPFEC (Forward Error Correction) with VP8, H.264
  • In-band FEC (Forward Error Correction) with Opus
  • Low-Latency MPEG-DASH streaming (Chunked CMAF)
  • Legacy HLS/MPEG-DASH streaming
  • Embedded Live Transcoder (VP8, H.264, Opus, AAC, Bypass)
  • Origin-Edge structure
  • Monitoring
  • Experiment
  • P2P Traffic Distribution
  • RTSP Pull, MPEG-TS Push Input

Так как команда активно развивает медиасервер, для быстрых апгрейдов я решил использовать предложенную ими установку через докер, накатывая внутрь контейнера всего две вещи: сертификаты от Lets Encrypt и файл настройки сервера.

С моей точки зрения из-за свежести проекта, документация OvenMediaEngine хоть и включает страницу с быстрым стартом, но не рассказывает о best default practice. Вникая во все это самостоятельно, выделил две проблемы с подачей материала и почувствовал что нужна статья.

  1. Показывают, как работают примеры по http и ws протоколу, хотя, очевидно, показывать нужно сразу, как работать на https и wss, все равно же придется заново все перенастраивать. К тому же, о прикреплении бесплатных сертификатов от  Lets Encrypt в документации ни слова, хотя официально полностью поддерживают. 
  2. Аналогично, после настройки и запуска сервера точка входа публично доступна для всех.(как и у nginx-rtmp-module) Нужно сразу показывать, как защищать точку входа.

Это все мелочи. Похвалю за очень удобные средства отладки. Они предлагают две страницы

http://demo.ovenplayer.com
https://demo.ovenplayer.com

http и https для отладки сервера. Более того, внесенные настройки сразу же отражаются как GET параметры в адресной строке  — это чертовски удобно тестировать между браузерами. Поверьте, путаница в протоколах, портах, описках в урлах при первой подготовке сервера то еще занятие! А так, сохранил ссылку в браузере в закладках да и возвращайся когда нужно к настройке!

Установка.  Быстрый старт


Итак, я возьму 20-ую Убунту.

https://airensoft.gitbook.io/ovenmediaengine/v/0.10.10/getting-started

docker run -d \
-p 1935:1935 -p 4000-4005:4000-4005/udp -p 3333:3333 -p 8080:8080 -p 9000:9000 -p 10000-10010:10000-10010/udp \
airensoft/ovenmediaengine:latest

После ставим certbot. Привязывайте ip к домену, получайте сертификаты.

Далее, получаем имя контейнера докера, например, 87b8610034bc

Server.xml
sudo docker container ls

Вытащим конфиг из контейнера для редактирования. (Мне удобнее в момент изучения конфига видеть его где-то с подсветкой синтаксиса, поэтому вытаскиваю файл)

sudo docker cp 87b8610034bc:/opt/ovenmediaengine/bin/origin_conf/Server.xml ./Server.xml

Старый добрый xml.

Выглядит конфиг так
https://github.com/AirenSoft/OvenMediaEngine/blob/master/misc/conf_examples/Server.xml

Раздел VirtualHost. Нам нужно задать имя сервера и указать пути к сертификатам внутри контейнера.
Имя сервера в виде звездочки "*" или еще дополнительные имена в конфиге не позволят запуститься OME корректно при использовании TLS.


<Host>
    <Names>
        <Name>stream.***.ru</Name>
    </Names>
    <TLS>
        <CertPath>/opt/ovenmediaengine/bin/cert.pem</CertPath>
        <KeyPath>/opt/ovenmediaengine/bin/privkey.pem</KeyPath>
        <ChainCertPath>/opt/ovenmediaengine/bin/chain.pem</ChainCertPath>
    </TLS>
</Host>

Затем, нужно оставить только TLSPort порты.


<Publishers>
    <HLS>
        <TLSPort>${env:OME_HLS_STREAM_PORT:8080}</TLSPort>
    </HLS>
    <DASH>
        <TLSPort>${env:OME_DASH_STREAM_PORT:8080}</TLSPort>
    </DASH>
    <WebRTC>
        <Signalling>
            <TLSPort>${env:OME_SIGNALLING_PORT:3333}</TLSPort>
        </Signalling>
    </WebRTC>
</Publishers>

Почему я рекомендую указывать те же порты, что и использовались для http? Сервер иначе не стартанет на одинаковых портах (не умеет), а выдумывать новые порты, когда при установке докера разработчики уже сделали в примере биндинги для контейнера, лишнее.

Заливаем конфиг обратно

sudo docker cp  ./Server.xml 87b8610034bc:/opt/ovenmediaengine/bin/origin_conf/Server.xml

И, соответственно, по заданным путям мы кидаем наши ключи


docker cp /etc/letsencrypt/live/stream.*.ru/chain.pem 87b8610034bc:/opt/ovenmediaengine/bin/
docker cp /etc/letsencrypt/live/stream.*.ru/privkey.pem 87b8610034bc:/opt/ovenmediaengine/bin/
docker cp /etc/letsencrypt/live/stream.*.ru/cert.pem 87b8610034bc:/opt/ovenmediaengine/bin/

Перезапуск 

sudo docker restart 87b8610034bc

Пробуем.

Урл вещания в obs

rtmp://stream.*.ru:1935/app

ключ ‘stream’



Линки для паблика

dash https://stream.*.ru:8080/app/stream/manifest.mpd
dash ll https://stream.*.ru:8080/app/stream/manifest_ll.mpd
hls https://stream.*.ru:8080/app/stream/playlist.m3u8
webrtc wss://stream.*.ru:3333/app/stream/

Если после запуска трансляции в OBS все хорошо и по линкам отдается манифест, можете проверить видео на странице с плеером.

Подписывание ссылок


OME так устроен, что позволяет создать публичные линки с разными правами. Например, одну и туже ссылку можно ограничить ip диапазоном или временем работы по разному для разных людей. Изменения в настройки сервера при этом вносить не нужно. Они используют схожую логику как у гугла Sign Policy.

1. Добавить блок SignedPolicy в секцию VirtualHost в Server.xml


<SignedPolicy>
    <PolicyQueryKeyName>policy</PolicyQueryKeyName>
    <SignatureQueryKeyName>signature</SignatureQueryKeyName>
    <SecretKey>secretkey</SecretKey>
      
    <Enables>
        <Providers>rtmp</Providers>
        <Publishers>webrtc,hls,dash,lldash</Publishers>
    </Enables>
</SignedPolicy>

После этого, вы не сможете ни посылать поток по старой ссылке в OBS ни принимать трафик по публичным ссылкам без подписей.

2. Запускаем signed_policy_url_generator.sh с параметрами, описанными внутри. 

Например:


sudo bash  ./signed_policy_url_generator.sh secretkey  rtmp://stream.***.ru:1935/app/stream signature policy '{«url_expire»:8807083098927}'

url_expire — обязательный параметр, который просит в миллисекундах (это не unix timestamp, а currentmillis.com ) указать, когда истечет ссылка.

результат:

rtmp://stream.***.ru:1935/app/stream?policy=eyJ1cmxfZXhwaXJlIjo4ODA3MDgzMDk4OTI3fQ&signature=xjS7NY-l4lY1f9e9sOiRNhPtAqI

rtmp://stream.***.ru:1935/app — идет в OBS в Server, остальная часть  — в «Stream key».



3. Если OBS стартанул трансляцию, теперь нужно обязательно подписать необходимые публичные ссылки. Например для WebRTC.

sudo bash  ./signed_policy_url_generator.sh secretkey  wss://stream.***.ru:3333/app/stream signature policy '{"url_expire":8807083098927}'

Таким образом, не имея доступа к секрету, получить какой либо доступ к OME из дефолтных настроек больше нельзя.

Из настроек остается  только прописать докер на автозапуск контейнера с системой. Ну и установить обновление сертификатов на крон, со скриптом, копирующим в контейнер ключи и рестартующим его. Ну или каким-то другим способом, как вы это делаете.

sudo systemctl enable docker

sudo docker update --restart unless-stopped 87b8610034bc


Кодировщик


Ребята считают OBS самым популярным кодировщиком для своего сервера. Поэтому как и в документации, так и более подробно в блоге можно найти подходящие настройки, максимально снижающие задержку в трансляции.

Настройки кодировщика для OBS студии для задержки в половину секунды следующие



Столь малая задержка конечно обходится более низким качеством изображения на пресете zero-latency. Другие пресеты хоть и добавляют задержку около 1.5 секунды, но картинку делают лучше.

Так же у них есть универсальный энкодер для андройда.

https://play.google.com/store/apps/details?id=com.airensoft.ovenstreamencoder.camera

Еще немного о корейской морковке


  • Сервер выдает несколько потоков под разные платформы, а плеер уже выбирает нужный под возможности браузера. Единственный минус современного видеовещания, это большие размеры бандлов зависимостей. Например, только DASH.js весит 175 kb gzip.
  • В зависимости от указания порядка источников в конфиге OvenPlayer, они будут стартовать соотвественно.
  • Когда пользователь выбирает в плеере в качестве  источника webrtc, OME на лету конвертирует аудио в требуемый формат opus.(Это требования стандарта.) 
  • По непонятным для меня причинам, WebRTC не может работать с mono звуком, поэтому не пытайтесь в настройках медиасервера переключать звук со стерео — он не запустится. Это не проблема OME.

Пожелания


  1. Система логов — это обычные txt файлики. Было бы очень круто иметь чуть более продвинутую визуальную аналитику. Например, знать сколько зрителей онлайн и какой траффик
  2. Я пробовал новый nginx-unit с его модным json-api  в качестве команд управления/конфига. Суть в чем, обновляешь вебсервер, а он продолжает работать, заливаешь сертификаты, а ему не надо перезагружаться, домен, поддомен, добавить заголовки, убрать — все налету без перезагрузки. А поверх json-api появляется миллион офигенно удобных админок с UI. Хотя в OME и вроде бы и нет нужды в таком API, но наверняка кто-то что-то потом обязательно придумает)

Немного о ребятах. Они себя позиционируют как группа экспертов по медиа технологиям, ведут блог с любопытным контентом.

Судя по тому, что они плотно сотрудничают с местными телекомами, чувствуется очень хороший бекграунд для поддержки опенсорса в области стриминга. Это замечательно. Я прикреплю пару фоток из их нового офиса.

Ребята передают всем привет, статью заметили.