ESP32 esp-idf bluetooth a2dp_sink への aptx decode 実装の考察 の続き、 #6 です。
ESP32 esp-idf bluetooth a2dp_sink への aptx decode 実装の考察 の続き、 #5 で説明した、プログラムの修正以外にも、結構な変更があったのですが、一応それらを、全て行って、
https://github.com/pali/libopenaptx のデコードのプログラムを組み込んで、試してみました。
結論から言えば、残念ながら、上記の、 libopenaptx のプログラムでは、おんちゃんの場合は、
まともな音は出ませんでした。
一応、Windows10+Bluetoothドングルで、 APTX でのフレーム受信までは出来るようになりました。
上記、 libopenaptx のプログラムでAPTX audio データをデコードして、I2S で音出ししてみると、
殆どノイズでうるさくて、まともに音楽は出てきません。
Windows10 の IE で YouTube を開いて、音楽を聴くと、 Bluetooth でペアリングした、ESP32 に繋げた I2S DAC ( https://www.switch-science.com/catalog/3572/ ) のヘッドホーンからは、それらしい音は出てきますが、ノイズの方が大きくて、まともには聴けません。
残念!!
libopenaptx に関して、少しだけ書くと、オリジナルは、openaptx.c の中の、aptx_decode() で、APTX をデコードして、24bit Stereo に変換しますが、
おんちゃんは、それをベースに、aptx_decode_16bit() を作って、16bit Stereo に変換してI2S へ出力するようにしました。
SRC から受信した、APTX Audio データを、 aptx_decode_16bit() へ渡して、デコードすると、かなりの確率で、パリティーチェックエラーになってしまいます。
ここを、解決しないといけないのでしょうが、
どう考えても、Windows10+ドングルの APTX の一般的な、エンコード処理と libopenaptx のデコード処理が一致していないのが原因のような気がします。
もう少し、おんちゃんの組み込み方に問題が無いのか調べてみるつもりですが、libopenaptx の中の問題であれば、おんちゃんの今回の作業もここで終わりとなります。
どうやら、avdt_scb_hdl_pkt_no_frag()::avdt_scb_act.c での、受信パケット内の、データのオフセットの計算と、
APTX の時は、連続して、パケットが2個受信される時があるのですが、その時の処理に問題があるような気がします。
もしかしたら、APTX はデータが多いので、フラグメントされて、複数パケットで上がって来るのかもしれません。
一方、SBC の場合は、ここには、常に1個のパケットが受信され、その都度、下位モジュールで適切に処理されています。
また、データのオフセットの計算も、本来、SBC 対応なので適切になされているのでしょう。
上述の、原因を、libopenaptx のデコード処理に決めてしまうには、まだ早計ぞね。
avdt_scb_hdl_pkt_no_frag()::avdt_scb_act.c の処理内容を、チェックしてみます。
但し、APTX がフラグメントパケットを扱わなければいけないのであれば、avdt_scb_hdl_pkt_frag()::avdt_scb_act.c を使わなければいけないと思います。
fluoride の方には、avdt_scb_hdl_pkt_no_frag() しか、見つからないので、avdt_scb_hdl_pkt_no_frag()::avdt_scb_act.c を使う事を信じて、ロジックをチェックしてみます。
が、しかし、此処のコードは、おんちゃんには、難解ぞね。
と思ったけれど、AVDT_MSG_PRS_OCTET1 とかは、#define 文を展開してみれば案外理解できました。
avdt_scb_hdl_pkt_no_frag()::avdt_scb_act.c を色々いじってみたのですが、旨く行かなかったので、fluoride の APTX のデコード処理 a2dp_vendor_aptx_send_frames()::a2dp_vendor_aptx_encoder.cc のコードを解析してみました。
現行の、 avdt_scb_hdl_pkt_no_frag() の中での、SBC 対応である、 offset の算出とは結構違うような気がします。
ですので、avdt_scb_hdl_pkt_no_frag() の offset 算出のロジックを、SBC と APTX と完全に分けて行うように、プログラムを変更しました。
余り期待していなかったのですが、期待に反してこれでやっと、aptx_decode_16bit()::openaptx.c でのエラーが取れました。
やれやれでしたが、
W(xxxxx) BT_APPL: Pkt dropped
のログが出る問題が出てきました。
この時点で、libopenaptx も、一般的な、Winddows10+Bluetooth ドングルのAPTX エンコードに対応していることが、判りました。疑って申し訳無かったぞね。
後は、この Pkt dropped の問題を解決すれば、やっと、APTX で音楽が聴けるようになるのでしょうか?
今の時点では、まだ音割れがひどいぞね。
Pkt Dropped が出る原因は、Bluetooth 側の受信フレームに対して、音楽データをデコードして、I2S へ送る側の処理が間に合っていない事のようです。
今回、SBC から、APTX のデコード処理へ変更したので、そこの部分が過負荷になっているようです。
対策として、CPU クロックを、80Mhz → 160Mhz に増やして、
APTXのデコードを行うタスクを、CORE 0 → 1 、プライオリティを configMAX_PRIORITIES - 3 → configMAX_PRIORITIES - 1 に変えてためしてみました。
少しは、Pkt Dropped が減りましたが、まだまだ常に出ています。
APTX のデコード処理は、ESP32 160Mhz 程度では、CPUの能力不足みたいぞね。
でも、本当にそうなのか?
もしかして、 esp-idf の Bludroid の作り込みが余りよくないのか?
結構、中で、データを、何度もコピーして、何度も、キューイングして、複数タスクを経由して、
やっと、I2S のライブラリーへデータを出している。
SBCのデコードが大した負荷が掛からなくて、処理速度の点が、問題として顕在化しなかった為、
安易に、Bluedroid のesp-idf へのインポート時に、タスク間通信のオーバーヘッドを余り
考えないで、してしまったのか?
その点は、おんちゃんにはおおいに気になるところぞね。
或いは、今回使っている libopenaptx 自体が、マイコンで使うようには、オプティマイズされていないのか?
そうは言っても仕方がないので、今後は、APTXのデコード部分を、2つのタスクを起動して、負荷の分散を行わせることを考えちょります。
さて、どうなることやら?