Volumio2 Bluetoothプラグイン修正の詳細

2021年9月18日土曜日

Volumio

t f B! P L

このページではVolumio2 Bluetoothプラグインでインストールについて説明したBluetooth Managerプラグインについて、以前のプラグインから今回動作させるために行った修正を中心に忘備録を兼ねて記載します。また異なるVolumioのバージョン上でプラグインが動作しない場合の参考情報となるかもしれません。

Bluetooth Manager アクティブ を確認

プラグイン関連ファイル

Bluetooth Managerプラグイン関連ファイルは以下です。このうち修正を加えたbluetooth_controller.zipとwww3.zipを対象に説明します。なお、便宜上プラグインをインストールしたマシンのファイルシステム上からの位置を用いて説明します。

インストール スクリプト

プラグインをインストールした後であればインストール スクリプトは/data/plugins/audio_interface/bluetooth_controller/install.shにあります。

volumio@volumio:~$ cat /data/plugins/audio_interface/bluetooth_controller/install.sh
#!/bin/bash

echo "Installing Build Enviroment"
sudo cat > /etc/apt/sources.list.d/raspbian.list <<EOC
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
EOC
sudo apt-get update
sudo apt-get install -y binutils libtool libstdc++-4.9-dev gcc-4.9 gcc g++-4.9 g++ dpkg-dev

echo "Installing Bluetooth Dependencies"
{ echo 'Yes, do as I say!'; yes Y; } | sudo apt-get install autoconf bluez pi-bluetooth bluez-tools libbluetooth-dev libglib2.0-dev libsbc-dev

echo "Cloning Bluez-Alsa repo"
cd /tmp
git clone -b v3.1.0 https://github.com/Arkq/bluez-alsa.git

echo "Building Bluez-Alsa"
cd bluez-alsa
autoreconf --install
mkdir build && cd build
../configure --disable-hcitop --with-alsaplugindir=/usr/lib/arm-linux-gnueabihf/alsa-lib
make

echo "Installing Bluez-Alsa"
sudo make install

cat > /lib/systemd/system/bluezalsa.service <<EOC
[Unit]
Description=BluezAlsa proxy
Requires=bluetooth.service
After=bluetooth.service
[Service]
Type=simple
User=root
Group=audio
ExecStart=/usr/bin/bluealsa --a2dp-force-audio-cd
[Install]
WantedBy=multi-user.target
EOC

mpd_conf_tmpl='/volumio/app/plugins/music_service/mpd/mpd.conf.tmpl'
sudo mv $mpd_conf_tmpl ${mpd_conf_tmpl}.bak
{ sed -rz 's/(\# bluealsa Output \(begin\) \#+).*(\#+ bluealsa Output \(end\) \#\n)//g' ${mpd_conf_tmpl}.bak; \
cat << EOC
# bluealsa Output (begin) #####################################################
audio_output {
        type "alsa"
        name "bluealsa"
        device "bluealsa"
        mixer_type "software"
}
####################################################### bluealsa Output (end) #
EOC
} > $mpd_conf_tmpl

sudo systemctl daemon-reload
sudo systemctl enable bluezalsa.service

#requred to end the plugin install
echo "plugininstallend"

ビルド環境の導入

インストールスクリプトの中でBluetooth機能をVolumio2に導入するためにBluez-Alsaというプロジェクトをソースからビルドするのですが、そのためにビルド環境を導入する必要があります。

Volumio2のソフトウェアパッケージの参照先は/etc/apt/sources.listによると以下のようになっています。

volumio@volumio:~$ cat /etc/apt/sources.list
deb http://archive.volumio.org/raspbian/ jessie main contrib non-free rpi
deb-src http://archive.volumio.org/raspbian/ jessie main contrib non-free rpi

ところが上記の参照先のみの場合どうしてもうまくBluez-Alsaをコンパイルできるビルド環境を準備することが出来ませんでした。

したがって強引にもともとのRaspberry Piのソフトウェアパッケージの参照先を/etc/apt/sources.list.d/raspbian.listに加えて認識させるようにしました。それがインストールスクリプトの以下の部分です。

sudo cat > /etc/apt/sources.list.d/raspbian.list <<EOC
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi
EOC

そのうえで以下のGCC 4.9関連のパッケージを導入します。

sudo apt-get update
sudo apt-get install -y binutils libtool libstdc++-4.9-dev gcc-4.9 gcc g++-4.9 g++ dpkg-dev

