SimulRadio(サイマルラジオ) – MPD(music player daemon)

前回までに作成したSimulRadioは少々UIがダサいことを除けば問題なく稼働しているのですが唯一の欠点は接続、再生開始に約10秒前後を要することです。

なんとかこの待ち時間を短縮すべく再生プレーヤーにMPD(music player daemon)を導入してみました。

MPDはpc audio,raspberry pi(moode audio)などで音質、安定性とも定評のあるmusic daemonですね。
当サイトの環境では音声はpulse audioで全てmoode audioに送っているのでMPDはユーザーで起動実行しています。(systemdのmpd(pulse audio)は接続できない)
RaspberryPi3,OrangePi3上のubuntuコンテナで確認

MPDのインストール

# apt install mpd mpc ncmpcpp

インストールしたMPDはsystemdから自動起動しないようdisableしておきます。

# systemctl stop mpd
# systemctl disable mpd

mpd.conf

/etc/mpd.confから抜粋 alsaを使う場合は有効に!
raspberry piのalsaでも確認していますがmpvなどのようにalsa-pulseaudioの自動切り替えはしないのでOS(pulseaudio)の設定次第になります。
~/.config/mpd/mpd.conf

music_directory     "~/radio/music"
playlist_directory  "~/radio/playlist"
db_file             "~/.config/mpd/database"
log_file            "~/.config/mpd/mpd.log"
pid_file            "~/.config/mpd/pid"
state_file          "~/.config/mpd/state"
sticker_file        "~/.config/mpd/sticker.sql"
bind_to_address "localhost"
port            "6600"
input {
    plugin   "curl"
}
input {
    enabled  "no"
    plugin   "tidal"
}
input {
    enabled  "no"
    plugin   "qobuz"
}
decoder {
    enabled  "no"
    plugin   "hybrid_dsd"
}
audio_output {
    type     "pulse"
    name     "pulse audio"
}
#audio_output {
#    type    "alsa"
#    name    "My Sound Card"
#}

ディレクトリを作成

$ mkdir ~/radio/music && mkdir ~/radio/playlist

mpdの起動、確認

$ /usr/bin/mpd &

適当な音楽ファイルを~/radio/musicに放り込んでインストールしたncmpcppからmpdの確認をします。

$ ncmpcpp


ncmpcというクライアントソフトもありますがraspberry piではうまく接続できませんでした。
browse画面で選択するとplaylistに登録追加されます。
デフォルトではyoutubeから直接再生はできないようです。
ダウンロードしたmp4ファイルは音声のみ再生可
設定に間違いが無ければalsaまたはpulse audioから再生します。

$ ncmpc


ncmpcも動作していました。
再起動が必要だったようです。

radioの再生

$ mpc help | less


mpdクライアントのmpcにはいろいろなコマンドがあります。
この中から適当なコマンドを使ってプログラム内で実行しています。


mpdの基本はplaylistを作成してmpcから実行指示します。
mpc add urlでplaylistに登録
mpc play 再生開始
mpc stop 停止
mpc clear playlistをクリア
pythonプログラムではplaylistを書き換えて実行しています。

killall.sh

mpc stopとmpc clearを追加

#!/bin/sh
mpc stop
mpc clear
killall -q mpv
killall -q mplayer
killall -q ffplay

simul.py

SimulRadioの動作はmpvプレーヤー時と同じようにしたいと思います。
参考 simul.py

mpdの起動
simul.py起動時プログラムの最初の方でmpdが起動していなかったらmpdを起動します。

# mpd
command = ("ps ax | grep mpd | grep -v grep")
proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
if not (proc):
    subprocess.run("/usr/bin/mpd &", shell=True)

play
前回は余計なことをしてyoutube urlも実行できると書いてしまったのでyoutube再生はmpvで実行するようにしました。選択したurlをmpc addしてwww.youtube.comの文字列があったらmpvで実行します。

# selection
def play_selection():
    for i in lb.curselection():
        a = (lb.get(i))
        subprocess.run("mpc add " + (a), shell=True)
        command = ("mpc playlist | grep -oP 'www.youtube.{0,4}' | grep -v {")
        proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
        proc = proc.strip()
        if proc == 'www.youtube.com':
            command = ((("mpv ") + (a)) + (" &"))
        else:
            command = ("mpc play")
        subprocess.run(command, shell=True)

ON AIR
ON AIR情報はmpc playlistから取得しています。停止時はkillall.shでmpc clearしてplaylistから削除

# ON AIR
def button7_click():
    command = ("mpc playlist | grep -oP 'JCB.{0,3}' | grep -v {")
    proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
    if not (proc):
        command = ("mpc playlist | grep -oP 'jp/3.{0,4}' | grep -v {")
        proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
        # CSRA NHK
        if not (proc):
            command = ("mpc playlist")
            proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
            proc = proc.strip()
            if proc == 'https://nhkradiohkfm-i.akamaihd.net/hls/live/512076/1-fm/1-fm-01.m3u8':
                proc = 'NHK FM 仙台'
            if proc == 'https://nhkradiohkr1-i.akamaihd.net/hls/live/512075/1-r1/1-r1-01.m3u8':
                proc = 'NHK R1 仙台'
            if not (proc): 
                command = ("ps ax | grep mpv | grep -v grep | awk '{print $NF}'")
                proc = (subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]).decode('utf-8')
                proc = proc.strip()
                if proc == '-':
                    proc = 'Radiko playing'
                else:
                    proc = 'No Station'
            messagebox.showinfo('ON AIR', proc)
        # ListenRadio
        else:
            proc = proc.strip()
            proc = proc[3:]
            with open("/home/pi/radio/CSRA/ListenRadio", 'r') as f:
                for id in f:
                    if re.search((proc), id):
                        messagebox.showinfo('ON AIR', id)
    # JCB
    else:
        proc = proc.strip()
        with open("/home/pi/radio/JCBA/JCB", 'r') as f:
            for id in f:
                if re.search((proc), id):
                    messagebox.showinfo('ON AIR', id)

simul.py実行

$ ~/bin/simul.py &

さて肝心のmpdの成果ですがかなりの改善を得ることができました。
特にListenRadioではplayとほぼ同時に再生を開始します。

ubuntuコンテナからも同様で
JCBA 3〜4秒
mms: 2〜3秒
接続再生開始します。
http(https)はmpdが圧倒的に早そうです。
これでストレス無く聴取できそうです。あとはラジオ局間の音量のばらつきが少なければいいのですが…
UI、操作類は一切変わっていないはずです。