Я давно подумывал о том, чтобы поднять еще один самый простенький VPS для Youtube-стрима Mikulski_Radio. Потому что в отличие от остальных площадок, Youtube очень чувствителен даже к коротким дисконнектам: малейший чих – и трансляцию приходится создавать заново. Особенно печально в тех нередких случаях, когда нужно внести правки в скрипт радио и ,соответственно, перезапустить его. Да и просто классно сохранить все накопленные лайки для “бесконечной” трансляции. Благо, что по умолчанию (в отличие от остальных платформ), Youtube выдает дополнительный backup ключ, который и нужен как раз для того, чтобы в случае падения основного стрима, произошло переключение на запасной поток.
Когда я для этого настроил стрим-заглушку на новом VPS (по этой моей инструкции) и запустил в работу, то подумал, а почему бы не поискать решение и для всех остальных площадок?
Я логично предположил, что умельцы должны были придумать какой-либо апгрейд для Nginx-rtmp модуля. И действительно, первый же запрос в Гугле вывел меня на комплект скриптов Nginx-rtmp-backup, опубликованный на Github.
ДИСКЛЕЙМЕР: Я не программист и не линуксоид, а лишь энтузиаст-копипастер, который делится тем, в чем смог разобраться. Поэтому, не исключено, что знающие специалисты некоторые моменты или формулировки могут счесть неправильными или нелепыми. Подача данного материала предполагает, что вы обладаете базовым уровнем знаний команд linux-терминала, а также понимаете принцип работы и настройки конфига Nginx-Rtmp-модуля. Как бы то ни было, следующие статьи и туториалы помогут вам разобраться: Свой Рестрим-Сервер (Nginx RTMP) Как я сделал свое Стрим-Радио 24/7(Ffplayout) Создание 24/7 радио-стрима (Liquidsoap) Создание 24/7 радио-стрима ч.2 (Liquidsoap)
Nginx-rtmp-backup
Суть этого решения проста, но немного заковыриста при попытке объяснить.
В Nginx-rtmp-модуле создается три Rtmp-приложения/адреса (application): основной стрим (main), запасной (backup) и конечный (out).
Для конфигов main и backup указываются специальные операторы, реагирующие на события публикации (exec_publish) или остановки стримов (exec_publish_done).
Эти операторы шлют в терминал shell-команду для активации нужного скрипта, отвечающего за запуск/остановку экземпляра avconv, ffmpeg или gstreamer на выбор .
avconv|ffmpeg|gstreamer копирует все параметры кодировщика основного/запасного стрима и транслирует его в out – видимый зрителю.
Получается следующее:
- main и backup параллельно начинают свое воспроизведение
- avconv|ffmpeg|gstreamer подхватывает main и начинает транслировать его в out
- main по какой-либо причине останавливается
- первый экземпляр avconv|ffmpeg|gstreamer для main закрывается и запускается новый, который подхватывает backup и начинает его транслировать в out
- когда main восстанавливает свое воспроизведение, то avconv|ffmpeg|gstreamer закрывает backup и снова направляет main в out.
При этом, дополнительная нагрузка этих процессов небольшая (в моем случае, при стриме 720p с битрейтом 3000k):
- 2-3,5% ЦПУ и 15mb ОЗУ для экземпляра gstreamer
- 1,5-2,5% ЦПУ; 10mb ОЗУ для nginx worker process
Единственный минус такого подхода в том, что на переключение источников уходит несколько секунд, а потому настроить бесшовное переключение на аварийный поток не представляется возможным. Тем не менее, gstreamer имеет наименьшую задержку и по сравнению с ffmpeg делает это за пару мгновений.
А еще у меня есть некоторые сомнения в стабильности работы gstreamer в режиме 24/7. Пока что еще не получилось протестировать на ощутимо продолжительной дистанции, чтобы сделать какие-либо выводы на этот счет.
Установка и настройка
На Github и внутри самих скриптов прилагаются подробные инструкции и комментарии, поэтому проблем возникнуть не должно. Однако, так как мы будем использовать gstreamer, который не предусмотрен в качестве опции в репозитории первоисточника, то воспользуемся уже модифицированным форком.
Предположим, что у нас уже установлен Nginx и Rtmp-модуль к нему (туториал).
Понадобится gstreamer:
sudo apt-get install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools
Переходим в директорию, которая может быть прочитана Nginx, клонируем туда репозиторий и открываем только что скопированную папку:
cd /usr/local/share
sudo git clone https://github.com/hosseini92/nginx-rtmp-backup.git
cd nginx-rtmp-backup
Теперь нужно отредактировать config.sh
Там можно изменить имена для Rtmp-applications (вместо main, backup, out), определить поведение (будет ли backup обратно переключаться на main, когда тот возобновит работу или нет) и выбрать что использовать в качестве прокладки (avconv|ffmpeg|gst). Но, чтобы не запутаться, оставим все по умолчанию, кроме
# username for nginx worker processes
NGINX_USER="nobody"
# group for NGINX_USER
NGINX_GROUP="nogroup"
Указываем тут свои логин и группу sudo-пользователя (их можно посмотреть введя в терминал команду id).
Далее выдаем права на выполнение скрипту init.sh и запускаем его:
sudo chmod a+x init.sh
sudo ./init.sh
Теперь можно править конфиг Nginx.
Обязательно меняем самую первую строчку user и вписываем туда имя пользователя, которого указывали ранее в NGINX_USER. По умолчанию, там определен www-data (или что-то вроде). На этом я потерял просто кучу времени, так как несовпадающие имена приводили к тому, что операторы exec не запускали скрипты.
user <USER>;
Теперь спускаемся в секцию rtmp и добавляем следующее:
rtmp {
server {
listen 1935;
application out {
live on;
}
application main {
live on;
play_restart on;
exec_publish /usr/local/share/nginx-rtmp-backup/main_publish.sh $name;
exec_publish_done /usr/local/share/nginx-rtmp-backup/main_publish_done.sh $name;
}
application backup {
live on;
play_restart on;
exec_publish_done /usr/local/share/nginx-rtmp-backup/backup_publish_done.sh $name;
}
}
}
Соотвественно, никто не запрещает в out прописать рестримы на любые желаемые площадки, разрешить публикацию только с определенных IP, запретить подключаться к main и out и любые прочие желаемые настройки. Главное, чтобы строки с exec_publish и exec_publish_done оставались на своих местах. Например:
rtmp {
server {
listen 1935;
chunk_size 4096;
allow publish 127.0.0.1;
deny publish all;
application out {
live on;
push rtmp://stream.dlive.tv/live/<key>;
push rtmp://a.rtmp.youtube.com/live2/<key>;
}
application main {
live on;
play_restart on;
allow play 127.0.0.1;
deny play all;
exec_publish /usr/local/share/nginx-rtmp-backup/main_publish.sh $name;
exec_publish_done /usr/local/share/nginx-rtmp-backup/main_publish_done.sh $name;
}
application backup {
live on;
play_restart on;
exec_publish_done /usr/local/share/nginx-rtmp-backup/backup_publish_done.sh $name;
}
}
}
Теперь остается только запустить стримы по соответствующим адресам и с одинаковым ключом. Допустим, ключ придумаем – stream, тогда:
Для main это будет rtmp://ваш.домен/main/stream
Для backup, соответственно, rtmp://ваш.домен/backup/stream
Итоговая трансляция будет доступна по адресу: rtmp://ваш.домен/out/stream
и на всех площадках куда вы обозначили рестрим источника.
Логи сохраняются в директорию /var/log/nginx-rtmp-backup