Особая благодарность EvergreenDeer, автору канала Deer Radio, за подсказки <3
Что в этой статье?
Данный гайд содержит в себе, по сути, готовый скрипт на языке программирования Liquidsoap, который воспроизводит зацикленное видео/анимацию/изображение и плейлист с музыкой из папки (добавляя новые треки в папку, плейлист будет обновляться автоматически) , показывает метаданные треков на экране (Исполнитель – Название песни), ну и отправляет поток на Youtube (или любую другую площадку, поддерживающую стримы). Проще говоря, типичный шаблон Lofi-радио.
А также подробную пошаговую инструкцию по установке и настройке минимально необходимого для запуска на виртуальном приватном сервере на базе Linux (Ubuntu в конкретном случае). С тем учетом, чтобы даже новичок смог разобраться и повторить эту процедуру.
В общем, вся та информация, которой мне остро не хватало, когда я загорелся идеей создания собственного 24/7 музыкального стрима.
Не обойдется и без лирических отступлений, которые можно было бы и пропустить, но и без них тоже нельзя.
UPD: Появилось дополнение к этому гайду: https://mikulski.rocks/ru/lofi-strim-24-7-guide-ch2/, с примерами того, как можно усовершенствовать свой радио-стрим.
Моя кулстори
Так или иначе данный гайд перекликается с моим предыдущим туториалом “Как я сделал свое Стрим-Радио 24/7” на основе скрипта Ffplayout. Материал, к сожалению, уже не столь актуален, т.к. разработчик перешел с языка Python на Rust, а потому изменился процесс установки и отдельные детали настройки. Тем не менее в том посте я описал чуть более развернуто о выборе VPS и о других моментах, чем будет в этом посте, а потому также рекомендую к ознакомлению.
Ffplayout заточен именно под непрерывное воспроизведение плейлиста с видеофайлами и он меня всецело устраивал. Но я всегда хотел научиться создавать стримы по типу Lofi 24/7: зацикленная гифка и музыка. Казалось бы, что может быть проще? И это просто, если есть средства арендовать сервер с графической оболочкой и установить там OBS, либо воспользоваться готовыми решениями “из-коробки” от Onbubble или permastream.io.
Про Liquidsoap и его широкие возможности я узнал достаточно скоро, но пугала необходимость разбираться в объемной документации и самому программировать код (опыта программирования у меня вообще нет). А потому я излазил Github вдоль и поперек в поиске готовых решений, но все найденное либо не запускалось из-под моих кривых рук, либо работало крайне нестабильно. В общем, я оставил эту затею почти на год, пока место на диске не забилось видео под завязку и не встал вопрос о переходе на более дорогую конфигурацию VPS: хостером не было предусмотрено наращивание отдельных компонентов. Я решил, что это хороший повод, чтобы вернуться к Liquidsoap, попытаться собрать минималистичный скрипт и сменить формат радио с показа видеороликов на воспроизведение треков. Как ни крути, стрим с видеороликами многих сбивал с толку, несмотря на то, что вся информация была и в названии стрима и в описании, а сами видео были смонтированы. Самая частая фраза в чате: “Это запись?”.
Как бы то ни было все оказалось не так уж сложно. Стоило просто набраться терпения и последовательно прочесть несколько первых глав The Liquidsoap book, а затем отдельные части этого руководства, чтобы собрать рабочий стрим, а впоследствии и модернизировать его разными “фишками”. Так что, если вдруг вы увлечетесь “радиостроением” или же захотите что-то надстроить в скрипте, которым я поделюсь, то эта книга – ваш верный помощник.
Ограничения и Что важно понимать?
- Я никакой не программист и не сетевой администратор, а всего лишь энтузиаст. Поэтому, не исключено, что знающим специалистам некоторые моменты или формулировки могут показаться глупыми и нелепыми.
- Версия Liquidsoap в данном гайде 2.1.2.
- Операционная система VPS в данном гайде – Ubuntu 20.04 (на 22.04 установка на этапе opam install обрывается на слабой конфигурации).
- Установка будет содержать только необходимый минимум библиотек для этого сетапа.
- Устанавливать Liquidsoap желательно на чистую систему. Либо остановить ВСЕ возможные процессы на сервере (особенно, если VPS маломощный, как в данном случае). Компилятор Ocaml весьма прожорлив на ресурсы, поэтому велика вероятность, что он будет выдавать ошибку в процессе установки необходимых компонентов.
- Алерты и виджеты (например, с DonationAlerts) добавить в сцену, по-легкому, не получится. Liquidsoap с такого рода веб-источниками, по умолчанию, не совместим. Возможно есть способ это сделать, но я пока не понимаю, как именно. Впрочем, если вы обращали внимание, то на 24/7 стримах, не то что виджеты, даже названия треков не всегда отображаются.
- Конфигурация VPS, которая справляется со стримом в 720p (нагрузка процессора от 70 до 90%): 1 CPU 2400MHz и 1 GB RAM, Пресет видеокодека: Veryfast. 1080p, к сожалению не тянет, – даже при пресете Superfast нагрузка под 100% и лаги.
- Место на диске, которое займет система и все устанавливаемые компоненты около 4.5гб.
- Удостоверьтесь, что ваш хостер предоставляет веб-оболочку с файл-менеджером к файловой системе VPS. Это значительно упростит редактирование текста и загрузку файлов. Либо освойте подключение к VPS через FTP для этих целей.
- Также, плюсом будет веб-оболочка для терминала/командной строки. Несмотря на то, что всю установку я буду объяснять через подключение из Windows Powershell (так удобнее и быстрее) – веб-оболочка упростит запуск/остановку скрипта в дальнейшем.
- Как правило, в платных тарифах интернет-трафик безлимитный. Но на это тоже стоит обратить внимание и рассчитать трафик заранее, если его объем ограничен месячным лимитом: количество секунд в месяц x битрейт = наш трафик.
Например, мы планируем, стримить в разрешении 720p с битрейтом 1500kbps (1,5 mbps):
2592000 секунд в месяц Х 1,5mbps битрейта= 3888000mb, конвертируем эту величину в Терабайты (обычно трафик указывается в ТБ) через любой онлайн конвертер величин и получаем 0,48 ТБ в месяц. Следовательно, 1 ТБ трафика в месяц будет с лихвой хватать для трансляции в 720p. - На рынке большой выбор VPS. У меня нет опыта использования разных хостеров, поэтому посоветовать ничего не могу. Сам я, для удобства, выбрал того же провайдера – beget.com, который хостит мой сайт и где есть веб-оболочки для файл-менеджера и терминала, а также безлимитный трафик с широким каналом.
Установка Liquidsoap
VPS арендован, его IP-адрес и пароль root-пользователя получены – можно подключаться.
Для этого нужно открыть утилиту Windows Powershell и ввести команду:
ssh root@ip_адрес_вашего_сервера
Система запросит пароль и после его верного ввода (введенных символов или “*” на экране не будет видно – это нормально) состоится подключение.
Важно! В командной строке не работают привычные комбинации для копирования/вставки из буфера. CTRL+C - останавливает текущий запущенный процесс! В Powershell копировать/вставить осуществляется "Правым кликом" мыши! Клавишей "Вверх" можно вызвать последние вводимые команды - чтобы не печатать их каждый раз заново.
Первым делом нужно создать нового пользователя и задать пароль:
sudo adduser ВАШ_НИК
Теперь важно наделить этого пользователя необходимыми правами:
sudo usermod -aG sudo ВАШ_НИК
Осталось зайти под этим пользователем:
su ВАШ_НИК
В дальнейшем, к серверу следует подключаться этим пользователем, т.к. все установленные компоненты будут закреплены за этой учеткой (а еще Liquidsoap не особо любит запуск от имени root):
ssh ВАШ_НИК@ip_адрес_вашего_сервера
Прежде всего следует установить библиотеку, которая понадобится для отображения метаданных трека:
sudo apt-get install libfreetype6-dev
Для корректной установки Liquidsoap и его зависимостей нужен OPAM (Ocaml Package Manager) не ниже версии 2.0:
sudo apt-get install opam
Затем
opam init
Когда установка завершится, надо ввести команду, чтобы синхронизировать OCaml с текущим окружением (это нужно делать каждый раз, когда в логе вы увидите сообщение “run eval $(opam env
)”):
eval $(opam env)
А также OCaml версии не ниже 4.12.0. Предлагаю установить 4.14.0, взяв пример из инструкции https://cs3110.github.io/textbook/chapters/preface/install.html:
opam switch create cs3110-2022fa ocaml-base-compiler.4.14.0
Это займет какое-то время, наберитесь терпения и не пугайтесь, если покажется, что система зависла.
И снова
eval $(opam env)
Теперь можно переходить к непосредственно самой установке Liquidsoap. Сперва нужно сделать “запрос”, который скачает все недостающие компоненты для запрашиваемых библиотек:
opam depext gd ffmpeg liquidsoap
А потом установить:
opam install gd ffmpeg liquidsoap
Где: gd – плагин, который понадобится для отображения текста, ffmpeg – кодировщик аудио/видео потоков, liquidsoap – это Liquidsoap с набором стандартных библиотек.
UPD: Команды opam depext/install liquidsoap установят последнюю версию Liquidsoap! На сегодня (июль 2023) вышла новая версия Liquidsoap 2.2.0, в которую был внесен ряд изменений и которая, возможно, будет потреблять больше ресурсов CPU. Поэтому, рекомендую установить версию 2.1.4 (последняя в ветке 2.1.x и с требованием к версии Ocaml не ниже 4.13.0). Полная команда в таком случае будет выглядеть так: opam depext gd ffmpeg liquidsoap.2.1.4 opam install gd ffmpeg liquidsoap.2.1.4
И в последний раз на сегодня:
eval $(opam env)
Готово! Чтобы удостовериться, что все прошло гладко можно проверить версию Liquidsoap и список установленных библиотек:
liquidsoap --version opam list
Скрипт
Первым делом надо создать папки, где будут находится скрипт, фоновая анимация и музыка. Это желательно все сделать из консоли от имени созданного пользователя, чтобы избежать конфликтов ролей и прав в системе (LInux достаточно щепетилен в этом отношении):
cd mkdir /home/ВАШ_НИК/radio mkdir /home/ВАШ_НИК/radio/music
Теперь можно текстовым редактором nano создать файл (этой же командой его можно будет открыть снова):
nano /home/ВАШ_НИК/radio/stream.liq
Скопируйте и вставьте содержимое из этого шаблона:
#разрешение запуска от root / permission to run the script from the root user
settings.init.allow_root.set(true)
#функции для метаданных / metadata functions
song_author = ref('')
def apply_song(m) =
song_author := m["artist"]
end
song_title = ref('')
def apply_song2(m) =
song_title := m["title"]
end
def get_track_name_text()
"$(artist) - $(title)" % [
("artist", !song_author),
("title", !song_title)
]
end
# источник аудио / audio source
audio = playlist(reload_mode="watch", "/home/ВАШ_НИК/radio/music")
audio = mksafe(audio)
#источник видео / video source
background = single("/home/ВАШ_НИК/radio/background.gif")
#вызов метаданных / calling metadata
audio.on_track(apply_song)
audio.on_track(apply_song2)
#отрисовка текста / drawtext
background = video.add_text(color=0xFFFFFF, font="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", speed=0, x=50, y=50, size=26,
get_track_name_text,
background)
# смешивание / mixing sources
radio = mux_video(video=background, audio)
#rtmp+codec
url = "rtmp://localhost/live"
enc = %ffmpeg(format="flv",
%video(codec="libx264", width=1280, height=720, pixel_format="yuv420p",
b="750k", maxrate="750k", minrate="750k", bufsize="1500k", profile="Main", preset="veryfast", framerate=30, g=60),
%audio(codec="aac", samplerate=44100, b="128k"))
#вывод / output
output.url(fallible=true, url=url, enc, radio)
UPD: если вы все-таки установили версию 2.2.0, то в ней немного изменился синтаксис (вместо '!x', следует писать 'x()') и блок с метаданными будет выглядеть так: def get_track_name_text() "$(artist) - $(title)" % [ ("artist", song_author()), ("title", song_title()) ] end
Чтобы сохранить изменения в nano, надо нажать F3 и подтвердить изменения.
F2, чтобы выйти из редактора.
Давайте разбираться и редактировать:
- Символ # перед строкой обозначает, что эта строка “закомментирована” и не влияет на код.
- settings.init.allow_root.set(true) – на всякий случай (если вдруг вы поленились создавать нового пользователя), разрешается запускать скрипт root-пользователем. Технически, можно удалить ее.
- Блок “Функции метаданных” лучше не трогать – эти функции собирают информацию о треках из тегов mp3-файлов.
- Источник аудио.
* audio – имя переменной; playlist – режим воспроизведения файлов из папки (рандом включен по умолчанию); reload_mode = “watch” – значит, что плейлист обновится, как только в папку попадет новый файл; путь к папке – “/путь/к/папке”. <- не забудьте отредактировать директорию!
* audio = mksafe(audio) – делаем источник “безопасным”. То есть если что-то случится с папкой с музыкой, то скрипт не сломается, а переключится на воспроизведение тишины.- Источник видео
* background – имя переменной; single – режим воспроизведения единичного файла и путь к нему. По умолчанию зациклен. Можно указать gif-анимацию, jpg/png – изображения, mp4 – видео. <- не забудьте отредактировать директорию! - В блоке “Вызов метаданных “, – скрипт обращается к функциям из блока “функции метаданных”, чтобы собрать “Исполнитель – Песня” для текущего воспроизводимого трека.
- Блок “Отрисовка текста”. Здесь указывается какой текст (get_track_name_text) и поверх какого источника (background) нужно отрисовать текст. А также атрибуты этого текста:
*color=0xFFFFFF – цвет текста, в этом примере задан белый. Подходят коды html-разметки: код нужно подставить после “0x”. Например, желтый цвет с этого сайта будет выглядеть так: color=0xFCB900.
*font=”/путь/к/шрифту” – указывается шрифт для отрисовки. В данном примере используется стандартный в Linux путь и шрифт. Для удобства, я рекомендую закидывать шрифты в ту же папку, где находится и сам скрипт.
*speed=0 – означает, что текст статичен. Если поменять значение, то текста будет плыть по экрану.
*x=50, y= 50 – координаты, где будет располагаться текст. x=0, y=0 – это левый верхний угол. Важно заметить, что в Liquidsoap не предусмотрены готовые инструменты для выравнивания текста (во всяком случае, я не смог разобраться или придумать математическую формулу для этого). Т.к. шаблон опирается на Lofi – радиостанции, то в данном примере текст размещается в левом верхнем углу с небольшим отступом от краев.
*size= – размер шрифта. - “Смешивание”. Или правильнее, “Мультиплексор”. Грубо говоря объединяем видео и аудио в единый источник.
- Блок “rtmp+codec”. Здесь определяется на какой адрес отправлять поток и указываются настройки для кодировщика.
* url = “rtmp://a.rtmp.youtube.com/live2/ключ_трансляции” – здесь прописываются rtmp адрес и ключ трансляции, которые выдает площадка для стриминга. Если вы хотите рестримить сразу на несколько площадок или просто улучшить стабильность потока, то рекомендую дополнительно установить и настроить Nginx-сервер с Rtmp-модулем. Не так давно я опубликовал подробный гайд и на эту тему.
*enc = – настройки кодировщика. Здесь начинается область творчества, экспериментов и личных предпочтений. Графы codec (как для видео, так и для аудио) и pixel_format, я рекомендую не трогать, если вы не знаете как этим пользоваться.
*width=, height= – желаемое разрешение в пикселях (1920 x 1080 / 1280 x 720 и так далее).
*b= – битрейт. Чтобы установить постоянный битрейт (CBR), что часто рекомендуется стрим-сервисами, то надо продублировать значение b в maxrate и minrate. Размер буфера bufsize – обычно устанавливается просто в два раза больше битрейта.
*Дальше стандартные значения profile=”Main” и preset=”veryfast”.
*framerate=, g= – количество кадров в секунду и количество ключевых кадров. Здесь я могу сильно ошибаться. Но, насколько я понял, то g (GOP-size) – надо указывать вдвое больше framerate (кадров в секунду) и тогда получится, что ключевые кадры будут вставляться каждые 2 секунды.
Подбор битрейта, очевидно, большая тема для дискуссий. Я же для себя решил опираться на битрейт и фреймрейт исходного видео для фона, посмотрев их в свойствах файла и установив близкие значения в кодере. В любом случае, чем ниже битрейт, тем лучше транслируемость, что для радио основополагающий фактор.
*Для аудио-кодека ставим параметры частоты дискретизации – samplerate=44100 (классика) и битрейт b= – тут по вкусу. Но явно не больше 320k. А так, насколько могу судить, то радиостанции редко устанавливают битрейт выше 128k. - Последняя строчка кода берет информацию из кодировщика, берет смешанный источник и отправляет его в эфир по указанному адресу.
- Источник видео
С этим разобрались. Осталось загрузить треки в папку с музыкой через файл-менеджер или FTP и приступать к запуску.
Запуск
Чтобы запустить скрипт, надо перейти в папку, где он хранится:
cd /home/ВАШ_НИК/radio
И ввести команду:
liquidsoap имя_скрипта.liq
Или же если всецело следовать этому гайду, то:
liquidsoap stream.liq
По экрану побегут строчки и если что-то не так, то он сразу прекратит свою работу: надо лезть в скрипт и смотреть, может быть, где-то допущена ошибка (не закрыта скобка, пропущена запятая и так далее).
Если же все хорошо, то стрим запустится и можно лицезреть воочию результат своих стараний.
Но, если закрыть Powershell, то скрипт прекратит свою работу и стрим упадет.
Если у хостера есть веб-оболочка для терминала, то надо его открыть и залогиниться от имени созданного пользователя.
И повторить процедуру запуска: перейти в папку со скриптом и запустить его. Браузер можно закрыть – скрипт продолжить работать.
Если потребуется что-то изменить в скрипте, то после внесения правок, надо открыть этот веб-терминал (вы увидите что процесс идет), остановить процесс (CTRL+C), нажать клавишу “Вверх”, чтобы вызвать последнюю команду (это был запуск скрипта) и снова активировать Liquidsoap.
Если же веб-оболочки терминала нет, или вам просто хочется всем управлять из Powershell, то запускаться следует командой со следующими атрибутами для активации работы в фоновом режиме:
nohup liquidsoap stream.liq &
После чего можно смело закрывать окно Powershell. При повторном подключении к серверу, бегущих строчек в логе вы не увидите. Поэтому, чтобы остановить скрипт, надо “убить” фоновый процесс:
killall liquidsoap
UPD: Появилось дополнение к этому гайду: https://mikulski.rocks/ru/lofi-strim-24-7-guide-ch2/, с примерами того, как можно усовершенствовать свой радио-стрим.