記事

Raspberry PiをBluetoothスピーカーにして音楽を鳴らしたい人生だった

やりたいこと

スマホとRaspberry PiをBluetoothでペアリングし、スマホから流した音楽をRaspiを通してスピーカーで聴く f:id:thr3a:20150903171844p:plain

用意するもの

  • Raspi 2 rasbianでローカルの音声が鳴るようにしておく(raspi-config
  • スピーカー
  • Bluetooth対応スマホ 今回はXperia Z3 Compactを使用

手順

インストール

sudo apt-get install pulseaudio-module-bluetooth python-gobject python-gobject-2

PulseAudio設定

Bluetoothで受信した音声をオーディオ出力に受け渡すのにPulseAudioというアプリケーションを使う

Bluetoothデーモンにアクセスできるようにlpグループにpiを追加

sudo usermod -a -G lp pi

/etc/pulse/daemon.confより、以下を変更

; resample-method = speex-float-3
 resample-method = trivial

Bluetooth設定

/etc/bluetooth/audio.confより、[General]項目に以下を追加

[General]
Enable=Source,Sink,Headset,Gateway,Control,Socket,Media

次に音の出力先名を確認するために以下のコマンド実行

sudo -u pi pactl list short sinks

下記のようなリストが出てきたらこれを控えておく。例だとalsa_output.0.analog-stereoが名前になる

pi@raspberrypi ~ $ sudo -u pi pactl list short sinks
0       alsa_output.0.analog-stereo     module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED

Bluetoothが接続された時に自動的にPulseaudioと連携して音声が出力できるように設定する。適当に/home/pi/speaker.shを作成。 実行権限を与えておく(0755)

#!/bin/bash

AUDIOSINK="alsa_output.0.analog-stereo"

echo "Executing bluetooth script...|$ACTION|" >> /var/log/bluetooth_dev

ACTION=$(expr "$ACTION" : "\([a-zA-Z]\+\).*")
if [ "$ACTION" = "add" ]; then
   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 pi 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 pi 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 pi 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 pi pactl unload-module $module_id >> /var/log/bluetooth_dev
   fi
fi

Bluetoohのペアリング完了後に発火させたいので/etc/udev/rules.d/99-input.rulesに以下追記

KERNEL=="input[0-9]*", RUN+="/home/pi/speaker.sh"

最後にbluetooth-agentを自動起動してコネクションを待ち受けるサービスを/etc/init.d/bluetooth-agentとして新規作成(実行権限与えるのを忘れずに)

### 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

再生

ペアリング有効にするには以下

sudo hciconfig hci0 piscan

あとは音がなるはず、、、なんだけど10秒程度したら勝手に止まって動かなくなる。原因は不明

Sep  3 08:00:16 raspberrypi bluetoothd[2218]: Endpoint unregistered: sender=:1.37 path=/MediaEndpoint/HFPAG
Sep  3 08:00:16 raspberrypi bluetoothd[2218]: Endpoint unregistered: sender=:1.37 path=/MediaEndpoint/HFPHS
Sep  3 08:00:16 raspberrypi bluetoothd[2218]: Endpoint unregistered: sender=:1.37 path=/MediaEndpoint/A2DPSource
Sep  3 08:00:16 raspberrypi bluetoothd[2218]: Endpoint unregistered: sender=:1.37 path=/MediaEndpoint/A2DPSink