05.絶対音量対応



送信側(スマートフォン等)が絶対音量(Absolute Volume)でオーディオデータを送信している場合は、受信したオーディオデータを、ボリューム設定に応じたオーディオデータに変更してから、オーディオDACモジュールに送ります。

補足1)
絶対音量ではないオーディオデータ送信」 : 送信側はオーディオをボリューム値に応じたデータで送信します。受信側は、受信したデータを、そのまま、オーディオDACモジュールに送ります。送信側のボリュームの変更が、再生される音量に反映されます。
絶対音量でオーディオデータ送信」 : 送信側はオーディオを常に最大音量でのデータで送信します。受信側は、受信したデータを、送信側のボリューム値に応じて変更してから、オーディオDACモジュールに送ります。「送信側のボリューム値に応じたオーディオデータに変更」をしないと、送信側のボリュームを変更しても、再生される音量は常に最大音量となります。

補足2)
デバイスの設定、OSの設定、アプリの設定、に依存するところも大きいですが、手元での確認の結果、
・「Android スマートフォン」は、「絶対音量ではないオーディオデータ送信」です。
・「iphone」は、「絶対音量でオーディオデータ送信」です。
・「Windows パソコン」は、「絶対音量でオーディオデータ送信」です。
・ 「絶対音量ではないオーディオデータ送信」「絶対音量でオーディオデータ送信」を設定で切り替えることができるデバイスもあります。

補足3)
本項目の内容は、「a2dp_sink example: adds software volume control (IDFGH-4307) by bellatriks · Pull Request #6150 · espressif/esp-idf · GitHub」を参考にしています。

前提

04.ボリューム変更シミュレーション機能の無効化」を実施していない場合は、実施します。

ボリューム値に応じたデータに変更するための関数の宣言と定義

ボリューム値に応じたオーディオデータに変更するための関数の宣言のファイルを用意します。
ファイル名を「bt_app_volume_control.h」とします。
「bluetooth_audio_receiver」ディレクトリに配置します。

ファイル「bt_app_volume_control.h」の内容は以下のようにします。


ボリューム値に応じたオーディオデータに変更するための関数の定義のファイルを用意します。
ファイル名を「bt_app_volume_control.c」とします。
「bluetooth_audio_receiver」ディレクトリに配置します。

ファイル「bt_app_volume_control.c」の内容は以下のようにします。

bt_app_set_volume 関数の呼び出し

送信側でボリュームが変更された際に呼び出される処理に、bt_app_set_volume 関数の呼び出しを追加します。
具体的には、「bt_app_av.c」ファイルの「volume_set_by_controller 関数」に「bt_app_set_volume(volume);」を追加します。
補足)この関数は、「絶対音量ではないオーディオデータ送信」の際には、コールされないので、「絶対音量ではないオーディオデータ送信」の際には、受信したデータは、データ変更処理は行われますが、処理の結果、データは変わらずに、オーディオDACモジュールに送られます。


送信側にボリューム値の初期値を送信する処理に、bt_app_set_volume 関数の呼び出しを追加します。
具体的には、「bt_app_av.c」ファイルの「bt_av_hdl_avrc_tg_evt 関数」の「ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT」処理に「bt_app_set_volume(volume);」を追加します。
補足)この処理は、「絶対音量ではないオーディオデータ送信」の際には、処理されないので、「絶対音量ではないオーディオデータ送信」の際には、受信したデータは、データ変更処理は行われますが、処理の結果、データは変わらずに、オーディオDACモジュールに送られます。


「bt_app_av.c」ファイルのヘッダー部に、「#include "bt_app_volume_control.h"」を追加します。

bt_app_adjust_volume 関数の呼び出し

オーディオDACモジュールにオーディオデータを送信する処理の直前に、bt_app_adjust_volume 関数の呼び出しを追加します。
具体的には、「bt_app_core.c」ファイルの「bt_i2s_task_handler 関数」に「bt_app_adjust_volume(data, item_size);」を追加します。


「bt_app_core.c」ファイルのヘッダー部に、「#include "bt_app_volume_control.h"」を追加します。

「CMakeLists.txt」ファイルの編集

ボリューム値に応じたオーディオデータに変更するための関数の定義のファイルを、ビルド対象に追加します。

「CMakeLists.txt」ファイルに、「bt_app_volume_control.c」を追加します。

ビルド

以下のコマンドを実行し、プロジェクトのプログラムをビルドします。



完了するまで、しばらく待ちます。

フラッシュ

ビルド結果を、マイコンに書き込むフラッシュのコマンドは以下の書式です。



シリアル通信デバイス名が「/dev/ttyUSB0」の場合は、以下のコマンドを実行します。



完了するまで、しばらく待ちます。

動作確認

フラッシュが完了すると、マイコンに書き込まれたプログラムが起動します。

Bluetooth機能が搭載されているデバイス(スマートフォンやパソコン)から、作成した「Bluetooth Audio Receiver」にBluetooth接続します。
作成した「Bluetooth Audio Receiver」のデバイス名は「ESP_SPEAKER」です。

作成した「Bluetooth Audio Receiver」のイヤホンジャックに接続したイヤホンやスピーカーから、接続元のデバイスで再生したオーディオを聴くことができます。

送信側(スマートフォン等)が絶対音量(Absolute Volume)でオーディオデータを送信している場合でも、送信側のボリュームの変更が、再生される音量に反映されます。

参考)ゲインプリセット配列の変更

a2dp_sink example: adds software volume control (IDFGH-4307) by bellatriks · Pull Request #6150 · espressif/esp-idf · GitHub」のオリジナルのコードの場合、ボリューム値が小さいときに、再生される音量が小さかったため、ゲインプリセット配列を変更しています。

オリジナルのコードのゲインプリセットは、
y = a * 10 ^ { (-51 + 51 * x/127 ) / 20 }
の式で表される値の配列となっていました。
(ここで x は、0から127までの値をとります。
 a は、x = 127 のときにとりたい y の値になる値とします。
 x = 127 のとき、y = 65535 をとりたいので、a = 65535 / 10^0 = 65535 となります。
 y = 65535 * 10 ^ { (-51 + 51 * x/127 ) / 20 }
 ミュートのために、y = 0 をゼロ番に加え、式から求まる値の配列番号は、1ずつ、シフトしたものです。127番の値は強制的に、y=65535 です。)

オリジナルのコードのゲインプリセットでは、ボリューム値が小さいときに、再生される音量が小さかったため、ゲインプリセットを、
y = a * (x/127)
の式で表される値の配列としました。
(ここで x は、0から127までの値をとります。
 a は、x = 127のときにとりたい y の値になる値とします。
 x = 127 のとき、y = 65535 をとりたいので、a = 65535 / 1 = 65535 となります。
 y = 65535 * (x/127)
 )

y = a * (x/127)^2
の式で表される値の配列も試しましたが、ボリューム値が小さいときに再生される音量が小さい問題が解消しませんでした。
(ここで x は、0から127までの値をとります。
 a は、x = 127のときにとりたい y の値になる値とします。
 x = 127 のとき、y = 65535 をとりたいので、a = 65535 / 1^2 = 65535 となります。
 y = 65535 * (x/127)^2
 )

参考)「オリジナル」版と「y = 65535 * (x/127)」版と「y = 65535 * (x/127)^2」版のゲインプリセットの配列


参考)「オリジナル」版と「y = 65535 * (x/127)」版と「y = 65535 * (x/127)^2」版のゲインプリセットの配列の値のグラフ

関連ページ

前項目:04.ボリューム変更シミュレーション機能の無効化

次項目:06.ボリューム値の復元対応