ブログ

ブラウザを使った音楽再生の遠隔制御

カテゴリ: メガネな開発, Ajax — iwata @ 2006.11.21(火) 4:31:50

先日,といっても 1ヵ月ほど前ですが,ファイルサーバにUSB音源をセットアップした,ということを 一行ほど 書きました.それ以来事務所は (安物スピーカのショボい音ながら) 音楽の流れる空間になっています.

音楽の再生には,Linux で定番の mpg123 を使っていますが,毎回コマンドラインでファイルやオプションを指定したりするのはメンドイ,というのが正直なところ.

さて,現在 Ajax についても勉強中でありますが,せっかくなのでこれを使わない手はありません.ということで,ブラウザからサーバの mp3 再生を制御する仕組みなんぞを小一時間考え,テキトーに実装してみました.

概要は,次の図のような感じです.最低限の機能として,再生,一時停止,曲送り,停止(終了)のみを用意しました.

概要.

概要.

動作の概要: 全体

ブラウザ上の制御ボタンをクリックすることで,割り当てられた onclick イベントハンドラ (JavaScript) が実行されます. このスクリプト内でサーバへリクエスト (XMLHttpRequest) を送信し,呼ばれた CGI の内部で mpg123 を制御,CGI 終了時にリクエスト送信元の JavaScript へレスポンスを送信する,今回はそんな方法をとってみました.なお,CGI には Perl を使っていることをつけ加えておきます.

動作の概要: JavaScript

どのイベントハンドラも,ただ XMLHttpRequest を投げているだけなので,書くまでもありません.

動作の概要: CGI

上図における PLAY,STOP,NEXT,EXIT の動作の概要を,以下に書きます.

PLAY

mpg123 のプロセスが存在しない場合は mpg123 を実行します.プロセスが存在し,かつ停止状態の場合は,同プロセスを再開させます.

STOP

mpg123 のプロセスが存在し,かつ動作している場合,同プロセスを停止させます.

NEXT

mpg123 は Ctrl-C を押すことにより、いつでも中断させることができます。複数のファイルの再生中であれば、現在のファイルの再生が止まり、次のファイルの再生 が始まります。

Manpage of mpg123 より

このことから,mpg123 のプロセスが存在かつ動作している場合に,同プロセスへ割り込みを行うことで,実現できそうです.

EXIT

mpg123 のプロセスが存在する場合,同プロセスを終了させます.

実装にあたってのメモ
mpg123 の実行

CGI プログラム内で mpg123 をシステムコマンドとして実行します.(引数として再生したいファイル名を指定しておく必要があります.)

今回は,mp3 ファイルがサーバの所定のディレクトリに存在しているものとし,これを静的に指定しています.

プロセスの状態の切り換え

kill コマンドをシステムコマンドとして実行します.

プロセスを停止させる場合は -STOP,再開させるには -CONT,割り込みを行うには -INT,終了させるには -KILL を第 1 引数にとります.

第 2 引数には,状態を切り換えたいプロセスの ID を指定する必要があります.ここでは mpg123 のプロセス ID となるわけです.

プロセスの取得

Perl 内でシステムコマンドを実行すると,その出力・結果が文字列で返ることを利用します.

ps -le | grep mpg123 をシステムコマンドとして実行し,この出力を変数 ($p とします)に格納しておきます.$p が空ならば,その時点で mpg123 のプロセスは存在していないことになります.存在している場合には,

0 S  0  2524  2516  1  75   0 -   465 ?      pts/2    00:00:51 mpg123

のような文字列が返ります.左から 2項目目がプロセスの状態,4項目目がプロセス ID となります.これらの項目を抜き出すには,$p をパタンマッチさせるといいでしょう (というか他の方法を知りません).

プログラム中では,次のようなサブルーチンを作っておくと楽になりそうです.このサブルーチンでは,mpg123 のプロセスの ID と状態を,ハッシュリファレンスとして返します.

sub get_process_mpg123 {
  my $ps = `ps -el | grep mpg123`;
  $ps =~ m{^s* d+ s+ (S+) s+ d+ s+ (d+) }x;
  my $p = {
    stat => $1  ||  0,
    pid => $2  ||  0  # $pid == 0 の場合,mpg123のプロセスは存在しない
  };
  return $p;
}

なお,ここで触れた ps コマンドは SVR4 系といわれるものです.BSD 系の ps では出力の書式が異なるため,それに従ったアプローチが必要となります.

プロセスの状態と mpg123 の動作状態との対応

経験上,S ならば mpg123 は再生中,T ならば停止中,となっているようです.

実装してみて...

最低限ではありますが,ブラウザから音楽再生の制御を行えるようになりました.

問題点や課題
mpg123 の実行

プログラム内で mpg123 をシステムコマンドとして実行した場合,mpg123 が終了しない,すなわち mp3 の再生が終了しない限り,次のステップへ進まないようです.(コマンドの最後に & をつけてもダメでした.そんな簡単にはいきませんね...)

現状では,プログラム終了の直前でレスポンスのための処理を行っているため,これではリクエスト送信元へレスポンスを送信できずにタイムアウトが発生してしまいます.

この点については,プロセスの分岐あたりについての調査が必要っぽいです.他の解決策もあるといいんですが...

再生ファイルの指定

現状では,プログラム内で静的に指定しています.今後はこれを,ブラウザ上でできるようにしたいものです.ついでに,ファイルのアップロードやプレイリストの作成・管理なんかも実装できれば,もっとハッピーになれそうです.

参考