2023年1月30日月曜日

Raspberry Piに2つのBluetoothスピーカーを接続してPythonで再生する

Raspberry Piに2つのBluetoothスピーカーを接続して、Pythonでその2つのスピーカーのうち1台を指定して音声ファイルを再生してみる。


環境

Raspberry Pi B+とRaspberry Pi OS。

$ lsb_release -dr
Description:    Raspbian GNU/Linux 11 (bullseye)
Release:        11
$ python3 -V
Python 3.9.2


2つのBluetoothスピーカーをRaspberry Piに接続する

今回使用するのはRaspberry Pi B+で、本体にBluetoothの機能がないので、USB接続のBluetoothアダプタ(ドングル)を2つ用意して接続する。Bluetoothアダプタが認識されているか確認しておく。

$ lsusb
Bus 001 Device 004: ID xxxx:xxxx Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 005: ID xxxx:xxxx Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
...


必要なモジュールのインストールと設定

Raspberry PiにBluetoothスピーカーをつなげると同様に、サウンドサーバとそのbluetoothモジュールをインストールし、使用するユーザ(pi)をbluetoothグループに追加しておく。

以下コマンドでモジュールのインストール。

$ sudo apt install pulseaudio pulseaudio-module-bluetooth

ユーザーをbluetoothグループに追加。

$ sudo usermod -a -G bluetooth pi
$ sudo reboot


2つのBluetoothスピーカーを接続

2つのBluetoothアダプタそれぞれにBluetoothスピーカーを接続する。基本的な接続方法はRaspberry PiにBluetoothスピーカーをつなげると同じだが、Bluetoothアダプタが2つ以上ある場合は、接続設定する前に、Bluetoothアダプタを選択しておく。bluetoothctlのlistコマンドでBluetoothアダプタの一覧が表示される(defaultが現在選択されているアダプタ)ので、selectコマンドで設定するアダプタを選択する。

$ bluetoothctl
[bluetooth]# list
Controller 11:11:11:11:11:11 raspberrypi #2 [default]
Controller 22:22:22:22:22:22 raspberrypi

以下のようにアドレスを指定して選択。

[bluetooth]# select 22:22:22:22:22:22
Controller 22:22:22:22:22:22 raspberrypi [default]

アダプタを選択したら、スピーカーを接続する。devicesコマンドで接続可能なBluetoothデバイスの一覧が表示されるので、接続するBluetoothスピーカーが一覧にあるのを確認する。

[bluetooth]# power on
[bluetooth]# scan on
[bluetooth]# devices

アドレスを指定してBluetoothスピーカーに接続する。

[bluetooth]# pair XX:XX:XX:XX:XX:XX
[bluetooth]# connect XX:XX:XX:XX:XX:XX
[bluetooth]# quit

selectコマンドでアダプタを切り替えて、もうひとつのBluetoothスピーカーも同様に接続する。


PythonでBluetoothスピーカーから音声ファイルを再生する

Pythonで音声ファイルを再生するには音声ファイルを再生するPythonコードをcron実行するのように、VLCで音声ファイルを再生する。まずは、PythonでVLCを制御するモジュールをインストール。

$ pip3 install python-vlc
$ pip3 show python-vlc
Name: python-vlc
Version: 3.0.16120
...

今回は2つのBluetoothスピーカーのうちひとつを選択して、音声ファイルを再生する。やり方としては、python-vlcでスピーカー名とそのアドレスを取得できるので、それをもとに再生するスピーカーを選択する。スピーカー名とそのアドレスは以下のように音声出力デバイス情報から取得できる。

import vlc

player = vlc.MediaPlayer()
mod = player.audio_output_device_enum()
while mod:
    mod = mod.contents
    address = mod.device.decode('utf-8').split('.')[1]
    print('--------------------')
    print('device =', mod.device)
    print('address =', address)
    print('name =', mod.description.decode('utf-8'))
    mod = mod.next

上記コードを実行すると以下のような結果が得られる。ひとつ目の内部オーディオはRaspberry Pi本体のオーディオ出力。今回は同じモデルのBluetoothスピーカーを2台使用しているので、スピーカー名は同じになる。このスピーカー名とアドレスで音声ファイルを再生するスピーカーを選択する。

device = b'alsa_output.platform-bcm2835_audio.analog-stereo'
address = platform-bcm2835_audio
name = 内部オーディオ Analog Stereo
--------------------
device = b'bluez_sink.AA_AA_AA_AA_AA_AA.a2dp_sink'
address = AA_AA_AA_AA_AA_AA
name = Speaker
--------------------
device = b'bluez_sink.BB_BB_BB_BB_BB_BB.a2dp_sink'
address = BB_BB_BB_BB_BB_BB
name = Speaker

以下のPythonスクリプトで、接続された2つのBluetoothスピーカーのうち1台を指定して音声ファイルを再生する。このスクリプトと同じディレクトリに再生する音声ファイル(ここではtest.mp3)を配置しておく。

import os
import sys
from time import sleep

import vlc

# スピーカー名とアドレスの設定
SPEAKER1 = {'name': 'Speaker', 'address': 'XX_XX_XX_XX_XX_XX'}
SPEAKER2 = {'name': 'Speaker', 'address': 'YY_YY_YY_YY_YY_YY'}
SPEAKERS = [SPEAKER1, SPEAKER2]

# 再生する音声ファイル
# スクリプトと同じディレクトリに配置する
SOUND_FILE = 'test.mp3'


def get_output_device(player, speaker):
    """指定のスピーカーを取得する"""
    speaker_name = speaker['name']
    speaker_address = speaker['address']
    mod = player.audio_output_device_enum()
    while mod:
        mod = mod.contents
        address = mod.device.decode('utf-8').split('.')[1]
        if speaker_name == mod.description.decode('utf-8') and speaker_address == address:
            return mod.device
        mod = mod.next

    return None


def play(speaker, volume):
    """指定したスピーカーで音声ファイルを再生"""
    script_dir = os.path.dirname(os.path.realpath(__file__))
    media_path = os.path.join(script_dir, SOUND_FILE)
    player = vlc.MediaPlayer(media_path)
    device = get_output_device(player, speaker)
    if device:
        player.audio_output_device_set(None, device)
        player.audio_set_volume(volume) # ボリューム設定
        player.play()

        # 再生が終わるまで実行を継続する
        sleep(10)


def main():
    # 引数としてスピーカーID(0か1)を指定する(デフォルトは0)
    speaker_id = 0
    if len(sys.argv) >= 2 and sys.argv[1] in ('0', '1'):
        speaker_id = int(sys.argv[1])

    play(SPEAKERS[speaker_id], volume=100)

if __name__ == '__main__':
    main()

2つ目のスピーカーから再生する場合は次のように実行する。

$ python3 sample.py 1


0 件のコメント:

コメントを投稿