Веб-радіо в Linux: встановлення сервера Icecast та базове налаштування ротації з Ezstream
Давно планував і нарешті вирішив таки створити власну "лампову" радіо-станцію для локальної мережі Yggdrasil. Інформації про налаштування Icecast в мережі повно, але для мене знайдена інфа виглядала заплутаною: я не розумів, чому окремо розглядається Icecast, Ices, Ezstream та додатковий скриптинг, у той час як мені для початку було потрібно просто зробити тривіальну річ: мотати по колу плейлист музичних файлів.
В темі стрімінгу та аудіо-обробки - я нуб. З цієї причини вирішив написати невеличкий гайд для Debian/Linux, зрозумілий для себе "в минулому" а також практичну нотатку, на випадок якщо завалю сервер та доведеться пригадувати що робив. Згодом, планую також навчитись додавати ретрансляцію етерів новин за розкладом, можливо - пускати в ефір живі стріми, тоді й розширю цей матеріал до серії.
Icecast
Icecast (https://icecast.org) - це класичний сервер, на базі якого створюється публічний сервіс для слухачів (клієнтів). Його можна порівняти з проксі сервером Nginx для Веб-сайтів, от тільки створений він спеціально для операцій з потоковими даними. Цей сервер ніяк не взаємодіє з медіа-колекціями напряму, він просто отримує на себе сирий потік аудіо (або інших) даних з бекенду (по API) та розподіляє його на активні підключення, виступаючи в ролі хабу, своєрідної "радіо-вежі".
Встановлення
apt install icecast2
Налаштування
Після встановлення пакету з репозиторію, до системи буде автоматично додано сервіс systemd (/etc/init.d/icecast2) та стандартний файл конфігурації (/etc/icecast2/icecast.xml). Зайдемо до останнього та адаптуємо його під свої потреби:
nano /etc/icecast2/icecast.xml
Earth icemaster@localhost 100 2 524288 30 15 10 1 65535 PASSWORD PASSWORD admin PASSWORD ua UTF-8 8000 :: 1 /usr/share/icecast2 /var/log/icecast2 /usr/share/icecast2/web /usr/share/icecast2/admin access.log error.log 3 10000 0
- не забудьте вказати актуальне значення PASSWORD
- після внесення змін, необхідно перезапустити сервіс `systemctl restart icecast2`
Фаєрвол
У прикладі вище, використовується IPv6 маска хостів "::" (у вас це може бути IPv4 типу "0.0.0.0") для доступу без Веб-проксі. Тому відкриваємо й відповідний порт:
ufw allow 8000/tcp
- приклад відкриття порту 8000 для IPv4 + IPv6 (TCP)
Якщо ви плануєте проксуватись через 80/443 порти Nginx (у вас там має бути вже відкритим 80/tcp / 433/tcp відповідно), або у вас локальний хост на кшталт "::1" чи "127.0.0.1" (стандартно) тоді відкривати не потрібно.
Веб-проксі через Nginx
Хоча сам не користуюсь такою комбінацією, але додам нотатку з налаштування проксі для віртуального хосту Nginx, на прикладі конфігурації бекенд-сервера "127.0.0.1:8000"
server {
# розкоментуйте, якщо використовуєте IPv4
# listen IPv4:80
listen [IPv6]:80;
server_name IPv4 IPv6 DOMAIN_1 DOMAIN_2;
location / {
proxy_pass http://127.0.0.1:8000;
# розкоментуйте значення якщо делегуєте журналювання серверу icecast
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-Proto $scheme;
}
}
- IPv4 і IPv6 - публічні адреси вашого Веб-сервера (Nginx)
- DOMAIN_1 і DOMAIN_2 - домени/субдомени/аліаси через пробіл, якщо використовуються
- не забуваємо відкрити порт 80 (і/або 443 якщо використовується)
SSL/TLS
В принципі, можна використовувати модні "захищені" з'єднання, але для стрімінгу я бачу його використання не доречним з точки зору енергозаощадження і здорового глузду в плані шифрування потоків з публічними даними. Дивіться самі, особисто я по причині вище завжди прослуховую радіо-станції по HTTP, якщо така опція надається сервером.
Ezstream
Коли "станцію" Icecast налаштовано, нам потрібно надіслати їй дані для трансляції. Такі дані можуть бути голосовими / потоковими або зберігатись у бінарних файлах. Оскільки мені потрібен останній варіант, з ним є одна не очевидна на перший погляд проблема: усі вони мають різні формати (`ogg`, `flac`, `mp3`, тощо) а також різні бітрейти та інші характеристики (в яких не торопаю). Оскільки вихідний стрім для слухача завжди має один формат, нам потрібно якимось чином відформатувати нашу колекцію до уніфікованого потоку: для цієї задачі й потрібен такий софт як Ezstream.
На відміну від популярної комбінації Icecast2 + Ices2 (https://icecast.org/ices/), Ezstream (https://icecast.org/ezstream/) відрізняється тим, що підтримує більше медіа-форматів з коробки та є простішим в налаштуванні (для поточних завдань)
Встановлення
apt install ezstream
Налаштування
Створімо окремого користувача з домашньою текою, де зберігатимуться налаштування та аудіо-файли:
useradd -m ezstream
Створення списку ротації
Насамперед, варто зауважити, що якщо це ротація великої колекції по колу, то медіа файли бажано звести до єдиного формату. Якщо цього не зробити то Ezstream буде конвертувати файли на льоту, що потребуватиме додаткових ресурсів CPU. На цьому етапі я не робив того, використовуючи колекцію що складається з mp3 і стрім мій буде в цьому ж форматі. Єдине що, я сумніваюся щодо різного бітрейту та інших аудіо-характеристик, це буде окремою темою про конвертацію наприклад з `ffmpeg`, але майте на увазі цей нюанс.
Для початку, завантажимо потрібні аудіофайли до умовної теки /home/ezstream/my-stream/collection. Якщо планується декілька тематичних стрімів, буде зручно заздалегідь створити для них простір імен у вигляді підтек, наприклад:
- mkdir -p /home/ezstream/my-stream-1/collection
- mkdir -p /home/ezstream/my-stream-2/collection
- ...
Після того, як до колекції додано медіа-файли, згенеруємо для них мета-індекс для ротації в Ezstream. На виході це буде звичайний текстовий список шляхів до файлів по одному на рядок:
find /home/ezstream/my-stream/collection -name *.mp3 > /home/ezstream/my-stream/playlist.txt
- у даному прикладі, всі мої файли у форматі mp3, тому пошук відбувається за відповідним суфіксом, інші розширення у цьому прикладі будуть проігноровані
Оскільки операції вище я проводив від рута (без попереднього логіну з `su ezstream`) варто виправити права Unix, адже наш сервіс systemd пускатиметься саме від користувача ezstream:
chown ezstream:ezstream -R ~/ezstream
Конфігурація Ezstream
Коли дані ротації готові, можна перейти безпосередньо до налаштувань Ezstream.
Щоб не переварювати зайві опції, копіюємо мінімальний конфіг в домашню теку користувача `ezstream`:
cp /usr/share/doc/ezstream/examples/ezstream-minimal.xml /home/ezstream/my-stream/config.xml
- замініть "my-stream" на логічну назву проєкту та занотуйте шлях - він також буде потрібен для налаштування systemd
Якщо вам потрібні додаткові опції, дивимось доступні пресети з коментарями:
ls /usr/share/doc/ezstream/examples/
Мій файл для конфігурації Icecast вище, містить деякі додаткові опції та зараз виглядає так:
::1 PASSWORD NAME DESCRIPTION GENRE /my-stream.mp3 mp3 /home/ezstream/my-stream/playlist.txt No No
Зауважу, що на кожен потік (стрім) потрібен окремий файл конфігурації / systemd процес, не додавайте масив <stream> в <streams> - це так не працює і якщо ви додасте декілька, потік просто видаватиме один з потоків. Тобто для кожного стріму - має бути окремий файл конфігурації і окремий конфіг systemd для нього, тому вище ми і створили неймспейс "/home/ezstream/my-stream"
systemd
Останнє, що потрібно зробити - це створити сервіс systemd для налаштованого потоку Ezstream. Запускатиметься він від створеного вище користувача ezstream та вище створеної конфігурації "/home/ezstream/my-stream/config.xml"
nano /etc/systemd/system/ezstream-my-stream.service
- назвати файл можна як завгодно, головне щоб ви його потім впізнали та відрізнили від інших сервісів / потоків Ezstream
[Unit] After=network.target [Service] Type=simple # актуальні користувач/група User=ezstream Group=ezstream # я додав затримку, оскільки потік не зможе стартувати, # якщо процес icecast того зробити не встиг (наприклад, при старті системи) ExecStartPre=/bin/sleep 5s # вказуємо коректний шлях до конфігурації ExecStart=/usr/bin/ezstream -c /home/ezstream/my-stream/config.xml # вказуємо актуальні шляхи до майбутніх журналів StandardOutput=file:/home/ezstream/my-stream/mainstream-debug.log StandardError=file:/home/ezstream/my-stream/mainstream-error.log # можна розкоментувати, але тоді ви можете не помітити збій окрім як читаючи логи # Restart=on-failure [Install] WantedBy=multi-user.target
Зберігаємось (Ctrl+X + Y) і виконуємо один раз в послідовності:
1. `systemctl enable ezstream-my-stream` - додаємо автозапуск стріма при старті системи
2. `systemctl start ezstream-my-stream` - стартуємо стрім
3. `systemctl status ezstream-my-stream` - перевіряємо статус
- `systemctl stop ezstream-my-stream` - зупинити стрім (опціонально)
Ось власне і все, перезавантажувати процес Icecast не потрібно, конкретний потік Ezstream буде змонтовано та відмонтовано автоматично під час запуску / зупинки його процесу.
Тестування
Тепер можна в браузері перейти за адресою вашого сервера Icecast: на прикладі конфігурації вище, це http://[IP]:8000
Якщо у вас активні процеси Ezstream, вони мають відображатися в списку на головній сторінці. До кожного потоку, з права є кнопки експорту в форматах M3U і XSPF - якщо на них клікнути вони або скачаються або відкриються в плеєрі, що підтримує стрімінг. В себе на Fedora, я відкриваю .m3u як текстовий файл та виймаю з нього URL, після чого копіюю в розділ "Radio" програвача "Rhythmbox" :)