またBluez-Alsaのコンパイルに必要なライブラリ群をパッケージでインストールする必要があります。-yオプションでもスキップできないプロンプトが出る部分に対応した自動応答を仕込んであります

{ echo 'Yes, do as I say!'; yes Y; } | sudo apt-get install autoconf bluez pi-bluetooth bluez-tools libbluetooth-dev libglib2.0-dev libsbc-dev

Volumio2 Bluetoothプラグインのインストール手順冒頭で「強引にビルド環境を導入」とあるのは以上の部分を意味します。


Bluez-Alsaのビルド インストール

ここまでのビルド環境が出来てしまえば、Bluez-Alsaはすんなりビルドに成功するのでインストールします。

echo "Cloning Bluez-Alsa repo"
cd /tmp
git clone -b v3.1.0 https://github.com/Arkq/bluez-alsa.git

echo "Building Bluez-Alsa"
cd bluez-alsa
autoreconf --install
mkdir build && cd build
../configure --disable-hcitop --with-alsaplugindir=/usr/lib/arm-linux-gnueabihf/alsa-lib
make

echo "Installing Bluez-Alsa"
sudo make install

bluezalsaサービスの設定

bluezalsaサービスの設定については/lib/systemd/system/bluezalsa.serviceに記述しますが、従来のBluetooth Managerプラグインからの変更は以下の点のみです。

    ExecStart=/usr/bin/bluealsa --disable-hfp # 修正前
    ExecStart=/usr/bin/bluealsa --a2dp-force-audio-cd # 修正後

mpd.confの設定

従来のBluetooth Managerプラグインでは接続するBluetoothレシーバデバイスが変更されるたびに/etc/mpd.confにBluetoothのMACアドレス情報を含めて書き換えが発生していましたが、あまり好ましい方式ではないので、大元のmpd.conf.tmplに反映、かつMACアドレスの記述が必要ない方式に変更しました。

具体的には/volumio/app/plugins/music_service/mpd/mpd.conf.tmplに以下の設定を追加しておきます。

audio_output {
        type "alsa"
        name "bluealsa"
        device "bluealsa"
        mixer_type "software"
}

このようにしておけばVolumio2側で出力デバイスの設定が更新されるたびにこのテンプレートから/etc/mpd.confに反映されるので、Bluetooth出力の設定は常に維持されることになります。

またネット上には上記設定を行った上で別途 ~/.asoundrc にBluetoothレシーバデバイスのMACアドレスを含めた設定を記述する例がありましたが、特にMACアドレス記述を必要とせずbluetoothctlで接続したBluetoothレシーバデバイスからオーディオ出力されるようです。

Node.js環境

Bluetooth ManagerプラグインのNode.js環境は/data/plugins/audio_interface/bluetooth_controller/node_modulesに展開されます。従来配布されていたbluetooth_controller.zipではNode.jsの一部のモジュールでエラーが発生して実行不可能となっていたため、最新のイメージの環境に合うようにアップデートを行い、bluetooth_controller.zipを作成しなおしました。


Node.jsモジュールのエラー発生個所確認

Bluetooth Managerプラグインの設定画面でEnable Pluginをクリックした際にエラーが表示される場合は、以下のコマンドでエラー発生個所を特定します。

$ sudo journalctl -b | less

udev

最新のVolumio2環境に対応するudevの実行イメージがBluetooth ManagerプラグインのNode.js環境になくエラーが発生していました。幸い、Volumio2本体のNode.js環境に実行可能なudev環境がありましたので、それをそのままbluetooth_controller以下に持ってきて対応しました。

$ cd /data/plugins/audio_interface/bluetooth_controller/node_modules/udev/
$ cp -rp /volumio/node_modules/udev/build/node-v57-linux-arm .

ptyw.js

ptyw.jsは以下のようにStack traceエラーを起こしていました。

 error: Stack trace: Error: The module '/data/plugins/audio_interface/bluetooth_controller/node_modules/ptyw.js/build/Release/pty.node'

ptyw.jsはVolumio2本体のNode.js環境には存在しなかったので新規にインストールしてエラーを起こしているptyw.jsフォルダと取り替えました。

$ npm i ptyw.js

> ptyw.js@0.4.1 install /home/volumio/node_modules/ptyw.js
> node-gyp rebuild

make: Entering directory '/home/volumio/node_modules/ptyw.js/build'
  CXX(target) Release/obj.target/pty/src/unix/pty.o
  SOLINK_MODULE(target) Release/obj.target/pty.node
  COPY Release/pty.node
