Повноцінне інтернет-радіо на Ubuntu 20.04 та Icecast 2.4 + Liquidsoap 1.4

В повсякденному житті я використовую Ubuntu як операційну систему на своєму комп’ютері. Моє знайомство з Linux почалось ще в 2006 році. І починаючи з Ubuntu 6.06, я залишаюсь фаном цієї системи. У свій вільний час я люблю адмініструвати сервери. Встановлювати та тестувати різноманітний цікавий софт.

Ідея своєї інтернет-радіостанції зацікавила мене десь 2009 року. В різний час я реалізовував її по-різному. На початку я тестував зв’язки з сервером Shoutcast, але швидко зрозумів, що Windows не моє. Після я почав цікавитись які програми, для інтернет радіо є в моїй улюбленій Ubuntu і був приємно здивований. Насправді Linux дає великі можливості для потокових трансляцій. Свого часу я успішно запускав зв’язки Icecast2 + Ezstreamer та Icecast2 + Ices. Цей софт гарно працює і його достатньо для звичайного потокового радіо. Проте, якщо ви хочете чогось незвичайного та дійсно вражаючого – вам потрібен Liquidsoap!

Вперше я познайомився з рідким милом (саме так переводиться назва застосунку) в 2018 році, версія 1.1.1. Я пам’ятаю, що возився кілька днів поки все налаштував як треба, але на виході я отримав реальну бомбу. Я посортував музику по жанрах, окремо виніс програми, жарти, джингли. Все це працювало по визначеному графіку. Liquidsoap дозволяє реалізувати це доволі просто, бо це не просто програма, яка крутить музику в заданому порядку, це мова програмування, яка дуже гнучка і дозволяє вам робити круті речі.

І так в мене все це собі працювало на VPS під Ubuntu 18.04 до 2023 року. Поки мій провайдер не відправив мені повідомлення, що вони закриваються. І відповідно мені треба переходить кудись інше. Нічого страшного, подувам я, перенесу музику, конфігураційні файли і гайда далі в ефір. Але не сталось так як гадалось 🙂 Переїздить я вирішив на Ubuntu 20.04. А там в репозиторіях вже Liquidsoap 1.4.1. Конфіги зі старого не підійшли, нічого не запрацювало. Прийшлось все робити по-новому.

Не знаю чому, але як і вперше, прийшлось повозитись. Інформації в інтернеті теж не багато. За основу брав статтю з офіційного сайту. Дуже допомогла стаття діджея з Німеччини, але на момент написання цього матеріалу, вона була не доступна. Я відкривав її через веб архів та читав збережену копію. Також в процесі налаштування прийшло деяке розуміння того як працює рідке мило, чим я поділюсь далі. Отже, переходимо до налаштувань! Всі маніпуляції будемо проводити користувачем з правами root!

Icecast2

З ним в мене все просто. Є конфіг, він працює років 10 вже, якщо не більше, я його просто переношу з сервера на сервер. Його вміст:

<icecast>
<location>earth</location>
<admin>info@china-way.top</admin>

<limits>
<clients>200</clients>
<sources>4</sources>
<threadpool>5</threadpool>
<queue-size>524288</queue-size>
<client-timeout>30</client-timeout>
<header-timeout>15</header-timeout>
<source-timeout>10</source-timeout>
<burst-on-connect>1</burst-on-connect>
<burst-size>65535</burst-size>
</limits>

<authentication>
<source-password>hack</source-password>
<relay-password>hack</relay-password>
<admin-user>admin</admin-user>
<admin-password>hack</admin-password>
</authentication>
<hostname>localhost</hostname>

<listen-socket>
<port>8000</port>
</listen-socket>
<fileserve>1</fileserve>
<mount>
<mount-name>/live</mount-name>
<charset>CP1251</charset>
<fallback-mount>/play</fallback-mount>
<fallback-override>1</fallback-override>
<fallback-when-full>1</fallback-when-full>
</mount>
<mount>
<mount-name>/play</mount-name>
<charset>CP1251</charset>
</mount>
    <mount>
      <fallback-mount>/play</fallback-mount>
      <fallback-override>1</fallback-override>
      <fallback-when-full>1</fallback-when-full>
      <mount-name>/live_320</mount-name>
      <charset>UTF8</charset>
    </mount>
    
    <mount>
      <fallback-mount>/play</fallback-mount>
      <fallback-override>1</fallback-override>
      <fallback-when-full>1</fallback-when-full>
      <mount-name>/live_128</mount-name>
      <charset>UTF8</charset>
    </mount>

