Liquidsoap + IceCastインターネットラジオ局

液体石鹸 ハブでは、内部からのインターネット放送についてかなり多くのことが言われています。 インターネット放送の理論的な 基礎もよく書かれていますので、読むことをお勧めします。 この記事では、あまり知られていないLiquidsoap 1.0.1とユビキタスIceCast 2.3.2の束の上に構築された別のアマチュアインターネットラジオ局の組織についてお話したいと思います。 この記事は、オーディオストリームが何であるか、IceCast、Linuxコンソール、および一般的に何を受け取りたいを少なくともほぼ知っている人を対象としています。 しかし、それは初心者ユーザーによって書かれたので、私の決定は最適のタイトルさえ主張しません。



必要な要約機能



  1. 任意の期間にプレイリストを割り当てる機能
  2. オーディオストリームのソースとしてのOGG、MP3、FLACピックアップのサポート
  3. 動的構成
  4. ラジオのコンテンツの編集のしやすさ
  5. Linuxで動作する
  6. 初心者のLinuxユーザーがこのすべてをインストールして構成する機能


この機能を得るためのさまざまな方法のかなり長い試行の後、Liquidsoap + IceCastに決めました。 後者は、コンプライアンスと広範な使用(原則として、私はアナログを探すことすらしませんでした)、およびその機能的なスクリプト言語を介して利用可能な本当に驚くべき機能のためのLiquidsoapのために採用されました。 彼の前に、私は氷、氷+ ardj、AirTime、私が言及することさえできなかった何かを考えましたが、それらのすべてはどういうわけか私に合っていませんでした。 一般的に、Liquidsoapを使用することにしました。 欠点のうち、未知の状況(再起動後)での空のストリームの発行のみに気付きました-再起動によって解決されます。 残念ながら、私はその力をすべて感じることはできません-すべてのドキュメントは英語で書かれており、スムーズに行くことはできません。



設置



ためらうことなく、私はopenSUSE 12.2 x64の下でラップトップのこの奇跡をすべて取り除くことにしました。そのため、Liquidsoapの機能を研究し、それを作業マシンに転送するのが便利でした。 リポジトリにはIceCastのみが存在し、Liquidsoapを収集する必要がありました。 Debian / Ubuntu、Windows、Mac OS X、FreeBSD、およびArchLinuxのユーザーは、 公式Webサイトで既製のパッケージを入手できます。



アイスキャスト


標準のリポジトリからIceCastのインストールを実行しました。

# zypper in icecast
      
      





IceCastの構成については詳しく説明しませんが、私と一緒に回転しているものの実例を示すだけです。



/etc/icecast.xml
 <icecast> <limits> <clients>100</clients> <sources>2</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>mypass</source-password> <relay-password>mysecondpass</relay-password> <admin-user>adminuser</admin-user> <admin-password>mythirdpass</admin-password> </authentication> <hostname>localhost</hostname> <listen-socket> <port>8000</port> </listen-socket> <fileserve>1</fileserve> #_____________________________________________________________ #   .      ,          ,      .      ices     secure. <mount> <mount-name>/secure</mount-name> <hidden>1</hidden> #   -      <charset>UTF8</charset> #  </mount> #   mount' <mount> <fallback-mount>/secure</fallback-mount> #   ,    <fallback-override>1</fallback-override> #           <fallback-when-full>1</fallback-when-full> #    ,       <mount-name>/HabraRadio_192</mount-name> #  mount'. <charset>UTF8</charset> #  </mount> <mount> <fallback-mount>/secure</fallback-mount> <fallback-override>1</fallback-override> <fallback-when-full>1</fallback-when-full> <mount-name>/HabraRadio_320</mount-name> <charset>UTF8</charset> </mount> <mount> <fallback-mount>/secure</fallback-mount> <fallback-override>1</fallback-override> <fallback-when-full>1</fallback-when-full> <mount-name>/HabraRadio_vorbis_avg_128</mount-name> <charset>UTF8</charset> </mount> #_____________________________________________________________ <paths> <basedir>/usr/share/icecast</basedir> <logdir>/var/log/icecast</logdir> <webroot>/usr/share/icecast/web</webroot> <adminroot>/usr/share/icecast/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>icecast</user> <group>icecast</group> </changeowner> </security> </icecast>
      
      