make: Leaving directory '/home/volumio/node_modules/ptyw.js/build'
npm WARN saveError ENOENT: no such file or directory, open '/home/volumio/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/home/volumio/package.json'
npm WARN volumio No description
npm WARN volumio No repository field.
npm WARN volumio No README data
npm WARN volumio No license field.

+ ptyw.js@0.4.1
added 3 packages in 10.878s
$ cd /data/plugins/audio_interface/bluetooth_controller/node_modules/
$ rm -rf ptyw.js
$ cp -r /home/volumio/node_modules/ptyw.js .

bluezalsaサービスの動作確認

Node.js環境で問題がなくなると、bluezalsaサービスの正常起動が確認できるようになります。コマンドからは以下のように確認します。

$  systemctl status bluezalsa
● bluezalsa.service - BluezAlsa proxy
   Loaded: loaded (/lib/systemd/system/bluezalsa.service; enabled)
   Active: active (running) since Mon 2021-09-xx xx:xx:xx UTC; xxs ago
 Main PID: xxx (bluealsa)
   CGroup: /system.slice/bluezalsa.service
           └─xxx /usr/bin/bluealsa --a2dp-force-audio-cd

index.jsの修正

/etc/mpd.confの更新方式の変更に伴い、Bluetooth Devicesの接続時に/etc/mpd.confを直接更新する手続きは不要になったので該当部分を無効化しました。

    BluetoothController.prototype.onStart = function () {
        // 前略
        // 以下を無効化
        //self.commandRouter.executeOnPlugin('music_service', 'mpd', 'registerConfigCallback', { type: 'audio_interface', plugin: 'bluetooth_controller', data: 'getMPDConfigString' });
        // 後略
    }
    BluetoothController.prototype.updateMPD = function () {
        // 以下を無効化
        /*
        var result = this.commandRouter.executeOnPlugin('music_service', 'mpd', 'createMPDFile', function (error) {
            if (error)
                this.commandRouter.pushToastMessage('Error', error);
        });
        */
    };
}

Volumio3 UI対応 (Contemporaryタイプ)

従来のBluetooth Managerプラグインにはbluetooth_controller.zipとui.zipがセットになっており、UIに関してはClassicタイプのみがサポートされていました。

bluetooth_controller.zipをドラッグ&ドロップしてインストールする際はClassicに戻してインストールするのはOKとしても、それ以降のBluetooth Deviceの選択など通常使用する部分はContemporaryタイプ対応もできていないと最新のVolumio2ではかなり不便ですので、Contemporaryタイプに対応するwww3.zipを新規に作成しました。従来のui.zipはwww.zipと名前を変更しました。


対応が必要な個所

具体的には、www3.zipの置き換えを行わないとContemporaryタイプでプラグイン→インストール済みのプラグイン→Bluetooth Manager→設定の画面で表示されるDiscoverableとBluetooth Devicesの2つのパートのうち、下側のBluetooth Devicesが全く表示されなくなります。

その理由はこのページの雛形はbluetooth_controller/UIConfig.jsonに定義されているのですが、Discoverableは個別項目別にプラグインの表示インターフェイスに従って定義されているのに対して、Bluetooth Devices部分は外部関数をコールして一括表示するようになっているからです。そしてコールされる側の関数は/volumio/http/www3/scripts/app-a79dee18c0.jsに定義されている必要があるので、その実装箇所をwww側のJavaScript(/volumio/http/www/scripts/app-cc34390d4d.js)から抜き出してwww3側に実装すればよいということになります。

(Bluetooth DevicesパートをDiscoverableパートと同様にUIConfig.json内に記述できない理由はAngularによる動的表示を行っているためです。)

$ cat /data/plugins/audio_interface/bluetooth_controller/UIConfig.json
{
    "page": {
        "label": "TRANSLATE.BLUETOOTH_SETTINGS"
    },
    "sections": [
                 { ### ここから Discoverable 表示領域 ###
                 "id": "port",
                 "element": "section",
                 "label": "TRANSLATE.DISCOVERABLE",
                 "icon": "fa-bluetooth",
                 "onSave": {"type":"controller", "endpoint":"audio_interface/bluetooth_controller", "method":"saveOptions"},
                 "saveButton": {
                 "label": "TRANSLATE.SAVE",
                 "data": [
                          "discoverable_setting"
                          ]
                 },
                 "content": [
                             {
                             "id": "discoverable_setting",
                             "element": "switch",
                             "label": "TRANSLATE.DISCOVERABLE",
                             "doc": "TRANSLATE.DISCOVERABLE_DOC",
                             "value": false
                             }
                             ]
                 }, ### ここまで Discoverable 表示領域 ###
                 ### ここから Bluetooth Device 表示領域 ###
                 {"coreSection":"bluetooth"}
                 ### ここまで Bluetooth Device 表示領域 ###
                ]
}