<relay>
<server>120.79.203.244</server>
<port>8000</port>
<mount>/live</mount>
<local-mount>/cwcn</local-mount>
<on-demand>0</on-demand>
<relay-shoutcast-metadata>1</relay-shoutcast-metadata>
</relay>
<paths>
<logdir>/usr/share/icecast2/logs</logdir>
<webroot>/usr/share/icecast2/web</webroot>
<adminroot>/usr/share/icecast2/admin</adminroot>
<alias source="/" dest="/status.xsl"/>
</paths>

<logging>
<accesslog>access.log</accesslog>
<errorlog>error.log</errorlog>
<loglevel>3</loglevel>
<logsize>10000</logsize>
</logging>

<security>
<chroot>0</chroot>
<changeowner>
<user>icecast2</user>
<group>icecast</group>
</changeowner>
</security>

</icecast>

Цей конфігураційний файл дозволяє підключити транслятор музики на точку /play в мене тут працює liquidsoap. Також є окрема точка /live сюди підключається студія із Radioboss і йде прямий ефір від ведучих. Є ретранслятор на точці /cwcn та дві додаткові точки монтування, вони призначені для окремих функцій. Коли будете використовувати цей конфіг, не забудьте змінити дані: хости, порти, паролі. Також вам треба вказати демона icecast2 власником даного файлу. Зробити це можна цією командою:

chown icecast2:icecast /etc/icecat2/icecast.xml

Запускаємо Icecast2:

icecast2 -c /etc/icecast2/icecast.xml

Якщо ви все зробили правильно, перейшовши за адресою вашого сервера в браузері, у мене це http://localhost:8000 ви маєте побачити подібну сторінку:

Іноді буває, що Icecast2 не хоче стартувати із системою. Включити його в автозапуск можна командою:

systemctl enable icecast2

Liquidsoap

Тут все трішки складніше … Після встановлення в мене не вийшло просто скопіювати свій старий конфіг і запустити радіо. Не підійшов і файл з офіційного сайту і будь-який інший з інтернету … Мабуть маю особливу удачу 🙂 Тож прийшлось ліпити новий конфіг самому, беручи частинками з різних джерел. На виході я отримав:

#!/usr/bin/liquidsoap
# Log dir
set("log.file.path","/var/log/liquidsoap/radio.log")
#Наступна директива потрібна, щоб ви могли запускати програму під рутом.
set("init.allow_root",true)
#Ці налаштування потрібні для того, щоб коли ви запустите з під рута
#Liquidsoap запустився як сервіс і ви могли далі працювати в терміналі
#Якщо закоментувати, після запуску ви не зможете користуватись терміналом
#Я використовую це тільки під час налаштування, потім коментую
#Якщо ви використовуєте, треба створити відповідну папку і файл
#"/etc/liquidsoap/daemon/pid.txt" - також потрібні права для liquidsoap
set("init.daemon.pidfile.path", "/etc/liquidsoap/daemon/pid.txt")
set("init.daemon",true)
#Вмикаємо кросcфейди
%include "crossfade.liq"
#Якщо щось зламається буде грати цей трек, щоб в ефірі не було тиші.
default = single("/home/music/1.mp3")
#Моя музика, яка буде йти в ефір, вдень, вночі, та хіти.
day     = playlist("/home/music/day/playlist.pls")
hit     = playlist("/home/music/hit/playlist.pls")
night   = playlist("/home/music/night/playlist.pls")
jingles = playlist("/home/music/jingl/playlist.pls")
# Вказуємо час, коли і що буде виходить в ефір.
# Вказувати треба час, який встановлений на вашому сервері.
radio = fallback([ request.queue(id="request"),
                    switch([({ 23h-6h }, day),
                            ({ 6h-11h }, hit),
                            ({ 11h-23h }, night)]),
                    default])
# Додаємо джингли. Джингл буде запускатись кожні 4 трека.
radio = random(weights = [1, 4],[jingles, radio])
# Тонкі налаштування кросcфейдів.
radio = smart_crossfade(start_next=8., fade_in=6., fade_out=6., width=2., conservative=true, radio)
#Якщо щось піде не так, наприклад ви перемістите папки з музикою.
#То запуститься трек за замовченням, ми його вказали вище.
radio = fallback(track_sensitive = false, [radio, default])
#Виводимо наш потік на сервер Icecast2.
output.icecast(%mp3(bitrate=128, samplerate = 44100, stereo = true), host = "localhost", port = 8000, name="Radchuk",genre="various", url="http://vitalii.radchuk.info", description="My cool radio", password = "hack", mount = "/play", radio)

