Raspberry Pi をA2DPのsinkにして携帯やタブレットから音楽を再生する
以前の記事で、Raspberry Piをリモートスピーカーとして使用するためにpulseaudioを使った方法を紹介しました。
そこでも少し触れましたが、BluetoothのA2DPを使用すればスマートフォン等多くのクライアントから手軽に接続できるようになります。
というわけでRaspberry PiをA2DP sinkとしてセットアップしてBTスピーカーにしてみたので紹介します。
またこちらの記事のように出力はデジタルでステレオに出しているので、スマートフォンからステレオをコントロールしている感覚でなかなか悪くないです。
(参考にしたサイト)
http://www.instructables.com/id/Turn-your-Raspberry-Pi-into-a-Portable-Bluetooth-A/
準備
USBのBluetoothアダプタをRaspberry Piに接続します。
なんでもいいと思いますが、買ったのはこれです。
iBUFFALO Bluetooth USBアダプター 3.0+EDR対応 class2 ブラック BSHSBD04BK
- 出版社/メーカー: バッファロー
- 発売日: 2010/09/29
- メディア: Personal Computers
- 購入: 29人 クリック: 259回
- この商品を含むブログ (11件) を見る
% sudo apt-get install pulseaudio-module-bluetooth python-gobject python-gobject-2
pulseaudio設定
pulseaudioを使って、bluetoothで受信した音声をオーディオ出力にルーティングします。
ここでは、pulseaudioをシステムデーモンとして起動する方向で説明します。
pulseaudioを走らせるユーザー(pulse)をgroup lp に追加
% sudo usermod -a -G lp pulse
/etc/init.d/puleaudio 修正
pulseaudioの起動オプションから --disallow-load-module を削除する。
注:DISALLOW_MODULE_LOADING=1 を 0 に変えても効かないので、以下のように起動コマンドから--disallow-module-loading=$DISALLOW_MODULE_LOADINGを削除します。
(pulseaudio_start () 内) #start-stop-daemon -x $DAEMON -p $PIDFILE --start -- --system --disallow-exit --disallow-module-loading=$DISALLOW_MODULE_LOADING --daemonize --log-target=syslog --high-priority start-stop-daemon -x $DAEMON -p $PIDFILE --start -- --system --disallow-exit --daemonize --log-target=syslog --high-priority
/etc/default/pulseaudio で以下の行を変更してシステムデーモンとして起動
PULSEAUDIO_SYSTEM_START=1
/etc/pulse/system.pa に以下を追加
.ifexists module-bluetooth-discover.so load-module module-bluetooth-discover .endif
リサンプル対応
/etc/pulse/daemon.conf に以下の行を追加
resample-method = trivial
以上の設定で、pulseaudioのサービスを起動しておきます。(リブートでもOK)
pulseというユーザーでpulseaudioが起動していること確認。
% sudo service pulseaudio start Starting system PulseAudio Daemon:. % ps aux | grep pulseaudio pulse 3623 0.5 1.0 105980 4824 ? S<l 14:43 0:01 /usr/bin/pulseaudio --system --disallow-exit --daemonize --log-target=syslog --high-priority
Bluetooth設定
/etc/bluetooth/audio.conf の [General]セクション直下に以下の行を追加します。
どれが何に必要なのかいまいち分かってませんが、例えばAndroidのクライアントのバージョンによってはこれがないとダメとかあるらしいんでとりあえず全部入りで。
Enable=Source,Sink,Headset,Gateway,Control,Socket,Media
必須ではありませんが、SDPで検索したときにコンピュータではなくPortrable audio deviceとして見せたければ以下の設定をします。
/etc/bluetooth/main.conf のClassを修正
Class 0x20041c
/var/lib/bluetooth/
class 0x20041c
次に、bluetoothの接続が行われたときに自動でpulseaudioの設定をして所望の出力から音を出すための設定をします。
まず /usr/lib/udev/bluetooth というスクリプトを以下の内容で作成し、実行パーミッションを付加します。
(オリジナルはここでしょうか?)
内容は、module-loopbackというpulseaudioのモジュールをロードし、bluezのデバイスから出力デバイスにルーティングしてやるというものです。
繰り返しますが、pulseaudioをシステムデーモンとしてpulseというユーザーで実行する前提です。
別ユーザーでpulseaudioを走らせる場合は、下記スクリプト内でpactlの実行ユーザーをpulseaudioを実行させるユーザーに変更してください。
また AUDIOSINK= の行は sudo -u pulse pactl list short sinks で得られるリストから適切なものを選んで設定してください。
ここでは前回紹介したUSBオーディオデバイスに出力する設定です。
#!/bin/bash #change if you don't use default analog audio out. #AUDIOSINK="alsa_output.platform-bcm2835_AUD0.0.analog-stereo" AUDIOSINK="alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-stereo" echo "Executing bluetooth script...|$ACTION|" >> /var/log/bluetooth_dev ACTION=$(expr "$ACTION" : "\([a-zA-Z]\+\).*") if [ "$ACTION" = "add" ]; then # set volume level here, if necessary # amixer set Master 100% # pacmd set-sink-volume 0 65537 for dev in $(find /sys/devices/virtual/input/ -name input*); do if [ -f "$dev/name" ]; then mac=$(cat "$dev/name" | sed 's/:/_/g') bluez_dev=bluez_source.$mac sleep 1 CONFIRM=`sudo -u pulse pactl list short | grep $bluez_dev` if [ ! -z "$CONFIRM" ]; then echo "Setting bluez_source to: $bluez_dev" >> /var/log/bluetooth_dev echo pactl load-module module-loopback source=$bluez_dev sink=$AUDIOSINK rate=44100 adjust_time=0 >> /var/log/bluetooth_dev sudo -u pulse pactl load-module module-loopback source=$bluez_dev sink=$AUDIOSINK rate=44100 adjust_time=0 >> /var/log/bluetooth_dev fi fi done fi if [ "$ACTION" = "remove" ]; then CONFIRM=`sudo -u pulse pactl list short | grep 'module-loopback\ssource=bluez_source'` if [ ! -z "$CONFIRM" ]; then module_id=`echo $CONFIRM | sed 's/\s.*//'` echo pactl unload-module $module_id >> /var/log/bluetooth_dev sudo -u pulse pactl unload-module $module_id >> /var/log/bluetooth_dev fi fi
そしてこのスクリプトをbluetoothのコネクションが確立したときに自動で実行する設定を行います。
/etc/udev/rules.d/99-input.rules に以下の行を追加
KERNEL=="input[0-9]*", RUN+="/usr/lib/udev/bluetooth"
最後にbluetooth-agentを自動起動してコネクションを待ち受けるサービスを /etc/init.d に作成します。
/etc/init.d/bluetooth-agent (新規、パーミッション0755)
### BEGIN INIT INFO # Provides: bluetooth-agent # Required-Start: $remote_fs $syslog bluetooth pulseaudio # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Makes Bluetooth discoverable and connectable to 0000 # Description: Start Bluetooth-Agent at boot time. ### END INIT INFO #! /bin/sh # /etc/init.d/bluetooth-agent USER=root HOME=/root export USER HOME case "$1" in start) #echo "setting bluetooth discoverable" #sudo hciconfig hci0 piscan sudo hciconfig hci0 pscan start-stop-daemon -S -x /usr/bin/bluetooth-agent -b -- 0000 echo "bluetooth-agent startet pw: 0000" ;; stop) echo "Stopping bluetooth-agent" start-stop-daemon -K -x /usr/bin/bluetooth-agent ;; *) echo "Usage: /etc/init.d/bluetooth-agent {start|stop}" exit 1 ;; esac exit 0
% sudo update-rc.d bluetooth-agent defaults
ここで bluetooth サービスを再起動(パッケージインストールしてから一度もリブートしてなければ起動してないかもしれませんが)& bluetooth-agent サービスを起動します
% sudo service bluetooth restart Stopping bluetooth: rfcomm /usr/sbin/bluetoothd. Starting bluetooth: bluetoothd rfcomm. % sudo service bluetooth-agent start bluetooth-agent startet pw: 0000
接続
さていよいよ接続してみます。
ペアリングする時は、inquiry scanを有効にします。
$ sudo hciconfig hci0 piscan
この状態でスマートフォン等から検索すると発見できるはずなので、ペアリングします。
ペアリングできたらinquiry scanは無効にしておきます。
$ sudo hciconfig hci0 pscan
これでコネクトできているはずなので、携帯のオーディオプレイヤーなどで音楽を再生してみてください。Have Fun!
(補足)
参考までに、コネクションが確立している状態のpulseaudioのlistは以下のようになっています。
USBオーディオを出力にしているので全く同じにはならないかもしれませんが、ポイントはBluetoothのコネクションにより bluez_source.
% sudo -u pulse pactl list short 0 module-alsa-card device_id="1" name="usb-0d8c_USB_Sound_Device-00-Device" card_name="alsa_card.usb-0d8c_USB_Sound_Device-00-Device" namereg_fail=false tsched=yes fixed_latency_range=no ignore_dB=no deferred_volume=yes card_properties="module-udev-detect.discovered=1" 1 module-alsa-card device_id="0" name="platform-bcm2835_AUD0.0" card_name="alsa_card.platform-bcm2835_AUD0.0" namereg_fail=false tsched=yes fixed_latency_range=no ignore_dB=no deferred_volume=yes card_properties="module-udev-detect.discovered=1" 2 module-udev-detect 3 module-native-protocol-unix 4 module-stream-restore 5 module-device-restore 6 module-default-device-restore 7 module-dbus-protocol access=local 8 module-rescue-streams 9 module-always-sink 10 module-suspend-on-idle 11 module-position-event-sounds 12 module-bluetooth-discover 18 module-bluetooth-device address="58:17:0C:55:C9:4E" path="/org/bluez/3969/hci0/dev_58_17_0C_55_C9_4E" profile="a2dp_source" auto_connect=no 19 module-loopback source=bluez_source.58_17_0C_55_C9_4E sink=alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-stereo rate=44100 adjust_time=0 0 alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING 1 alsa_output.platform-bcm2835_AUD0.0.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED 0 alsa_output.usb-0d8c_USB_Sound_Device-00-Device.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz IDLE 1 alsa_input.usb-0d8c_USB_Sound_Device-00-Device.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED 2 alsa_output.platform-bcm2835_AUD0.0.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED 6 bluez_source.58_17_0C_55_C9_4E module-bluetooth-device.c s16le 2ch 44100Hz RUNNING 2 0 - module-loopback.c s16le 2ch 44100Hz 2 6 - module-loopback.c s16le 2ch 44100Hz 19 protocol-native.c pactl 0 alsa_card.usb-0d8c_USB_Sound_Device-00-Device module-alsa-card.c 1 alsa_card.platform-bcm2835_AUD0.0 module-alsa-card.c 5 bluez_card.58_17_0C_55_C9_4E module-bluetooth-device.c
まとめ
以上でRaspberry PiをBluetoothスピーカーとして仕立てることができました。
しかしBluetoothの設定はややこしく、またツールも貧弱でディストリビューションによって使える物があったりなかったりとなかなか難儀です。
ここでまとめたステップも、途中で思ったように動かない場合はこうすればよいという明確なインストラクションも書きづらいです。
一応クリアな状態から動作確認しているので大丈夫だと思いますが、もう少しなんとかならないものかと思ってしまいますね...