液体石鹸


ダウンロード、準備:

 $ git clone https://github.com/savonet/liquidsoap-full.git liquidsoap $ cd liquidsoap $ make init $ cp PACKAGES.minimal PACKAGES
      
      





私にとっては、最小限のセットで十分ですが、他のサポートが必要な場合は、PACKAGESファイルを編集する必要があります。

プログラムの通常のコンパイルのために、次のパッケージをインストールしました。
 # zypper in make autoconf automake ocaml libao-devel libmad-devel libmp3lame-devel flac-devel libgavl-devel ocaml-camomile-devel ocaml-camlimages-devel ocaml-camomile-data libtheora-devel ocaml-findlib-devel libsamplerate-devel libtag-devel libvorbis-devel gcc-c++ ocaml-pcre-devel libtiff-devel libjpeg62-devel libXpm-devel
      
      





収集するもの:
 $ ./bootstrap $ ./configure --with-user=user --with-group=users $ make # make install
      
      





ところで、「./ configure ...」を実行した後、必要なすべての機能がアセンブルされたプログラムで利用可能になるかどうかをチェックする価値があります。 これは、「./ configure ...」の最後に表示されるテーブルを見るだけで実行できます。

すべて、「liquidsoap --version」を実行することでプログラムのパフォーマンスを確認できます。エラーはないはずです。



航空のスケジュールをご案内します



およそ次のものを取得する必要があるとします。

  1. 02:00-06:00-夜のプレイリスト
  2. 06:00-09:00-朝のプレイリスト
  3. 09:00-19:00-日のプレイリスト
  4. 午後7時-午前2時-夜のプレイリスト
  5. 月、水、金-21:00-22:00-1つのプログラム
  6. 月、水、木、金-18:00-19:00-2番目のプログラム


ファイルシステム内の場所:
 radio ├── collection |  │ ├── efir |    │ │ ├── daytime |   │ │ │ ├── jingles | ,   │ │ │ └── music | ,   │ │ ├── evening | ,  │ │ │ ├── jingles │ │ │ └── music │ │ ├── morning |  │ │ │ ├── jingles │ │ │ └── music │ │ └── night |   │ │ ├── jingles │ │ └── music │ ├── programs │ │ ├── 1_prog | 1  │ │ ├── 2_prog | 2  │ ├── promo |   │ └── security |     ├── technical | ,  └──  |   
      
      





液体石鹸の構成



完成した構成をすぐにもたらします。



