Bluetooth® LEで音声通信にトライ！ LE Audioを試してみた①　ユニキャスト

今回は、STマイクロエレクトロニクスのワイヤレスSoC「STM32WBAシリーズ」の開発ボードを使って、Bluetooth® Low Energy（Bluetooth LE）のversion 5.2から追加された<a href=https://www.bluetooth.com/learn-about-bluetooth/feature-enhancements/le-audio/>LE Audio</a>を試してみます。Bluetooth LEでは、長らく音声通信がサポートされていなかったので、音声通信を行う場合、Bluetoothクラシック（BR / EDR）を使うのが一般的でした（現在普及しているBluetoothイヤホン / ヘッドホン / スピーカの多くは、このBluetoothクラシックで動作しています）
「すでに（音声通信は）昔からある機能なので、いまさら別の仕様である“LE Audio”などを組み込まなくてもよいのでは？」とも思われるかもしれませんが、LE Audioを使うことで実現できる新機能や性能改善もあります。Bluetooth SIG（Bluetooth規格の標準化団体）は、「1 対 多受信」（ブロードキャスト = AURACAST™）、「マルチストリーム」、「コーデックの改善」、「低遅延」などを挙げています。
また、いわゆるBluetoothクラシックはBluetooth SIGにより廃止される予定なので、長い目で見ればいずれすべての音声通信がLE Audioに移行されます。

今回は、LE Audioのサンプルコードが用意されているマイコン・ボードを使って、音楽送信 & 再生を行ってみます。



![000_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/ec0c5440-dc36-a953-9494-62513ac8bde9.png)

LE Audioでは、アイソクロナス伝送チャネルを使用します。同じグループのストリーミング･データを同期的に受信できる仕組みになっています。つまり、複数ストリーミング間で同じタイミングでのデータ受信が可能です。
方式として 「 **ユニキャスト** 」 と 「 **ブロードキャスト** 」 の2種類があります。ユニキャストは、Bluetoothクラシックと同じように、機器間で接続（コネクション）した後、データを送受信します。ブロードキャストはラジオ放送受信のような考え方で、1つの発信機器（ソース）のデータを、多数の受信機器（シンク）が受信する形になります。これは、LE Audioで実現できる新しい機能です。


<a href=https://wiki.st.com/stm32mcu/wiki/Connectivity:Introduction_to_Bluetooth_LE_Audio>ST WiKi LE Audio</a>

<table>
  <caption>LE Audio</caption>
  <thead>
    <tr>
      <th>アイソクロナス転送種別</th>
      <th>内容</th>
    </tr>
  </thead>
  <tr>
    <td> ユニキャスト <BR>CIS（Connected Isochronous Streams）</td>
    <td> ポイント･ツー･ポイントのコネクション型<BR>双方向通信 </td>
  </tr>
  <tr>
    <td> ブロードキャスト<BR>BIS（Broadcast Isochronous Streams） </td>
    <td> 1 対 多の非コネクション型<BR>受信側デバイス数に制限なし<BR>単方向通信</td>
  </tr>


</table>

# 1．ハードウェアの準備
【用意するもの】
- <a href=https://www.st.com/ja/evaluation-tools/stm32wba55g-dk1.html>STM32WBA55G-DK1</a>　x2台
- USB Type-Cケーブル x2本
- パソコン
- イヤホン or ヘッドホン（有線）
- ポータブル音楽プレーヤ（ヘッドホン出力 or LINE-OUT付き）
- 3.5mmステレオ･ミニプラグ･ケーブル
- モバイル･バッテリ
- LE Audioをサポートするスマートフォン（ここではPixel7を使用）
- LE Audioをサポートするワイヤレス･イヤホン（ここではearfun Air Pro4を使用）

STM32WBA55G-DK1の外観

![100_board_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/1d5a4379-5d5a-d544-c7cc-cf202200d9ea.png)


ユーザマニュアル（UM3255）: <a href=https://www.st.com/ja/evaluation-tools/stm32wba55g-dk1.html#documentation>STM32WBA55G-DKドキュメントページ</a>参照

