やりたい事
スマホの音楽(Amazon Musicなど)をBluetooth(a2dp)で受信し、Raspberry pi3のI2S-DACに接続したスピーカーで流します。
環境
- raspberry pi3
- hifiberry dac(pcm1502mk)
- アンプ・スピーカー
解説
BlueALSAを使って実現します。
BlueALSAが、bluetoothdとサウンドカード間を繋いでくれるイメージです。bluetoothdがa2dpでの接続を受け付けた際に音楽をサウンドカードに橋渡しできるように、BlueALSAのサービスをsystemdに登録します。BlueALSAの心臓にあたるbluealsaと、スマホからの音楽をサウンドカードに渡すbluealsa-aplayの2つのサービスを登録します。
とりかかろう!
1. 事前ソフトのインストール
BlueALSAが必要とするソフトをインストールします。
sudo apt-get update
sudo apt-get install libasound2-dev
sudo apt-get install dh-autoreconf
sudo apt-get install libortp-dev
sudo apt-get install bluez pi-bluetooth bluez-tools libbluetooth-dev
sudo apt-get install libusb-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
No package 'dbus-1' found のエラーが出たら、dbus-1 もインストールします。
sudo apt install git virtualenv build-essential python3-dev libdbus-glib-1-dev libgirepository1.0-dev
さらに続けます。
sudo apt-get install libsbc1 libsbc-dev
2. Bluez-Alsaのインストール
sudo git clone https://github.com/Arkq/bluez-alsa.git
cd bluez-alsa
sudo autoreconf --install
sudo mkdir build && cd build
sudo ../configure --enable-manpages --enable-rfcomm --disable-hcitop --with-alsaplugindir=/usr/lib/arm-linux-gnueabihf/alsa-lib
sudo make && sudo make install
3. Bluetoothの設定
/etc/bluetooth/main.conf の内容を次の内容でアップデートします。
[General]
Class = 0x20041C
このクラスの指定で、RasberryPiが、どういうbluetoothの機器かと言う事を指定します。この情報を周りのbluetooth機器にも伝えるので、ここでは、audioの機器であることを指定しています。
/etc/bluetooth/audio.conf を以下の中身で作ります。
[General]
Class = 0x20041C
Enable = Source,Sink,Media,Socket
4. bluealsaの設定
4.1. bluealsaの自動起動用設定ファイルの作成
systemd を使用して、bluealsaを自動起動させるため、/lib/systemd/system/bluealsa.serviceファイルを作成します。
[Unit]
Description=BluezAlsa proxy
Requires=bluetooth.service
After=bluetooth.service
[Service]
Type=simple
User=root
Group=audio
ExecStart=/usr/bin/bluealsa -p a2dp-sink
[Install]
WantedBy=multi-user.target
bluealsaは、bluetooth.serviceの起動が前提なので、
Requires=bluetooth.service
After=bluetooth.service
が必要です。
4.2. bluealsa-aplayの自動起動用の設定ファイル
[Unit]
Description=BlueAlsa-Aplay -Dhw:1,0
Requires=bluetooth.service bluealsa.service
[Service]
Type=simple
User=root
Group=audio
ExecStart=/usr/bin/bluealsa-aplay -Dhw:1,0
[Install]
WantedBy=multi-user.target
bluealsa-aplayでは、使用するサウンドカードを-Dパラメータの後に指定します。古いbluealsa-aplayだと、-Dではなく、-dでした。今は、-dの指定は、無効です。パラメータでカードを指定しない場合、pulseaudioのデフォルトカードを使おうとするようで、ログ見てると急にpulseaudioが出て来て、ハマりました。
systemdが管理するこのbluealsa-aplay@.serviceの中で、パラメータに、%Iを指定して、bluealesa-aplay -Dhw:1,0 %I
のようにして接続するbluetooth機器のアドレスをbluealsa-aplayに渡してもいいのですが、どうもわたさなくてもアドレスを拾ってくれるみたいなので、指定をやめました。
4.3. udev登録
KERNEL=="input[0-9]*", RUN+="/home/bluealsa/a2dp-autoconnect"
bluetooth機器が接続されて、uevent が送信された時、環境変数KERNELに"input[0-9]*"にマッチする文字列が設定されているのでこのudevのルールファイルが読まれ、bluetooth機器が接続された時に行われる既存の処理に加えて、RUNで指定したプログラムをudevデーモンが実行します。
udevデーモンは起動時に/usr/lib/udev/rules.d/.rulesおよび/etc/udev/rules.d/.rulesファイルからすべての規則を読み込んで解析し、メモリ内に保持するんですって。
4.4. スクリプトa2dp-connect
#!/bin/bash
# at each BT connection/disconnection start/stop the service bluealsa-aplay
function log {
sudo echo "[$(date)]: $*" >> /var/log/a2dp-autoconnect
}
# bluealsa-aplay でBTMACを指定できるようにBTMACを取得しています。
# 今回は使ってないので、下記行は無くてもOK
BTMAC=${PHYS//\"/}
if [ $ACTION = #"remove" ]
then
log "Stop Played Connection " $BTMAC
systemctl stop bluealsa-aplay@$BTMAC
elif [ $ACTION = "add" ]
then
log "Start Played Connection " $BTMAC
systemctl start bluealsa-aplay@$BTMAC
else
log "Other action " $ACTION
fi
こーひーぶれいく:udevadm monitor での環境変数チェック
最初、参考にしていたページでは、bluetooth機器アドレスをbluealsa-aplayに渡していました。そしてこのアドレスは、環境変数NAMEを使って渡されていました。それで、私も同じようにしましたが、すると、私の環境では、なんとアドレスは渡されず、スマホの名前(motorola g52j)が渡されてきました。しばらく途方に暮れたのですが、udvadm monitor -pk
を使って調べれそうな事にたどり着き、実行することでアドレスを取得できる環境変数PHYSを見つけました。結局は、アドレス指定しないことにしたのですが^^;。下記がその時のコマンド実行の様子です。
nob@music:~ $
nob@music:~ $ udevadm monitor -pk
monitor will print the received events for:
KERNEL - the kernel uevent
KERNEL[1319.510073] add
/devices/platform/soc/3f201000.serial/tty/ttyAMA0/hci0/hci0:11
(bluetooth)
ACTION=add
DEVPATH=/devices/platform/soc/3f201000.serial/tty/ttyAMA0/hci0/hci0:11
SUBSYSTEM=bluetooth
DEVTYPE=link
SEQNUM=1623
KERNEL[1322.023904] add /devices/virtual/input/input4 (input)
ACTION=add
DEVPATH=/devices/virtual/input/input4
SUBSYSTEM=input
PRODUCT=5/8/2e81/2020
NAME="moto g52j 5G (AVRCP)"
PHYS="b8:XX:XX:XX:XX:90"
PROP=0
EV=100007
KEY=2fc800 1452 0 0 0 0 10300 49e8 c00 e1680 f f8100000 10000ffc
REL=0
MODALIAS=input:b0005v0008p2E81e2020-e0,1,2,14,k71,72,73,8A,8B,A3,A5,A6,A7,A8,AB,AE,C8,C9,D0,161,164,166,16A,16C,18B,18E,18F,190,191,192,193,195,ramlsfw
SEQNUM=1624
KERNEL[1322.025135] add /devices/virtual/input/input4/event2 (input)
ACTION=add
DEVPATH=/devices/virtual/input/input4/event2
SUBSYSTEM=input
DEVNAME=/dev/input/event2
SEQNUM=1625
MAJOR=13
MINOR=66
^C
nob@music:~ $
nob@music:~ $
5. deamonの再読み込み
sudo systemctl daemon-reload
sudo systemctl enable bluealsa.service
systemd の挙動は、journalctl
で確認しましょう。
6. blueatoothデバイス接続
さあ、スマホを接続しましょう!
nob@music:~ $
nob@music:~ $ sudo bluetoothctl
Agent registered
[CHG] Controller B8:XX:XX:XX:XX:90 Pairable: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:XX:XX:XX:XX:90 Discovering: yes
[NEW] Device 6C:XX:XX:XX:XX:8A moto g52j 5G
[CHG] Device 6C:XX:XX:XX:XX:8A RSSI: -63
[bluetooth]# connect 6C:XX:XX:XX:XX:8A
Attempting to connect to 6C:XX:XX:XX:XX:8A
[CHG] Device 6C:XX:XX:XX:XX:8A Connected: yes
[CHG] Device 6C:XX:XX:XX:XX:8A Modalias: bluetooth:v0008p2E81d2020
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001105-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000110a-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001112-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001115-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001116-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000111f-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000112d-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 0000112f-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001132-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: 10000000-328e-0fbb-c642-1aa6699bdada
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: a82efa21-ae5c-3dde-9bbc-f16da7b16c5a
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: a924496e-cc7c-4dff-8a9f-9a76cc2e9d50
[CHG] Device 6C:XX:XX:XX:XX:8A UUIDs: badbadba-dbad-badb-adba-badbadbadbad
[CHG] Device 6C:XX:XX:XX:XX:8A ServicesResolved: yes
Request confirmation
[agent] Confirm passkey 044732 (yes/no): yes
[CHG] Device 6C:XX:XX:XX:XX:8A Paired: yes
Connection successful
[moto g52j 5G]# trust 6C:XX:XX:XX:XX:8A
[CHG] Device 6C:XX:XX:XX:XX:8A Trusted: yes
Changing 6C:XX:XX:XX:XX:8A trust succeeded
[moto g52j 5G]# exit
nob@music:~ $
さあ、スマホのアプリで希望の音楽を再生しましょう。
スピーカーから心地のいい音楽が流れていることでしょう!!