Це все копіюємо, далі створюємо файл і вставляємо туди:

nano /etc/liquidsoap/radio.liq

Якщо вийшло так, що вказаної папки ще не існує створюємо її:

mkdir /etc/liquidsoap

Тепер повторюємо попередню дії, все має вийти на цей раз. Зараз створюємо основний файл налаштувань для кроссфейдів:

nano /etc/liquidsoap/crossfade.liq

Тут я нічого не міняв і не додавав, все взято з офіційного сайту, вставляємо:

# Crossfade between tracks, 
# taking the respective volume levels 
# into account in the choice of the 
# transition.
# @category Source / Track Processing
# @param ~start_next   Crossing duration, if any.
# @param ~fade_in      Fade-in duration, if any.
# @param ~fade_out     Fade-out duration, if any.
# @param ~width        Width of the volume analysis window.
# @param ~conservative Always prepare for
#                      a premature end-of-track.
# @param s             The input source.
def smart_crossfade (~start_next=5.,~fade_in=3.,
                     ~fade_out=3., ~width=2.,
                     ~conservative=true,s)
  high   = -20.
  medium = -32.
  margin = 4.
  fade.out = fade.out(type="sin",duration=fade_out)
  fade.in  = fade.in(type="sin",duration=fade_in)
  add = fun (a,b) -> add(normalize=false,[b,a])
  log = log(label="smart_crossfade")

  def transition(a,b,ma,mb,sa,sb)

    list.iter(fun(x)-> 
       log(level=4,"Before: #{x}"),ma)
    list.iter(fun(x)-> 
       log(level=4,"After : #{x}"),mb)

    if
      # If A and B and not too loud and close, 
      # fully cross-fade them.
      a <= medium and 
      b <= medium and 
      abs(a - b) <= margin
    then
      log("Transition: crossed, fade-in, fade-out.")
      add(fade.out(sa),fade.in(sb))

    elsif
      # If B is significantly louder than A, 
      # only fade-out A.
      # We don't want to fade almost silent things, 
      # ask for >medium.
      b >= a + margin and a >= medium and b <= high
    then
      log("Transition: crossed, fade-out.")
      add(fade.out(sa),sb)

    elsif
      # Do not fade if it's already very low.
      b >= a + margin and a <= medium and b <= high
    then
      log("Transition: crossed, no fade-out.")
      add(sa,sb)

    elsif
      # Opposite as the previous one.
      a >= b + margin and b >= medium and a <= high
    then
      log("Transition: crossed, fade-in.")
      add(sa,fade.in(sb))

    # What to do with a loud end and 
    # a quiet beginning ?
    # A good idea is to use a jingle to separate 
    # the two tracks, but that's another story.

    else
      # Otherwise, A and B are just too loud 
      # to overlap nicely, or the difference 
      # between them is too large and 
      # overlapping would completely mask one 
      # of them.
      log("No transition: just sequencing.")
      sequence([sa, sb])
    end
  end

  cross(width=width, duration=start_next, 
        conservative=conservative,
        transition,s)
end

Зберігаємо. Тепер давайте створимо Log файл. Це дуже важливо, без нього Liquidsoap в мене не хотів працювати.

mkdir /var/log/liquidsoap
nano /var/log/liquidsoap/radio.log

Зараз давайте призначимо liquidsoap користувачем для всіх наших створених файлів та папок, а також виставимо необхідні права:

chown -R liquidsoap:liquidsoap /var/log/liquidsoap
chown -R liquidsoap:liquidsoap /etc/liquidsoap
chmod u+x /etc/liquidsoap/radio.liq

Тепер створюємо папки з музикою:

mkdir /home/music/day
mkdir /home/music/night
mkdir /home/music/hit
mkdir /home/music/jingl

Завантажуємо туди музику в форматі .mp3 та створюємо плейлісти:

find /home/music/day -type f > /home/music/day/playlist.pls
find /home/music/night -type f > /home/music/night/playlist.pls
find /home/music/hit -type f > /home/music/hit/playlist.pls
find /home/music/jingl -type f > /home/music/jingl/playlist.pls

Тепер призначимо користувача liquidsoap власником папок з нашою музикою:

chown -R liquidsoap:liquidsoap /home/music

Після цього можемо запустити та протестувати нашу зв’язку:

