Raspberry Pi で Bluetooth レシーバー (オーディオ:A2DP) を作成するための設定方法解説
2019/6 Bluetooth のファイル転送、PAN 設定について書きました。
2020/12 RaspberryPi4 の最新セットアップ方法に更新しました。
2022/1 raspberry pi os bullseye を使用した時の補足を追加。
2023/1 ssh でデフォルト pi ユーザが使えない時の補足を追加。
2023/1 raspios_lite_arm64-2022-09-26 使用時、ログンしないと Bluetooth の音楽接続できない場合の補足を追加。
RaspberryPi で Bluetooth AUDIO (A2DP) レシーバーを作成するための設定方法が Web に載っていますが、幾つかハマったポイントがあったので、 そのポイントを解説していきます。
設定内容は、apt でパッケージを入れてペアリングするだけですが、 ペアリングして音声が再生出来るようになるまでに、 いくつかハマるポイントがあります。
OS イメージ
<https://www.raspberrypi.org/software/operating-systems/>
RaspberryPi の OS イメージは、 必ず Raspberry Pi OS を使用してください。 Raspberry Pi OS であれば、 Lite でも with desktop でも and recommended software でも OK です。
ちなみに今回使用したのは現時点で最新 2020-12-02 5.4 2022-09-26 を使用しました。
2020/3 現在、 Raspbian Buster と RaspberryPi3 Model B の組み合わせだと、A2DP 再生時の音声ノイズを改善できません。 Raspbian Stretch でも、バージョンが異なるとノイズを改善できない可能性があります。 RaspberryPi3 Model B 以外でどうか、 あるいは、RaspberryPi3 Model B の他の個体でどうかは確認できていません。
なお、RaspberryPi3 の WiFi で脆弱性が確認されているようです。
<https://pc.watch.impress.co.jp/docs/news/1237645.html>
この記事では、末尾で WiFi を無効化しているので影響はありませんが、 もしも WiFi を有効化している場合は 各自の自己責任 のもと、 注意して運用してください。
Raspberry pi 4 では、ノイズの問題はありません。
最新 OS イメージ + Raspberry pi 3 でノイズが発生するかどうかは確認していません。
sshd 有効化
これは必須ではないですが ssh で作業した方が、なにかと便利なので設定しておきます。
OS イメージを書き込んだドライブ直下に、ファイル名 ssh で空ファイルを作成します。
Raspbian から作業する場合は、次のコマンドと等価です。
$ sudo touch /boot/ssh
Raspbian から作業するには、 RaspberryPi に キーボードとディスプレイを接続する必要があるので、 OS イメージ書き込み時にファイルを作成しておいた方が良いでしょう。
これで Raspbian を起動すれば、 ssh (id: pi, password: raspberry)が利用可能です。
※デフォルトパスワードを変える、 pi アカウントを無効にするなど別途設定してください。
2023/1 追記
Bullseye からは、デフォルト user/pass が利用できなくなりました。
ssh を利用するには、次の手順で user/pass を設定しておく必要があります。
なお、Raspberry Pi Imager を利用してイメージを作成する場合は、 Raspberry Pi Imager のウィザードに従えば以下の user/pass 設定手順は不要です。
user/pass 設定
以下のコマンドで、 OS イメージ内の /boot/userconf.txt に user/pass 情報を設定します。
$ echo -n 'user:' > userconf.txt
$ echo 'password' | openssl passwd -6 -stdin >> userconf.txt
上記 user, password は適宜変更してください。
これを実行すると、 userconf.txt は次のような状態になります。
user:encrypted_password
この userconf.txt を OS イメージの /boot にコピーします。
この OS イメージを起動すると、上記で指定した user/pass で ssh が接続できます。
apt パッケージ更新
まずは apt パッケージを更新します。
$ sudo apt-get update
$ sudo apt-get upgrade
これはお決まりのパターンなんで、特に理由がない限りやっておきます。
bluetooth 関連のパッケージ追加
$ sudo apt-get install bluez pulseaudio-module-bluetooth python-gobject python-gobject-2
2023/1 追記
bullseye の場合 python-gobject python-gobject-2 は不要
このバージョンの OS イメージでは、 bluez はインストール済みですが念のため指定しておきます。
Bluetooth の設定
次のコマンドを実行します。
pi@raspberrypi:~$ sudo bluetoothctl
[NEW] Controller XX:XX:XX:XX:XX:XX raspberrypi [default]
ここで show を入力し、 Bluetooth の情報を確認します。
show
Controller XX:XX:XX:XX:XX:XX
Name: raspberrypi
Alias: raspberrypi
Class: 0x6c0000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Headset AG
UUID: Generic Attribute Profile
UUID: A/V Remote Control
UUID: Generic Access Profile
UUID: PnP Information
UUID: A/V Remote Control Target
Discovering: no
上記出力のようになると思います。
この出力には、以下がないです。
UUID: Audio Sink
これがないと A2DP で接続出来ません。
以下では、Audio Sink を出すための設定について説明します。 Audio Sink がある場合は、ペアリングまで手順を飛ばしてください。
まずは、 bluetoothctl を抜けてから以下を実行します。
sudo apt-get install pulseaudio-module-bluetooth
これはデフォルトで入っているはずですが、念のため実行しておきます。
インストール後に再起動が必要です。
次に以下のコマンドを実行します。
$ sudo pulseaudio -D
$ sudo service bluetooth restart
ここで、再度 bluetoothctl の show を実行すると、次のようになっているはずです。
[bluetooth]# show
Controller XX:XX:XX:XX:XX:XX
Name: raspberrypi4
Alias: raspberrypi4
Class: 0x000c0000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Headset AG
UUID: Generic Attribute Profile
UUID: A/V Remote Control
UUID: Generic Access Profile
UUID: PnP Information
UUID: A/V Remote Control Target
UUID: Audio Source
UUID: Audio Sink
UUID: Headset
Discovering: no
これで Audio Sink が認識されたので、 A2DP が利用できます。
sudo pulseaudio -D で安定しない場合は、以下を実行してみてください。
$ pulseaudio --start
次はペアリングです。
ペアリング方法
Bluetooth を使用したことがあれば分かると思いますが、 ペアリングは次のステップで行ないます。
- Bluetooth service 側のデバイスをペアリング登録状態にする
- Bluetooth client 側のデバイスで検索し、ペアリングする
- ペアリングを認証する
以降では、ペアリングの登録と認証手順に分けて説明します。
ペアリング登録
ペアリングを行なうには、service 側をペアリング登録状態にします。 具体的には show コマンドで表示される次の状態を変更する必要があります。
Powered: yes
Discoverable: no
Pairable: yes
それぞれの状態を設定するには、次のコマンドを使用します。
power <on/off> Set controller power
pairable <on/off> Set controller pairable mode
discoverable <on/off> Set controller discoverable mode
現状 discoverable だけ no になっているので、 今回は discoverable on だけ実行します。
[bluetooth]# discoverable on
念のため再度 show を実行し、次のようになっていることを確認します。
Powered: yes
Discoverable: yes
Pairable: yes
bullseye の場合、更に以下の実行が必要です。
[bluetooth]# default-agent
この状態で、 client 側で検索し、ペアリングします。
bullseye の場合、client 側でペアリングを開始すると、 以下のメッセージが raspberrypi 側に出力されるので、 ?????? の部分が client 側に表示されている数字と同じか確認して、 問題なければ yes を入力します。
[agent] Confirm passkey ?????? (yes/no): yes
emacs の shell-mode だと、上手く認証できないので console での操作推奨です。
クライアント側の OS によっては、 ペアリングしただけでは A2DP 接続されていない状態になります。 クライアント側で音楽再生用の接続をしてください。 この接続を行なうと、再度上記の Confirm の問合せになることがあります。
この Confirm を通さないと、一定時間で切断されることになります。
一定時間経過すると、 discoverable が自動で off になりますが、 discoverable off で明示的に off にしてください。 念のため show コマンドで discoverable の状態を確認します。
discoverable が on の状態だと新規にペアリングを登録可能なので、 そのままだとセキュリティ上問題になります。 必ず discoverable が off になっていることを確認してください。
ペアリングの認証
ペアリングすると、次のように出力されます。
[CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
[CHG] Device XX:XX:XX:XX:XX:XX Connected: no
出力を見ると Connected が yes になった後に直ぐに no になっていることが分かります。
これは、ペアリングが認証されていないため、 接続を持続できずに切断していることを示します。
そこで、次のコマンドでペアリングを認証します。
[bluetooth]# trust XX:XX:XX:XX:XX:XX
これでペアリングが認証され次のように表示されます。
[CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes
Changing XX:XX:XX:XX:XX:XX trust succeeded
この状態で再度 client 側から接続すると、接続が維持されます。
以上でペアリング完了です。
この状態になれば、リブート後も自動でペアリングされます。
audio source の確認
ペアリング完了した状態で、次のコマンドを実行してください。
$ pactl list sources short
これで次のような出力がされます。
0 lsa_output.platform-soc_audio.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
これは、 Audio のソース一覧を出力するコマンドです。 A2DP で接続すると、このリストに次のような情報が出力されると、 Web の解説ページには記載されていましたが、私の環境では表示されませんでした。
6 bluez_source.XX_XX_XX_XX_XX_XX.a2dp_source module-bluez5-device.c s16le 2ch 44100Hz RUNNING
ここでは慌てず騒がず、 client 側の Audio 出力設定を Bluetooth に切り替えて音楽を再生してから、 再度上記コマンドを実行してください。
どうでしょうか? 出力されましたか? まだ、出力されない? その人は、 client が A2DP ではなく Headset で再生されていると思われます。 client 側の設定で出力を A2DP に変更してください。
それでも駄目な場合、次のコマンドを実行してください。
$ sudo service bluetooth restart
/etc/rc.local の編集
デフォルトの起動状態では Audio Sink が有効にならないので、 Audio Sink を有効にするために /etc/rc.local に次の処理を追加します。
sleep 10 # 10 は環境によって変更する
pulseaudio -D
service bluetooth restart
2023/1 追記
raspberry pi os の raspios_lite_arm64-2022-09-26 では、上記では上手くいきませんでした。
上記の代わりに、以下を実施してください。
- 以下を実行
$ sudo systemctl --global disable pulseaudio.service pulseaudio.socket
- at をインストール
$ sudo apt-get install at
- 下記を /etc/rc.local に追加
echo "/usr/bin/pulseaudio -D --log-target=journal --exit-idle-time=-1" | at now
なお、 raspios_lite_arm64-2022-09-26 では、 ユーザがログインすると pulseaudio が起動するようになっています。
その設定を、 sudo systemctl --global disable pulseaudio.service pulseaudio.socket
で
無効化しています。
これをしておかないと、
boot 時に起動している pulseaudio とログイン時に起動される pulseaudio がバッティングして、
ログアウトすると bluetooth 接続が出来なくなってしまいます。
なお、ログイン時に pulseaudio を起動する設定に戻すには、 rc.local に追加した行を削除するのと、以下を実行してください。
$ sudo systemctl --global enable pulseaudio.service pulseaudio.socket
pulseaudio 出力先変更
pulseaudio の出力先は、次のコマンドで確認できます。
$ pactl list sinks short
0 alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
1 alsa_output.platform-soc_audio.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
デフォルトの出力先を変更する場合は、 /etc/pulse/default.pa に出力先名を設定します。
set-default-sink alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo
これでリブートすれば出力先が切り替わります。
一時的に出力先を変更する場合は、以下を実行します。
$ pactl set-default-sink 0
ここで 0 には、 pactl list sinks short
で表示されている番号を指定します。
WiFi を無効化
Bluetooth は WiFi と干渉します。 RaspberryPi3 の WiFi を有効にしていると、干渉ノイズが入ります。
干渉ノイズが気になる場合は、WiFi を無効化します。
WiFi 無効化は /boot/config.txt に次の設定を追加します。
# WiFi off dtoverlay=pi3-disable-wifi
/etc/pulse/daemon.conf の設定
2018/5/29 追記
/etc/pulse/daemon.conf に追記し、リブートさせます。
resample-method = trivial
この設定をしないと、多くの場合にノイズが発生します。
/etc/bluetooth/main.conf の設定
2018/6/7 追記
Client によっては、ペアリングできないことがあります。 その場合 /etc/bluetooth/main.conf に次を設定します。
Class = 0x240404
Amazon Fire TV とペアリングする場合、この設定が必要でした。
ボリューム (AVRCP Absolute Volume)
client 側のボリュームを変更しても、音量が変わらない場合があります。
私の環境では、ボリューム最小(ミュート)から 1 上げると最大の音量になる現象でした。
これは、 AVRCP Absolute Volume (絶対音量) というものが影響しているらしく、 この設定をオフにする必要があります。
なお、 pulseaudio ではこの問題を認識しているようなので、 将来的にはこの問題はクリアになると思います。
https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/239
windows
次のレジストリに 1 をセットしてください。
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Bluetooth\Audio\AVRCP\CT の 名前: DisableAbsoluteVolume 値: 1 (DWORD)
※再起動が必要
android
開発者オプションで絶対音量機能を off にしてください。
「To install the screen reader press control alt spce」音声出力が定期的に出力される
2022/1 追記
raspberry pi os bullseye にすると、次の英語の音声が数秒ごとに出力されます。
To install the screen reader press control alt spce
以下を実行し Raspberry Pi を再起動すると、再生されなくなります。
sudo mv /etc/xdg/autostart/piwiz.desktop /etc/xdg/autostart/piwiz.desktop.bak
参考
- https://www.raspberrypi.org/forums/viewtopic.php?t=68779
- https://qiita.com/yyano/items/802da53ad8a4a00d00e1
- https://raspberrypi.stackexchange.com/questions/118911/how-do-i-stop-the-audio-message-to-install-the-screen-reader-press-control-alt
- https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/
- https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/SystemWide/