./radio/technical/start_liquidsoap
 #!/usr/local/bin/liquidsoap #          #      out = output.icecast( #   icecast host = "127.0.0.1", #   port = 8000, #  user = "source", #   password = "mypass", #  name = "-", #  genre = "Rock", #    url = "http://habrahabr.ru", #  encoding = "UTF-8" ) #  telnet- set("server.telnet.bind_addr","127.0.0.1") set("server.telnet",true) # _____________________________________ #     . #    ,       ,       ,       .   ,   . #      wd = "/home/user/radio" #      pl = "#{wd}/collection" #   tech = "#{wd}/technical" #  set("log.file.path","#{tech}/liquidsoap.log") #     set("log.level", 3) #   #     promo_dir = "#{pl}/promo" #    progr_dir = "#{pl}/programs" #     ef = "#{pl}/efir" #    ni = "#{ef}/night" mo = "#{ef}/morning" da = "#{ef}/daytime" ev = "#{ef}/evening" #    mus_ni_dir = "#{ni}/music" mus_mo_dir = "#{mo}/music" mus_da_dir = "#{da}/music" mus_ev_dir = "#{ev}/music" #    jin_ni_dir = "#{ni}/jingles" jin_mo_dir = "#{mo}/jingles" jin_da_dir = "#{da}/jingles" jin_ev_dir = "#{ev}/jingles" #   .   -      ,   -    . 1_prog_pl = "#{progr_dir}/1_prog.pl" 2_prog_pl = "#{progr_dir}/2_prog.pl" # _____________________________________ #    "source",     . #   "reload"    360     ,  . #  ,   ,  <code>mode = "normal"</code>     . #  , , ,  mus_ni = playlist (reload = 360, "#{mus_ni_dir}") mus_mo = playlist (reload = 360, "#{mus_mo_dir}") mus_da = playlist (reload = 360, "#{mus_da_dir}") mus_ev = playlist (reload = 360, "#{mus_ev_dir}") jin_ni = playlist (reload = 360, "#{jin_ni_dir}") jin_mo = playlist (reload = 360, "#{jin_mo_dir}") jin_da = playlist (reload = 360, "#{jin_da_dir}") jin_ev = playlist (reload = 360, "#{jin_ev_dir}") promo = playlist (reload = 360, "#{promo_dir}") 1_prog = playlist (reload = 360, "#{1_prog_pl}", mode = "normal") 2_prog = playlist (reload = 360, "#{2_prog_pl}", mode = "normal") # _____________________________________ #  4 ,    #   ins_ni = rotate (weights = [2, 1], [jin_ni, promo]) ins_mo = rotate (weights = [2, 1], [jin_mo, promo]) ins_da = rotate (weights = [2, 1], [jin_da, promo]) ins_ev = rotate (weights = [2, 1], [jin_ev, promo]) #     ni = rotate (weights = [3, 1], [mus_ni, ins_ni]) mo = rotate (weights = [3, 1], [mus_mo, ins_mo]) da = rotate (weights = [3, 1], [mus_da, ins_da]) ev = rotate (weights = [3, 1], [mus_ev, ins_ev]) #_______________________________________________________________________ #    radio = switch (track_sensitive = true, [ ({ (1w21h - 1w22h) or (3w21h - 3w22h) or (5w21h - 5w22h)}, 1_prog), ({ (1w18h - 1w19h) or (3w18h - 3w19h) or (4w18h - 4w19h) or (5w18h - 5w19h)}, 2_prog), ({ 2h - 6h }, ni), ({ 6h - 9h }, mo), ({ 9h - 19h }, da), ({ 19h - 2h }, ev) ]) #_______________________________________________________________________ #  crossfade radio = crossfade(start_next=1., fade_out=1., fade_in=1., radio) # , ,      out( %vorbis.abr(samplerate = 44100, channels = 2, bitrate = 128, max_bitrate = 192, min_bitrate = 96), description = "Average vorbis 96-128-192 Kbps", mount = "HabraRadio_vorbis_avg_128", mksafe(radio) ) out( %mp3(bitrate = 320, id3v2 = true), description = "MP3 320 Kbps", mount = "HabraRadio_320", mksafe(radio) ) out( %mp3(bitrate = 192, id3v2 = true), description = "MP3 192 Kbps", mount = "HabraRadio_192", mksafe(radio) )
      
      







いくつかのコメント:

1)これらの行:
 wd = "/home/user/radio" pl = "#{wd}/collection" ef = "#{pl}/efir" ni = "#{ef}/night" mus_ni_dir = "#{ni}/music" mus_ni = playlist (reload = 360, "#{mus_ni_dir}")
      
      





かなりうまく置き換えることができます
 mus_ni = playlist (reload = 360, "/home/user/radio/collection/efir/night/music")
      
      





あなたには何もありません-Liquidsoapは#{wd}の代わりにwdの値を単純に置き換えます。



2)挿入を実装した場所には、次の行がありました。

 ins_ni = rotate (weights = [2, 1], [jin_ni, promo]) ni = rotate (weights = [3, 1], [mus_ni, ins_ni])
      
      





rotate()



-キューを調整できます

weights = [2, 1], [jin_ni, promo]



-jin_niから2トラックを繰り返した後、jin_niから2トラック、次にpromoから1トラックを取得することを示します。

weights = [3, 1], [mus_ni, ins_ni]



-mus_niから3トラック、次に1行前に判明した既に混合されたプレイリスト(ins_ni)から1トラックを取得することを示します。



3)ブロードキャストスケジュールを構成するとき、次の行を使用しました。
 radio = switch (track_sensitive = true, [ ({ (1w21h - 1w22h) or (3w21h - 3w22h) or (5w21h - 5w22h)}, 1_prog), ({ (1w18h - 1w19h) or (3w18h - 3w19h) or (4w18h - 4w19h) or (5w18h - 5w19h)}, 2_prog), ({ 2h - 6h }, ni), ({ 6h - 9h }, mo), ({ 9h - 19h }, da), ({ 19h - 2h }, ev) ])
      
      