icecast2 -c /etc/icecast2/icecast.xml
liquidsoap /etc/liquidsoap/radio.liq

Якщо ви все зробили правильно і в терміналі не було помилок, ви можете відкрити свій браузер і ввести адресу вашого сервера в адресній строці, якщо ви налаштовували все на своєму робочому комп’ютері переходьте за адресою: http://localhost:8000 там ви маєте побачити подібне:

Якщо подібного у вас не вийшло, і при запуску програми не показали жодних помилок, таке теж було в мене на практиці, дивіться, які повідомлення були відправлені в /var/log/syslog. Через пошук по “liquidsoap” ви знайдете причини.

Але я вірю, що у вас все вийшло і ви вже насолоджуєтесть прослуховуванням свого власного інтернет-радіо. Та є ще один момент яким я хочу з вами поділитись. Після перезавантаження сервера ваше радіо перестане працювати. Це відбувається тому, що liquidsoap не запускається разом із системою. Я знайшов кілька інструкцій в інтернеті як можна це змінити, але в мене на Ubuntu 20.04 вони не спрацювали, зате спрацювала схема, яку я раніш використовував на Ubuntu 18.04. Тож якщо у вас також є з цим проблема, робимо наступне. Створюємо файл:

nano /etc/init.d/liquidsoap

Далі вставляємо туди ось такий вміст:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          liquidsoap
# Required-Start:    $remote_fs $network $time
# Required-Stop:     $remote_fs $network $time
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts the liquidsoap daemon
# Description:
### END INIT INFO

user=liquidsoap
group=liquidsoap
prefix=/usr
exec_prefix=${prefix}
confdir=/etc/liquidsoap
liquidsoap=${exec_prefix}/bin/liquidsoap
rundir=/var/run/liquidsoap

# Test if $rundir exists
if [ ! -d $rundir ]; then
  mkdir -p $rundir;
  chown $user:$group $rundir
fi
case "$1" in
  stop)
    echo -n "Stopping liquidsoap channels: "
    cd $rundir
    has_channels=
    for liq in *.pid ; do
      if test $liq != '*.pid' ; then
        has_channels=1
        echo -n "$liq "
        start-stop-daemon --stop --quiet --pidfile $liq --retry 4
      fi
    done
    if test -n "$has_channels"; then
      echo "OK"
    else
      echo "no script found in $confdir"
    fi
    ;;

  start)
    echo -n "Starting liquidsoap channels: "
    cd $confdir
    has_channels=
    for liq in *.liq ; do
      if test $liq != '*.liq' ; then
        has_channels=1
        echo -n "$liq "
        start-stop-daemon --start --quiet --pidfile $rundir/${liq%.liq}.pid \
          --chuid $user:$group --exec $liquidsoap -- -d $confdir/$liq
      fi
   done
    if test -n "$has_channels"; then
      echo "OK"
    else
      echo "no script found in $confdir"
    fi
    ;;

  restart|force-reload)
    $0 stop
    $0 start
    ;;

  *)
    echo "Usage: $0 {start|stop|restart|force-reload}"
    exit 1
    ;;
esac

Зберігаємо. Виставляємо потрібні права:

chown liquidsoap:liquidsoap /etc/init.d/liquidsoap
chmod u+x /etc/init.d/liquidsoap

Після цього у нас є можливість додати Liquidsoap в автозагрузку, щоб він самостійно запускався разом із системою:

systemctl enable liquidsoap

Тепер можна перезавантажити сервер. Після старту ваша радіостанція повинна працювати.

Під час завантаження Liquidsoap буде сканувати всі файли з розширенням .liq в своїй папці /etc/liquidsoap і запускати їх, якщо вони позначені відповідним чином. Тож ви можете створити стільки радіостанцій скільки вам потрібно. І всі вони можуть мати власну музику, джингли, програми та розклад ефірів. Як на мене це дійсно вражаючі можливості!

Сьогодні я розповів вам, та лишив для себе інструкцію на майбутнє :), як встановити та базово налаштувати власну інтернет-радіостанцію на Icecast2 та Liquidsoap 1.4. Попереду ще процес тонкого налаштування: потрібно додати програми, жарти, запрограмувати графік роботи радіо, що і коли має виходити в ефір. Тож, чекайте на продовження цього матеріалу.

Дякую за увагу.

Бажаєте отримати інформацію та контакти з виставки, але не маєте можливості самостійно приїхати в Китай? звяжіться зі мною. ✌️

© Віталій Радчук. All rights reserved.
Powered by RA Web Studio.