Pi3でインターネットラジオ選局機能を作る
出しつくされた感があるインターネットラジオ選局ソフトですが、
せっかく Pi3 に無線 LAN と Bluetooth が標準装備された
ので、簡単なものを作ってみます。
今日は選局機能を持つサーバプログラムを作ります。
(後日スマホからアクセス可能な web サーバを作り、
UNIX ドメインソケットで通信させます。)
- コマンド
/tmp/player.sock に UNIX ドメインソケットを構築し、
コマンドを受信します。コマンドに対する応答はありません。
- play <playlist または URL>
指定されたインターネットラジオを選局し、bluetooth スピーカー
から音声を流します。
- stop
音声を停止します。
- exit
サーバプログラムを終了します。
- プログラム
久々に perl で書いてみました。
デーモン化させるため、Proc::Daemon
(libproc-daemon-perlパッケージ)をインストールしています。
また選局は mplayer を使っているので、mplayer2 パッケージを
インストールしておく必要があります。
#!/usr/bin/perl use IO::Socket::UNIX; use Proc::Daemon; # unset X parameter $ENV{"DISPLAY"} = undef; my $pidfile = "/run/lock/player.pid"; my $sockpath = "/tmp/player.sock"; my $pidmplayer = 0; if (-f $pidfile) { writelog("pid file found; already invoked?"); exit(0); } $SIG{'INT'} = \&sigint; $SIG{'TERM'} = \&sigint; unlink($sockpath); # daemonize Proc::Daemon::Init; my $server = IO::Socket::UNIX->new( Type => SOCK_STREAM(), Local => $sockpath, Listen => 1 ); # main loop while (my $conn = $server->accept()) { while (<$conn>) { s/^\s*(.*?)\s*$/$1/; next if $_ eq ""; my @s = split(/\s+/, $_); if ($s[0] eq "play") { if ($pidmplayer != 0) { kill ('TERM', $pidmplayer); $pidmplayer = 0; } $s[0] = "/usr/bin/mplayer"; my $j = join(" ", @s); $pidmplayer = fork(); if ($pidmplayer == 0) { # child process # start pulseaudio with bluetooth support `pulseaudio --start`; `echo 'power on' | sudo bluetoothctl`; `echo 'connect ZZ:YY:XX:WW:UU:VV' | sudo bluetoothctl`; `echo 'set-default-sink 1' | pacmd`; exec "$j"; } } elsif ($s[0] eq "stop") { if ($pidmplayer != 0) { kill('TERM', $pidmplayer); waitpid($pidmlayer, 0); $pidmplayer = 0; } } elsif ($s[0] eq "exit") { last processAbort; } } } processAbort: # create UNIX domain socket unlink($pidfile); # stop mplayer sub sigint { if ($pidmplayer != 0) { kill('INT', $pidmplayer); `pulseaudio -k`; $pidmplayer = 0; } exit(0); } # write PID file sub writePidFile { local ($_) = @_; open PID, ">$pidfile"; print PID $$; print PID "\n"; close PID; } # write a log sub writelog { local ($w) = @_; open LOG, ">>/tmp/player.log"; print LOG $w; print LOG "\n"; close LOG; }
bluetoothctl を使うために sudo するので pi
ユーザのようにパスワード無しで root ユーザに
なれないと動きません。
また、指定可能な文字列を制限していないので、
セキュリティに対する一種の脆弱性が存在します。
まあ、所詮家の LAN で使うものだから堅いことはなし(笑)。