# 2．ファームウェアの準備
（既にインストール済みであればスキップしてください）
初めてパソコンでSTM32マイコンの開発ボードを使用する場合、 **STM32CubeProgrammer** （旧ツール：ST Link Utility）をインストールしてCOMポート･ドライバなどを入れます。このツールは一般的にSTM32マイコンにファームウェア・プログラムを書き込む際に使いますが、このツール自体は今回使用しません。後述するように、簡易書き込みで行います。
ダウンロードはこちらから：[STM32CubeProgrammer](https://www.st.com/ja/development-tools/stm32cubeprog.html)

![200_cubeprogrammer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/c982fa59-a639-c40b-e081-f792cadcb7a2.png)


## 動作用ファームウェアの入手（STM32CubeWBA）

ダウンロードはこちらから：[STM32CubeWBA](https://www.st.com/ja/embedded-software/stm32cubewba.html)

ダウンロードしたファイルを解凍すると、そのまま統合開発環境用の作業フォルダが作成されます。以下のプロジェクト･フォルダに今回使用するプログラム･ファイル（バイナリ・ファイル）が用意されているので、まずはファイルを確認します。
ファームウェアは、送信側用と受信側用がそれぞれ用意されています。LE Audio用サンプルとして、“BLE_Audio_xxx”というプロジェクト･フォルダがいくつかあるので確認してください。
場所（例）：
Drive:\...\STM32Cube_FW_WBA_V1.4.0\Projects\STM32WBA55G-DK1\Applications\BLE\

用意されているLE Audio関連プロジェクト･フォルダ

![201_explorer_cubeFW.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/88c3b316-4c0d-468f-0e31-cf6170fc076c.png)


<table>
  <caption>STM32CubeWBA音声通信関連ファームウェア（ver1.4）</caption>
  <thead>
    <tr>
      <th>プロジェクト名</th>
      <th>内容</th>
      <th> Note </th>
    </tr>
  </thead>
  <tr>
    <td> BLE_Audio_HAP_Central <BR> BLE_Audio_HAP_Peripheral </td>
    <td> Hearing Access Profile </td>
    <td> 補聴器（Hearing Aid）想定 </td>
  </tr>
  <tr>
    <td> BLE_Audio_PBP_Sink <BR> BLE_Audio_PBP_Source </td>
    <td> Public Broadcast Profile </td>
    <td> ブロードキャスト</td>
  </tr>
  <tr>
    <td> BLE_Audio_TMAP_Central <BR> BLE_Audio_TMAP_Peripheral </td>
    <td> Telephony and Media Audio Profile </td>
    <td> 通話 / ユニキャスト / ブロードキャスト </td>
  </tr>

</table>

今回は、ユニキャスト通信の確認のため、**TMAP（Telephony and Media Audio Profile）** 用ファームウェアを使います。ユニキャストの他、ブロードキャスト通信といった基本的な動作を試せます。TMAPやPBP、HAPといった用語の詳細については、Bluetooth SIGのホームページ内にある<a href=https://www.bluetooth.com/learn-about-bluetooth/feature-enhancements/le-audio/le-audio-specifications/>LE Audioの技術資料</a>を参考ください。
ファームウェア実行ファイル（バイナリ･ファイル）の場所を確認します。

ファイル保管場所（例）：
Drive:\...\STM32Cube_FW_WBA_V1.4.0\Projects\STM32WBA55G-DK1\Applications\BLE\BLE_Audio_TMAP_Central\Binary
ファイル名：**「BLE_Audio_TMAP_Central.bin」**
Drive:\...\STM32Cube_FW_WBA_V1.4.0\Projects\STM32WBA55G-DK1\Applications\BLE\BLE_Audio_TMAP_Peripheral\Binary
ファイル名：**「BLE_Audio_TMAP_Peripheral.bin」**

![202_explorer_cubeFW_bin_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/547d9282-abd7-6e8f-1a9d-2409738db380.png)





## STM32WBA55G-DK1にファームウェアを書き込み（パソコンと接続）

STM32WBA55G-DK1をUSBケーブル（Type-C）でPCと接続し、Windowsエクスプローラで確認します。
→ **「DIS_WBA55G」** といったUSBメモリ・デバイスのような形式で認識されます。

STの評価ボードであるディスカバリ･キット（Discovery Kit）はSTM32 Nucleoボードと同様に、ST-LINK機能がボード内に回路として用意されているので、USB接続だけでファームウェア書き込み & デバッグが行えます。


STM32WBA55G-DKの2台に、Central側とPeripheral側ファームウェアをそれぞれ書き込みます。先ほど確認したバイナリ・ファイルを、この「DIS_WBA55G」へドラッグ & ドロップ。これだけでSTM32 マイコンへのファームウェア書き込みは完了です。書き込み後は、Central / Peripheralの区別がつくようにラベルを貼っておくと良いでしょう。書き込みは1台ずつパソコンに接続して行います。
+ BLE_Audio_TMAP_Central.bin
+ BLE_Audio_TMAP_Peripheral.bin

![210_explorer_cubeFW_praogramcentral.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/6a4d9932-85f1-793d-8071-d791c3185e2c.png)

![211_explorer_cubeFW_praogramperipheral.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/94873ca6-ad4c-c4b1-0390-1f1d2bb388b3.png)



# 3．動作確認1　

まずは、準備した2台のSTM32WBA55G-DKボードを使って通信を行います。

## セットアップ

ポータブル･プレーヤからのアナログ･オーディオ出力を、Central側ボードのCN4ジャック･コネクタ（AUDIO IN）へオーディオケーブルで接続します。PCのヘッドホン出力も利用できますが、注意点があります（*1）。
Peripheral側ボードのCN3ジャック･コネクタ（AUDIO OUT）は、イヤホン（ヘッドホン）もしくはアンプ付きスピーカを接続します。
両ボードにUSB（Type-C）で電源供給します。


![300_boardsetup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/1474da09-b58b-f4ab-8f65-a94b91300955.png)


（*1） 接続時注意点
Central側ボードについて、電源とオーディオ出力の両方をPCから取る接続にすると、バックグラウンドにノイズ発生することが多いです（どちらか1つであれば問題なし）。原因は不明ですが、RF部 / Audio部がなんらかの影響を受けている可能性があります。

![301_PCconenct_NG_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/a0445487-0b67-e441-b8e9-d897b4b3a969.png)


### 操作手順

両ボードを起動すると、液晶画面（LCD）にメニューが表示されます。その下にある4方向キーボタン（ジョイスティック）で操作します。基本的には、上下ボタンでセレクト、右ボタンで決定、左ボタンで戻りといった操作になります。


Central側およびPeripheral側について、以下操作でユニキャスト･モードから開始します。ユニキャストはBluetoothクラシックと同じく、送信側・受信側どうしで1対1接続を行い、送受信する接続方式です。

![310_LCD_connection_1_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/99a87216-91bc-e842-c107-daf8ce904a6e.png)


接続（“Connected”表示）できたら、音声ストリーミング･モードにします。

![311_LCD_conenction_2_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/03e9dcac-10e7-b399-eb66-e83c403f24ab.png)


“Streaming 48KHz”と表示されれば成功です。Central側に接続したポータブル･プレーヤで音楽再生したところ、Peripheral側のイヤホンから音声が確認できました。


ボリュームは、Central側 / Peripheral側どちらからでもコントロールでき、上下キーで変更可能です。Central側から行う場合“Remote Volume”から操作します。

## 音声確認

以下の条件で聴き比べてみました。比較条件の違いとしては、プレーヤとイヤホン間におけるSTM32WBA55G-DK1ボードによるBluetooth LE通信の有無のみです。

+ A : ポータブル･プレーヤ → STM32WBA55G-DK（Central） → （Bluetooth LE） → STM32WBA55G-DK（Peripheral）→ イヤホン
+ B : ポータブル･プレーヤ → イヤホン

![320_listeningcheck.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/7580ef5d-4939-e01c-5a68-dac33b7b1f25.png)




ポータブル･プレーヤとイヤホンは一般的な製品を使用しました。ハイエンドの機器を使用すれば、さすがに差が出てくるかもしれませんが、そこまでは試していません。感想として、私の耳ではA / B間の違いはさほど判りませんでした。十分に使えるレベルだと思います。（残念ながら、音の“透明感”や、“艶”などの指標は筆者の耳では感知できません。）

#### 試聴環境

ポータブル･プレーヤ: iPod touch（MD717J/A）/ Apple.
イヤホン: CKM500 / Audio Technica.

#### 試聴用音声ソース
邦楽1:　WAV_44.1KHz（CD音源）
洋楽1:　WAV_44.1KHz（CD音源）
クラシック1:　WAV_48KHz

#### 音声周りハードウェア情報（STM32WBA55G-DK1）

STM32WBA55G-DKボードには、3.5mmのジャック・コネクタが入出力用にそれぞれ用意されており、ADC（アナログ･デジタル･コンバータ） / DAC（デジタル･アナログ･コンバータ）両機能を持つIC「CS42L51」がオーディオ入出力部を担います。入力部は、ジャック・コネクタ（CN4）からのアナログ信号をI2Sデジタル信号に変換後、STM32WBA55がSAIポート（Serial Audio Interface）で受けます。出力時は、STM32WBA55から同じくSAIポートでI2S信号をCS42L51が受け、アナログ変換後、ジャック・コネクタ（CN3）に出力します。念のため、CS42L51のLRクロック（pin1）周波数を確認したところ、48KHz出ていました。

### LC3設定内容をログで確認

LE Audioで採用されている音声コーデックは<a href=https://www.bluetooth.com/specifications/specs/low-complexity-communication-codec-1-0/>LC3</a>です。送受信時、具体的にどのようなコーデック設定内容になっているのかをログで確認してみます。再コンパイルが必要ですが、app_conf.hファイル内で、**CFG_LOG_SUPPORTED = 1** にすることでUSBシリアルポート（VIRTUAL COM PORT）経由で、動作中のログが出力表示されます。送信側･受信側どちらでも設定できます。


```app_conf.h
     #define CFG_LOG_SUPPORTED     (1U)  /* 1=UART Log ON */
``` 

以下は、接続後に音声ストリーミングを開始した時のログ例になります。
受信側（Peripheral側ボード）で確認。ターミナル･モニタはTeraTermを使いました。

```Log_TMAP_Periperal_MediaStart.txt
CAP Event : 0x0D
Preferred Server QoS Settings is requested for ASE ID 1 (Type 0x00)
  Target Latency : 1
  Target Phy 2 to achieve the Target Latency
  Codec ID
    Coding format : 0x06
    Company id : 0x0000
    VS codec id : 0x0000
    Frequency : 8
    Frame Duration : 1
    Octets Per Codec Frame : 120
    Codec Frame Blocks Per SDU : 1
  Min Controller Delay in Source role 4394 us
  Max Controller Delay in Source role 110000 us
  Min Controller Delay in Sink role 4575 us
  Max Controller Delay in Sink role 70000 us
Calculated SDU Interval : 10000 us
Computed Min Controller Delay with 2 Snk ASEs and 1 Src ASEs : 13544 us
WARNING : Controller Delay Min ( 13544 us) could be higher than the frame duration (10 ms)
Submitted Min Presentation Delay 10100 us
Submitted Max Presentation Delay 70100 us
```

Bluetooth資料によると、LC3コーデック用の設定はいくつかあり、サンプリング周波数以外にフレーム期間や、1コーデック･フレームあたりのByte数が設定できます。今回のメディア･ストリーミング開始時のログで確認すると、以下情報が読み取れます。（<a href=https://www.bluetooth.com/bluetooth-resources/le-audio-book/?utm_source=marketo&utm_medium=email&utm_campaign=le-audio&utm_term=email&utm_content=leaudio-book-announce-mem&mkt_tok=OTE1LUJSRi0xNDkAAAGB8aZVPUygwiY2uHloWjtokyLJEL-BmRCbHQmIx2Ns0NHv3KCT98trA4PJ75BxWBEhpG6lLf5w-M91lpR_ZTpu7kg5TgjANyweRR3YlWYkQg>「Introducing-Bluetooth-LE-Audio-book.pdf」</a>で確認）

"Frequency : 8" --> Fs = 48KHz
"Frame Duration : 1" --> Frame duration = 10ms
"Octets Per Codec Frame : 120" --> Octest (Byte) per Frame = 120 Byte

10ms分のフレーム内データを、1チャネルあたり120Byteデータに変換。つまりビットレートとしては、120*8/0.01 = 96kbit/s。ステレオ2chで想定すると192Kbit/sといったところでしょうか。
ちなみに、Central側ファームウェアを確認したところ、48KHzは1～6までサポートしています。ストリーミング開始操作時、送り手側と受け手側とで話し合いの後、コーデック設定を決定しているようです。


# 4．動作確認2　with スマートフォン

次にCentral側としてスマートフォンを使い、Peripheral側としてSTM32WBA55G-DKボードを1台使います。

## セットアップ

Peripheral側ボードの接続は動作確認1の時と同じく、電源とイヤホンなどを接続します。スマートフォンについては、Bluetooth設定においてLE Audioが使えるようにしておきます。

![400_smartphonesetup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/84575f70-3b41-798b-9fe7-50e5088b6f29.png)



### 操作手順

以下手順でスマートフォンから対象デバイスをBluetoothデバイスとして登録し、接続します。

![410_LCD_connection_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/3a136472-3713-9919-f852-0c85c052453e.png)



スマートフォン側操作（例）

![411_smartphone_connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/55bb91a3-31d6-41d7-9916-3fdd499767bf.png)



## 音声確認

音楽再生アプリ（YouTube Musicを使用）で確認しましたが、問題なく音声確認できました。こちらの音声も私の耳で聴く限り良好でした。

### ログ確認

動作確認1の時と同様にログを見てみます。設定内容は同じくFs = 48KHz、Frame duration = 120Byteとなっていました。




# 5．動作確認3　with ワイヤレス･イヤホン

最近は、LE Audio対応のワイヤレス･イヤホンも発売されてきているので、送信側ボードと接続して試してみます。
Central側としてSTM32WBA55G-DKボードを1台、Peripheral側としてワイヤレス･イヤホンを使います。

使用したワイヤレス･イヤホン: earfun Air Pro 4

## セットアップ

Central側ボードのみ動作確認1の時と同じようにセットします。ワイヤレス･イヤホンを本体ボックスから取り出して耳にセットします。この時ペアリング･モード状態にします。

![500_earbud_setup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/31a37fca-36d3-4440-62e5-255487d9fd61.png)


### 操作手順
操作手順も動作確認1の時と同じです。

![510_LCD_connection_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/ced467e8-af64-2ae4-b23d-e40560d9c9ad.png)


接続（“Connected”表示）できたら、音声ストリーミング･モードにします。

![511_LCD_connection_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360475/e7510cf8-f929-87d8-1b9a-ed17f21d8d20.png)


ストリーミングがスタートすると、“Streaming 48KHz”と表示されます。ポータブル･プレーヤ側を操作して音楽再生すると、音声確認できます。

## 音声確認

こちらも問題なく音声確認できました。ワイヤレス･イヤホンの性能が良いのかどうかわかりませんが、今回のテストの中では最も高音質のように感じました。


次回は、ブロードキャスト通信（AURACAST™）にトライしてみます。
<a href=https://qiita.com/ykawano/items/62e48136a4ec2e1af50a>Bluetooth® LEで音声通信にトライ！ LE Audioを試してみた②　ブロードキャスト</a>