mirror of
https://codeberg.org/postscriptum/gemlog.git
synced 2026-02-19 06:22:41 +00:00
162 lines
No EOL
9.3 KiB
Text
162 lines
No EOL
9.3 KiB
Text
# Проксування потоку m3u8 засобами ffmpeg в Icecast
|
||
|
||
Я не маю значного досвіду з адміністрування стрімінгових сервісів, раніше на базі Icecast робив тільки локальну ротацію музичної колекції:
|
||
=> setup-icecast-ezstream-web-radio-on-linux.gmi Веб-радіо в Linux: встановлення сервера Icecast та базове налаштування ротації з Ezstream
|
||
|
||
Зацікавив проєкт довкола-айтішних стрімів eQtv:
|
||
=> https://tv.equalitie.org/uk/live/
|
||
|
||
Цей матеріал - невеличка нотатка про налаштування проксі на прикладі сервісу eQtv українською мовою для локальних мереж за адресами:
|
||
=> http://[202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:8000/eQtv.mp3 Yggdrasil
|
||
=> http://[505:6847:c778:61a1:5c6d:e802:d291:8191]:8000/eQtv.mp3 Mycelium
|
||
=> http://mrkssh4b2qkrf5hl4yxrwbtuowbmjugozaa7emaybnokw5jtcydq.b32.i2p/eQtv.mp3 I2P
|
||
|
||
## Джерела
|
||
|
||
Витягнути потік виявилось задачею не тривіальною, я її постійно відкладав але згодом таки знайшов в дебагах (ctrl+shift+i) наступні доріжки:
|
||
|
||
* https://eqtv.live:8083/eqtvua/eqtvua480/chunks_dvr.m3u8 - схоже, що відповідає за відео
|
||
* https://eqtv.live:8083/eqtvua/eqtvua_hd_ukr/chunks_dvr.m3u8 - відповідає за аудіо-ряд (їх 3)
|
||
|
||
## ffmpeg
|
||
|
||
Вже звичний мені ezstream не вміє проксувати потоки з URL, тому віднайшов спосіб з ffmpeg:
|
||
|
||
``` bash
|
||
ffmpeg -i "https://eqtv.live:8083/eqtvua/eqtvua_hd_ukr/chunks_dvr.m3u8?nimblesessionid=xxx" -c:a copy icecast://user:password@127.0.0.1:8000/eQtv.aac
|
||
```
|
||
|
||
У прикладі вище - потік передається в Icecast "як є" у форматі AAC, але такий формат мені не зовсім підходить, бо я хочу окрім оверлейних мереж Yggdrasil і Mycelium ще й стрімити в I2P з його "вузьким" каналом. Хоч конвертація вимагає додаткових ресурсів CPU, все ж вирішив її застосувати, звівши до поширеного формату MP3 з бітрейтом 32 kb/s:
|
||
|
||
``` bash
|
||
ffmpeg -i "https://eqtv.live:8083/eqtvua/eqtvua_hd_ukr/chunks_dvr.m3u8?nimblesessionid=xxx" -b:a 32k icecast://user:password@127.0.0.1:8000/eQtv.mp3
|
||
```
|
||
|
||
Як видно на прикладах вище, я додав до URL джерела аргумент `?nimblesessionid=xxx` - він потрібен для того, щоб ffmpeg не плодив нові сесії в процесі читання. Тут я ще не знаю, як довго протримається поточна сесія, але якщо будуть проблеми - напишу скрипт, що витягає актуальний її номер та доповню цей матеріал.
|
||
|
||
UPD. очікувано, сесія прожила менше доби, тому створив такий скрипт, будемо пускати його в `ExecStart` сервісу systemd, замість сирої команди `ffmpeg`:
|
||
|
||
``` /home/eqtv/stream.sh
|
||
#!/bin/bash
|
||
|
||
# завантажуємо актуальний файл m3u8, що містить активний номер сесії
|
||
# та витягаємо перше знайдене значення в змінну SESSION_ID
|
||
CHUNKS_DVR="/home/eqtv/chunks_dvr.m3u8"
|
||
wget -O $CHUNKS_DVR https://eqtv.live:8083/eqtvua/eqtvua_hd_ukr/chunks_dvr.m3u8
|
||
SESSION_ID=$(grep -oP '(?<=sessionid=)\d+' $CHUNKS_DVR -m 1)
|
||
if [ -z "$SESSION_ID" ]; then
|
||
echo "SESSION_ID is empty. Exiting script."
|
||
exit 1
|
||
fi
|
||
|
||
# запускаємо стрім з актуальним значенням SESSION_ID
|
||
ffmpeg -i "https://eqtv.live:8083/eqtvua/eqtvua_hd_ukr/chunks_dvr.m3u8?nimblesessionid=$SESSION_ID" -b:a 32k icecast://user:password@127.0.0.1:8000/eQtv.mp3
|
||
```
|
||
* цей скрипт передбачає роботу з systemd: під час помилки процесу, буде виконано `Restart=on-failure`, таким чином ключ сесії буде актуалізовано
|
||
|
||
UPD2. згодом, додав аргумент `-re` оскільки стрім вилітав через помилку затримки кодування:
|
||
|
||
``` bash
|
||
ffmpeg -re -i ...
|
||
```
|
||
|
||
UPD3. також, на прикладі eQtv, збільшив гучність аргументом `-af volume=5.0`:
|
||
|
||
``` bash
|
||
ffmpeg -re -i ... -af volume=5.0 ...
|
||
```
|
||
|
||
UPD4. довго шукав рішення для копій потоків AAC, які чомусь не відтворювались у зв'язці ffmpeg + Icecast, але рішення виявилось тривіальним: треба було додати лише заголовок `-content_type 'audio/aac'`:
|
||
|
||
``` bash
|
||
ffmpeg -re -i ... -c:a copy -content_type 'audio/aac' ...
|
||
```
|
||
|
||
## Icecast
|
||
|
||
Декілька слів про налаштування сервера Icecast. Раніше, для локальних колекцій, мета-інформація про стрім в мене обслуговувалась сервером ezstream. Тут його немає, тому я додав такий набір до конфігурації точки монтування Icecast:
|
||
|
||
``` /etc/icecast2/icecast.xml
|
||
<mount type="normal">
|
||
<mount-name>/eQtv.mp3</mount-name>
|
||
<username>user</username>
|
||
<password>password</password>
|
||
<stream-name>eQtv українською мовою (аудіо, 32 kb/s)</stream-name>
|
||
<stream-description>eQtv — це проект eQualitie, неприбуткової організації, що розробляє технології для підвищення цифрової стійкості, особливо для спільнот, яким загрожують цензура, стеження, зміна клімату та мережева ізоляція.</stream-description>
|
||
<stream-url>https://tv.equalitie.org/uk/live</stream-url>
|
||
</mount>
|
||
```
|
||
* відповідно, `user:password` мають відповідати тим, що вказані в команді `ffmpeg`
|
||
|
||
## Systemd
|
||
|
||
Команду `ffmpeg` я виконую від системного сервісу, створивши відповідного користувача:
|
||
|
||
``` /etc/systemd/system/eqtv-mp3.service
|
||
#/etc/systemd/system/eqtv-mp3.service
|
||
[Unit]
|
||
# якщо Icecast локальний, можна додати icecast2.target поряд з network-online
|
||
# After=network-online.target icecast2.target
|
||
After=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
|
||
User=eqtv
|
||
Group=eqtv
|
||
|
||
# Затримка потрібна у моєму випадку через залежність від Icecast
|
||
# ExecStartPre=/bin/sleep 5s
|
||
|
||
# ExecStart=/usr/bin/ffmpeg -i ...
|
||
# ExecStart=/bin/bash /path/to/script.sh
|
||
ExecStart=/path/to/script.sh
|
||
|
||
# Журнали я вимкнув, але можна продебажити наступним чином
|
||
StandardOutput=null
|
||
# file:///home/eqtv/eqtv-mp3-debug.log
|
||
StandardError=null
|
||
# file:///home/eqtv/eqtv-mp3-error.log
|
||
|
||
# Бажано увімкнути, якщо замість команди ffmpeg в ExecStart
|
||
# використовується скрипт оновлення номеру сесії
|
||
Restart=on-failure
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
* в `ExecStart` треба вказати відповідний набір атрибутів `ffmpeg` або шлях до скрипта (вище)
|
||
|
||
## Nginx
|
||
|
||
Як видно з прикладу, мій сервер Icecast крутиться на інтерфейсі `127.0.0.1` для локальних потреб (щоб не ганяти трафік через оверлей). Окрім локалхосту, в мене відбувається ретрансляція на різні мережі IPv6, тому для зручності я проксую клієнтський трафік через Nginx:
|
||
|
||
``` /etc/nginx/sites-available/default
|
||
#/etc/nginx/sites-available/default
|
||
server {
|
||
listen [202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:8000;
|
||
listen [505:6847:c778:61a1:5c6d:e802:d291:8191]:8000;
|
||
listen xx.xx.xx.xx:8000;
|
||
|
||
access_log /var/log/nginx/icecast.access.log;
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:8000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_redirect off;
|
||
}
|
||
}
|
||
```
|
||
* на прикладі `listen` - проксі на Yggdrasil та Mycelium і одна на локальну мережу IPv4
|
||
* `proxy_pass` - може бути відмінний локальний порт від вказаного у прикладах
|
||
|
||
## Посилання
|
||
|
||
=> https://devzone.org.ua/post/proksuvannia-m3u8-zasobamy-icecast Веб-версія цього матеріалу з коментарями на DevZone
|
||
|
||
### Читайте також
|
||
|
||
=> yggdrasil-is-network-with-distributed-routing.gmi Yggdrasil - мережа з децентралізованою маршрутизацією |