公開技術情報

[English] [Japanese]

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