switch()



-指定された時間にオーディオソースを切り替えます。

track_sensitive = true



アクティブなプレイリストの有効期限が切れていても、現在のトラックを中断しないようにします。 つまり 夜のトラックが05:59に開始した場合、それが終了するまで、朝のプレイリストは有効になりません。

({ (1w21h - 1w22h) or (3w21h - 3w22h) or (5w21h - 5w22h)}, 1_prog),



-月曜日、水曜日、金曜日の21〜22時間はソース1_progを再生します。

私が理解しているように、上にあるswitch()リストのこれらの行は最も高い優先度を持っています。



ラジオ番組のプレイリストを作成する



原理は簡単です。prog_1フォルダーには、ラジオホストの音声が記録される「01_ProgName」という形式のラジオブロードキャストファイルがあります。 プレイリストの形式は次のとおりです。



01_ProgName

音楽152

02_ProgName

音楽241

03_ProgName

音楽937

...



このようなプレイリスト用のジェネレータをbashで作成する方が正しいと思いますが、最近Pythonにたどり着いたので、それについてホイップしました。



./radio/technical/generatorProg1.py
 #!/usr/bin/env python2 # -*- coding: utf-8 -*- import os import random finalPaylist = '/home/user/radio/collection/programs/1_prog.pl' music = '/home/user/radio/collection/efir/evening/music/' show = '/home/user/radio/collection/programs/1_prog/' myShow = sorted(os.listdir(show)) myMusic = os.listdir(music) listOfTracks = [] def getRandomTrack(list): i = 0 buf = random.choice(myMusic) while (buf in list) & (not i == 100): i += 1 buf = random.choice(myMusic) return buf for i in range(60): if not i%2: try: listOfTracks.append(show + myShow[i/2]) except : listOfTracks.append(music + getRandomTrack(listOfTracks)) else: listOfTracks.append(music + getRandomTrack(listOfTracks)) myFile = open(finalPaylist, 'w') for i in range(len(listOfTracks)): myFile.write(listOfTracks[i]+'\n')
      
      





その結果、ラジオファイルがなくても、少なくとも1時間の放送をカバーするプレイリストが作成されます。 主なことは、このプレイリストを非ランダムモードで選択することを忘れないことです。 さて、2番目のプログラムでは、プレイリストを生成する価値もあります。



最後の仕上げ



crontabプレイリスト生成を配置します。



crontab -e
 0 19 * * * /home/user/radio/technical/generatorProg1.py 0 16 * * * /home/user/radio/technical/generatorProg2.py
      
      





KDE自動実行に数行を追加します。



/home/user/.kde4/Autostart/start_liquidsoap.sh
 #!/bin/sh cp /home/user/radio/technical/liquidsoap.log /home/user/radio/technical/liquidsoap_backup.log cat /dev/null > /home/user/radio/technical/liquidsoap.log liquidsoap /home/user/radio/technical/start_liquidsoap
      
      





IceCastの自動起動も痛くない

 /etc/init.d/icecast start chkconfig --add icecast
      
      





そして、重要なのは最後になりましたが、NTPを設定する必要があります-ここでの多くは、正しく設定された時間に依存します。 YaSTで設定しました。



結論として



これで、このラジオは正常に動作し、ファイルはWindowsから責任者によってリモートで追加されます。これは、openVPN + Sambaバンドルを使用して可能になり、プログラムが再生され、ログが書き込まれます。 将来的には、いくつかの機能が計画されています:その中には、毎時間の始めにさまざまな挿入を再生する、プレイリストのランダム化を実装する、オンエアでのリモート会議通話、すべてとすべてを組み合わせる、最もフォールトトレラントを設定する、落とし穴を検索するなどがあります。 一般的に、Liquidsoapを扱うことは喜びです。 すべての人に良い音楽。



UPD: ミラーからのサプリメント



UPD 2:クロスフェード後の沈黙を回避するには、クロスフェードの前に行を追加します。
 radio = mksafe(radio)
      
      





このソリューションのkvapsに感謝します。



All Articles