UI JavaScript修正

とは言え、/volumio/http/www/scripts/app-cc34390d4d.jsや/volumio/http/www3/scripts/app-a79dee18c0.jsを見ればわかりますが、minify処理がされているため簡単にという訳には行きません。minifyの逆変換を使用しながら、注意深く/volumio/http/www/scripts/app-cc34390d4d.jsからBluetooth Manager関連と思われる記述を抜き出して/volumio/http/www3/scripts/app-a79dee18c0.jsに移植しました。

ポイントのみを以下に書き出しておきます。

  • www/scripts/app-cc34390d4d.js からe.put("app/plugin/core-plugin/bluetooth-plugin.html", ...),を抜き出してwww3/scripts/app-a79dee18c0.js に加える
  • www3/scripts/app-a79dee18c0.js 冒頭の関数定義部分の末尾にom=i(141),sm=a(om)を追加して、初期化部分に.controller("BluetoothPluginController", sm["default"])を記述
  • www3/scripts/app-a79dee18c0.js の関数配列定義部分の末尾(141番目)にbluetoothが含まれるfunction (e, t) {"use strict"; ... } 部分をwww/scripts/app-cc34390d4d.jsから抜き出して追加

css, i18n修正

またcssやi18nに対しても以下の変更を加えます。

  • www/styles/app-b84007a5bf.css から#bluetoothPlugin {} で始まる語句を他の #wifiPlugin 等を除いて www3/styles/app-936d2e26fe.cssに加える
  • /volumio/http/www3/app/i18n/locale-en.jsonに以下を追加
    "BLUETOOTH": {
        "AUDIO":"Audio Device",
        "COMPUTER":"Computer",
        "CONNECT":"Connect",
        "DISCONNECT":"Disconnect",
        "REFRESH":"Refresh"
    }

これで、ContemporaryタイプでもClassicタイプのUIと同様にBluetooth ManagerのBluetooth Devicesの部分が動的に表示されるようになりました。

設定、コマンド、ツール類

プラグイン修正で使用したコマンドやツール類を列挙しておきます。

設定

  • bluesalsaサービス設定: /lib/systemd/system/bluezalsa.service
  • MPD設定: /etc/mpd.conf
  • MPDテンプレート: /volumio/app/plugins/music_service/mpd/mpd.conf.tmpl
  • asound.conf設定: /etc/asound.conf, ~/.asoundrc (両方とも今回は使用しなかった)

コマンド

### bluealsa再起動 ###
$ sudo systemctl daemon-reload
$ sudo systemctl enable bluezalsa.service
$ sudo reboot

### bluesalsa状態確認 ###
systemctl status bluezalsa

### mpd再起動 ###
$ sudo systemctl restart mpd.service

### bluetooth設定 ###
$ bluetoothctl
[bluetooth]# power on
[bluetooth]# scan on
[bluetooth]# pair <device MAC>
[bluetooth]# trust <device MAC>
[bluetooth]# connect <device MAC>
[bluetooth]# info <device MAC>

### サウンドデバイスの一覧 ###
$ aplay -L

### ALSAMIXER ###
$ alsamixer
$ alsamixer -D bluealsa

### bluealsaの情報確認 ###
$ amixer -D bluealsa

### volume設定 ###
$ amixer -c 5 -M set "SoftMaster" unmute 50%  # デバイス番号5は変わる可能性あり
$ amixer -D bluealsa -M set "[Device Name] - A2DP" unmute 50%

### プラグイン含めた全体動作確認 ###
$ sudo journalctl -b | less


### Minify ####
## for JavaScript ##
$ sudo npm install -g uglify-js
$ uglifyjs --compress --mangle -- xxx.js

## for CSS ##
$ sudo npm install -g clean-css-cli
$ cleancss xxx.css

ツール

参考URL

自己紹介

自分の写真
電子工作&プログラミング、オーディオ・音楽

注目の投稿

Raspberry Pi Pico Wで電波時計を合わせる (JJY標準電波エミュレータ)

Raspberry Pi Pico Wのアプリケーションとして 最少の周辺部品で電波時計むけJJYエミュレータ(時刻合わせ用)を製作しました。 ※2023年6月6日: ソースコード修正の内容を反映させました。 時刻合わせ風景 概要 電波時計は電波が届くところで使...

QooQ