ストリーミング配信をIP電話経由で聞く

というわけで、久々の記事になったわけですが、一回書きかけにブラウザがクラッシュしたので書き直しています。
そんなこんなで今回は、IP電話の保留音としてストリーミング配信を使う方法を書いていきます。

大まかな流れ

ストリーミング配信をいかにしてAsteriskに食わせるか、そしてその向こう側のIP電話に流すか。今回はこういった流れでやっていこうと思います。

+----------------+
| ストリーミング |
+----------------+
        || < 取得
+----------------+
|    Mplayer     |
+----------------+
        || < 流し込み
+----------------+
|  名前付パイプ  |
+----------------+
        || < 再生
+----------------+
|    Asterisk    |
+----------------+
        || < 保留音
+----------------+
|    IP電話機    |
+----------------+

下準備

今回は、ストリーミングの取得にMPlayerを使います。というのも、今後IP-TV電話機にストリーミング映像を流しこめたらなという淡い期待が持てそうです。今回は音声ストリーミングまでです。
というわけで早速MPlayerをインストールします。CentOSではyumでとってこれないのでソースから取得します。

# wget http://www4.mplayerhq.hu/MPlayer/releases/MPlayer-1.0rc2.tar.bz2
# bzip2 -dc MPlayer-1.0rc2.tar.bz2 | tar xvf -
# cd MPlayer-1.0rc2
# ./configure
# make
# make test
# make install

ストリーミングの取得

さて、MPlayerのインストールが終わったら手始めにストリーミングを聞いてみます。

mplayer http://hoge.example.com/test.pls

こんなことをすると、当然mplayerを実行したPCから音が鳴るので、案の定サーバから音が鳴りました。

パイプに流し込み

さて、ここでどうやって名前付パイプに流し込むのかというと、「-ao」オプションを使います。これはAudioOutputを何らかの出力に飛ばすことができます。また、音声を出力する際にAsteriskが再生できる形式にしておくと後々楽になります。Asteriskは8kHzモノラルのwavファイルが再生できるので、それにあわせます。
今回はこのようにしました。

# pwd
/var/lib/asterisk/moh/netstream
# mkfifo pipe.mp3  //名前付パイプを作る
# mplayer http://hoge.example.com/test.pls -srate 8000 -af channels=1 -ao pcm:file=/var/lib/asterisk/moh/netstream/pipe.mp3

拡張子がmp3になっています。これはAsteriskのmohモジュールが保留音ファイルの存在を確認する際、拡張子がmp3のものがあるかどうかを確認しているためです。ファイルがないとWARNINGが出てしまいました。

最後に、常にパイプに音声を流し込むため、以下のようなスクリプトを回しておきます。今回は/etc/init.d/にServiceとして追加し、起動時に立ち上がるようにしました。

  • netstream.sh
#!/bin/sh

while :
do
        /usr/local/bin/mplayer http://hoge.example.com/test.pls -srate 8000 -af channels=1 -ao pcm:file=/var/lib/asterisk/moh/netstream/pipe.mp3
done
#!/bin/bash

# chkconfig: 2345 35 35
# description: Asterisk Network Streaming
# processname: asterisk_netstream

start(){
    rm -f /var/lib/asterisk/moh/netstream/nohup.out
    echo -n "Starting Asterisk Network Streaming"
    /usr/bin/nohup /var/lib/asterisk/moh/netstream/netstream.sh &
    return 0
}
stop(){
    echo -n "Stop Asterisk Network Streaming"
    killall netstream.sh -9
    killall mplayer -9
    return 0
}


case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
esac

Asteriskで再生する

さて、ここで話はAsterisk側になります。Asteriskが保留音を再生するとき、以下のような流れになっています。
Asteriskでmpg123を使って再生するときの例です。

+----------------+   保留音   +----------------+
|    Asterisk    |==========> |    IP電話機    |
|                |==┐        +----------------+
+----------------+  ||
        || < 起動   || < 標準出力
+----------------+  ||
|     mpg123     |==┘
+----------------+

これはAsteriskがmpg123を起動したプロセスを見ればわかります。

# ps aux | grep mpg
root     23883  0.1  0.2   4116  2712 ?   S   15:48   0:01 mpg123 -q -s --mono -r 8000 -b 2048 -f 8192 hoge.mp3
root     23884  0.0  0.0   4116   340 ?   S   15:48   0:00 mpg123 -q -s --mono -r 8000 -b 2048 -f 8192 hoge.mp3

mpg123の「-s」オプションは、ManPageによると

  • s, --stdout

デコードしたオーディオのサンプル音を標準出力に出力します。オーディオデバイスを使った演奏は行いません。お使いのハードウェアが mpg123 でサポートされていなければ、このオプションを使わなければなりません。出力フォーマットは raw (ヘッダ無し)形式、16 ビット、ステレオの PCM オーディオデータであり、そのバイト順はホストに従います。

となっているので、容易に標準出力に出力していることがわかります。
さて、ここで問題になるのはAsteriskが起動するアプリケーションです。名前付パイプには常に音声データのみが垂れ流し状態になっているため、通常のアプリケーションで開こうとするとエラーがでます。そこで、標準出力として流し込むことができればよいというところに着目して今回はcatを使います。パイプに流し込む段階で音声形式をAsteriskに合わせておいたため、安易にcatするだけで大丈夫です。

cat pipe.mp3

保留音としての設定をする

というわけで、最後にAsteriskの設定をします。musiconhold.confとextensions.confをいじります。ダイヤル301でストリーミングを垂れ流すようにしました。

  • musiconhold.conf
[netstream]
mode=custom
directory=/var/lib/asterisk/moh/netstream
application=/bin/cat
format=slin
  • extensions.conf
exten => 301,1,Answer()
exten => 301,2,StartMusicOnHold(netstream)
exten => 301,3,Wait(3600)
exten => 301,n,Goto(301,3)
exten => 301,n,Hangup

StartMusicOnHoldだけではすぐにHangupしてしまうのでWaitでループを組んでいます。

聞いてみる

というわけで聞いてみました。IP電話機のしょぼいスピーカーから流れるチープな音声が海辺のラジオっぽくなっていたので、良い感じに風流になりました。