mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
fix(ble_audio): Miscellaneous fixes for ISO & LE Audio examples
This commit is contained in:
@@ -1,52 +1,107 @@
|
||||
| Supported Targets | ESP32-H4 | ESP32-S31 |
|
||||
| ----------------- | -------- | --------- |
|
||||
|
||||
# BLE BIG Broadcaster Example
|
||||
# BIG Broadcaster
|
||||
|
||||
(See the README.md file in the upper level `examples` directory for more information about examples.)
|
||||
|
||||
This example demonstrates the **Bluetooth LE Isochronous Broadcaster** functionality. It acts as a Broadcast Isochronous Stream (BIS) source: it starts extended advertising and periodic advertising, creates a Broadcast Isochronous Group (BIG), and sends isochronous data on the BIS channels. Receivers can synchronize to this BIG using the [big_receiver](../big_receiver) example.
|
||||
## Overview
|
||||
|
||||
The implementation uses the NimBLE host stack with ISO support and the ESP-BLE-ISO APIs (CIG/BIG, data path, channel operations). It is intended for chips that support BLE 5.2 ISO (e.g. ESP32-H4). The advertised device name is hardcoded as `BIG Broadcaster` and the broadcast code is hardcoded as `1234`; these can be changed by editing the source code constants.
|
||||
This example demonstrates a raw BLE Isochronous Broadcaster — it creates a Broadcast Isochronous Group (BIG) directly at the ISO transport layer over the NimBLE host, without any BLE Audio profile (BAP/CAP) on top.
|
||||
|
||||
The device acts as the **broadcaster**: it starts extended + periodic advertising, creates a BIG carrying two BIS streams, sets up an HCI input data path on each BIS, and then transmits SDUs on a fixed 10 ms cadence using a software TX scheduler. The peer (`big_receiver`) discovers the broadcaster by name, syncs to the periodic advertising train, decodes BIGInfo, and joins the BIS sub-events.
|
||||
|
||||
The audio data on the wire is **application-supplied dummy payload** (each SDU is filled with the byte value of its sequence number). The coding format is `ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT`, so no LC3 / LE-Audio framing is involved.
|
||||
|
||||
## Requirements
|
||||
|
||||
* A board with Bluetooth LE 5.2 and ISO support (e.g. ESP32-H4)
|
||||
* Optionally, a second device running the [big_receiver](../big_receiver) example to receive and sync to the BIG
|
||||
* A board with BLE 5.2 and ISO support (e.g. ESP32-H4, ESP32-S31)
|
||||
* Peer device running the paired example
|
||||
|
||||
## How to Use Example
|
||||
## Configuration
|
||||
|
||||
Before project configuration and build, set the correct chip target:
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
No build-time options — runtime defaults are baked into source.
|
||||
|
||||
Notable hard-coded parameters in `main/main.c`:
|
||||
|
||||
* `LOCAL_DEVICE_NAME` — `"BIG Broadcaster"` (advertised in extended adv)
|
||||
* `LOCAL_BROADCAST_CODE` — `"1234"` (BIG is encrypted)
|
||||
* `BIG_SDU_INTERVAL_US` — 10 000 us
|
||||
* `BIG_LATENCY_MS` — 10 ms
|
||||
* `BIG_PHY` — 2M
|
||||
* `BIG_RTN` — 2 (retransmissions)
|
||||
* `BIS_ISO_CHAN_COUNT` — 2
|
||||
* `BIS_SDU_SIZE` — 120 bytes
|
||||
|
||||
### Security & Pairing
|
||||
|
||||
The shared init at `../common_components/example_init/ble_iso_example_init.c` configures Just-Works pairing (LE Secure Connections, no MITM, `BLE_SM_IO_CAP_NO_IO`) with bonding enabled, and leaves `gatts_register_cb = NULL` (no GATT services). These settings are not exercised by this example — BIG broadcast traffic is non-connectable and BIS payload encryption is driven by the broadcast code, independent of host SMP.
|
||||
|
||||
## Build & Flash
|
||||
|
||||
```bash
|
||||
idf.py set-target esp32h4
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run the following to build, flash and monitor:
|
||||
|
||||
```bash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF.
|
||||
(Exit serial monitor with `Ctrl-]`.)
|
||||
|
||||
## Example Flow
|
||||
|
||||
1. **Initialization**: NVS, Bluetooth stack (NimBLE), and ISO common layer (`esp_ble_iso_common_init`).
|
||||
2. **Extended and periodic advertising**: Configure and start extended advertising with a fixed interval; attach periodic advertising with name `BIG Broadcaster` for receivers to discover.
|
||||
3. **Create BIG**: Register the advertising set for BIG, then create a BIG with two BIS channels (hardcoded as `BIS_ISO_CHAN_COUNT` in the source; `CONFIG_BT_ISO_MAX_CHAN` must be >= 2), SDU interval 10 ms, latency 10 ms, sequential packing, unframed, and encryption with the hardcoded broadcast code `1234`. The [big_receiver](../big_receiver) must use the same broadcast code.
|
||||
4. **Send ISO data**: Once all BIS channels are connected and their data paths are set up, a periodic TX scheduler based on `k_work_delayable` sends the same SDU on all BIS channels at the configured interval in the ISO task context; sequence numbers and drift handling are applied. Note that the scheduler timer resolution is in milliseconds, which may not match the exact SDU interval for all configurations.
|
||||
1. NVS, NimBLE host, and the ISO common layer are initialised.
|
||||
2. A TX scheduler is initialised for each of the two BIS channels.
|
||||
3. Extended advertising parameters / data and periodic advertising parameters / data are configured for handle 0 (non-connectable, non-scannable, primary 1M / secondary 2M).
|
||||
4. Periodic advertising and extended advertising are started.
|
||||
5. `esp_ble_iso_big_ext_adv_add()` ties the adv handle to the BIG, then `esp_ble_iso_big_create()` issues the HCI `LE Create BIG` with two BIS, encryption on, and broadcast code `"1234"`.
|
||||
6. As each BIS becomes ready, the connected callback installs an HCI input data path (`ESP_BLE_ISO_DATA_PATH_DIR_INPUT`, transparent coding).
|
||||
7. Once both BIS are connected, the per-channel TX schedulers start firing every 10 ms, calling `esp_ble_iso_chan_send()` with a 120-byte dummy SDU and an incrementing sequence number.
|
||||
8. On disconnect of all BIS the schedulers are stopped and the BIG handle is cleared.
|
||||
|
||||
## Example Output
|
||||
## Expected Log
|
||||
|
||||
Tag: `BIG_BRD`.
|
||||
|
||||
Startup / advertising:
|
||||
|
||||
```
|
||||
I (xxx) BIG_BRD: Extended adv instance 0 started
|
||||
I (xxx) BIG_BRD: ISO channel 0x0001 connected
|
||||
I (xxx) BIG_BRD: ISO channel 0x0002 connected
|
||||
I (xxx) BIG_BRD: Transmitted 1000 ISO data packets (chan 0x...)
|
||||
...
|
||||
I (xxx) BIG_BRD: Advertising started (handle 0)
|
||||
```
|
||||
|
||||
BIS bring-up (first BIS, then second, then TX start):
|
||||
|
||||
```
|
||||
I (xxx) BIG_BRD: [BIS #0] Connected
|
||||
I (xxx) BIG_BRD: Waiting for remaining BIS channels (1/2)
|
||||
I (xxx) BIG_BRD: [BIS #1] Connected
|
||||
I (xxx) BIG_BRD: All 2 BIS channels connected, starting TX
|
||||
```
|
||||
|
||||
Steady-state (logged every `LOG_INTERVAL_PACKETS` SDUs by the shared TX helper):
|
||||
|
||||
```
|
||||
I (xxx) BIG_BRD: [BIS #0] TX: <N> packets
|
||||
I (xxx) BIG_BRD: [BIS #1] TX: <N> packets
|
||||
```
|
||||
|
||||
Teardown:
|
||||
|
||||
```
|
||||
I (xxx) BIG_BRD: [BIS #0] Disconnected, reason 0x<rr>
|
||||
I (xxx) BIG_BRD: [BIS #1] Disconnected, reason 0x<rr>
|
||||
I (xxx) BIG_BRD: All BIS channels disconnected, TX stopped
|
||||
```
|
||||
|
||||
## Peer Pairing
|
||||
|
||||
Run [big_receiver](../big_receiver/) on a second board.
|
||||
|
||||
1. Flash and run `big_broadcaster` on board A; it begins extended + periodic advertising and creates the BIG immediately.
|
||||
2. Flash and run `big_receiver` on board B; it starts passive extended scanning.
|
||||
3. Board B matches on the device name `"BIG Broadcaster"` and creates a periodic advertising sync to the broadcaster's PA train.
|
||||
4. Once PA-synced, board B receives the BIGInfo report and calls `LE BIG Create Sync` with broadcast code `"1234"` and both BIS in the bitfield.
|
||||
5. Board A logs `[BIS #0/1] Connected` as the controller reports the BIS as established; board B logs `PA synced` followed by per-BIS `Connected` and starts counting received SDUs.
|
||||
6. Resetting either side causes the receiver to drop and (via `pa_sync_lost`) restart its scan, re-establishing the link automatically.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -73,20 +74,21 @@ static void iso_connected_cb(esp_ble_iso_chan_t *chan)
|
||||
.pid = ESP_BLE_ISO_DATA_PATH_HCI,
|
||||
.format = ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT,
|
||||
};
|
||||
int chan_idx = bis_chan_index_get(chan);
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "ISO channel %p connected", chan);
|
||||
ESP_LOGI(TAG, "[BIS #%d] Connected", chan_idx);
|
||||
|
||||
err = esp_ble_iso_setup_data_path(chan, ESP_BLE_ISO_DATA_PATH_DIR_INPUT, &data_path);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to setup ISO data path, err %d", err);
|
||||
ESP_LOGE(TAG, "[BIS #%d] Failed to setup data path, err %d", chan_idx, err);
|
||||
return;
|
||||
}
|
||||
|
||||
connected_bis_count++;
|
||||
|
||||
if (connected_bis_count < BIS_ISO_CHAN_COUNT) {
|
||||
ESP_LOGI(TAG, "Waiting for all BIS channels (%u/%u)",
|
||||
ESP_LOGI(TAG, "Waiting for remaining BIS channels (%u/%u)",
|
||||
connected_bis_count, BIS_ISO_CHAN_COUNT);
|
||||
return;
|
||||
}
|
||||
@@ -100,7 +102,7 @@ static void iso_connected_cb(esp_ble_iso_chan_t *chan)
|
||||
|
||||
err = example_iso_tx_scheduler_start(&chan_tx[i].scheduler, BIG_SDU_INTERVAL_US);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to start tx scheduler[%u], err %d", i, err);
|
||||
ESP_LOGE(TAG, "[BIS #%zu] Scheduler start failed, err %d", i, err);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -110,7 +112,8 @@ static void iso_connected_cb(esp_ble_iso_chan_t *chan)
|
||||
|
||||
static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason)
|
||||
{
|
||||
ESP_LOGI(TAG, "ISO channel %p disconnected, reason 0x%02x", chan, reason);
|
||||
ESP_LOGI(TAG, "[BIS #%d] Disconnected, reason 0x%02x",
|
||||
bis_chan_index_get(chan), reason);
|
||||
|
||||
if (connected_bis_count > 0) {
|
||||
connected_bis_count--;
|
||||
@@ -124,7 +127,7 @@ static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason)
|
||||
for (size_t i = 0; i < BIS_ISO_CHAN_COUNT; i++) {
|
||||
err = example_iso_tx_scheduler_stop(&chan_tx[i].scheduler);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to stop tx scheduler[%u], err %d", i, err);
|
||||
ESP_LOGE(TAG, "[BIS #%zu] Scheduler stop failed, err %d", i, err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,14 +138,16 @@ static void iso_disconnected_cb(esp_ble_iso_chan_t *chan, uint8_t reason)
|
||||
static void iso_sent_cb(esp_ble_iso_chan_t *chan, void *user_data)
|
||||
{
|
||||
int chan_idx = bis_chan_index_get(chan);
|
||||
char name[24];
|
||||
|
||||
if (chan_idx < 0) {
|
||||
ESP_LOGW(TAG, "Unknown BIS channel %p", chan);
|
||||
ESP_LOGW(TAG, "Unknown BIS channel");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "BIS #%d", chan_idx);
|
||||
example_iso_tx_scheduler_on_sent(&chan_tx[chan_idx].scheduler,
|
||||
user_data, TAG, "chan", chan);
|
||||
user_data, TAG, name);
|
||||
}
|
||||
|
||||
static esp_ble_iso_chan_ops_t iso_ops = {
|
||||
@@ -281,7 +286,7 @@ static int ext_adv_start(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Extended adv instance %u started", ADV_HANDLE);
|
||||
ESP_LOGI(TAG, "Advertising started (handle %u)", ADV_HANDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -334,7 +339,7 @@ static void iso_chan_send(int chan_idx)
|
||||
}
|
||||
|
||||
if (bis_iso_chan[chan_idx].iso == NULL) {
|
||||
ESP_LOGW(TAG, "No channel to transmit data, %u", chan_idx);
|
||||
ESP_LOGW(TAG, "[BIS #%d] No channel to transmit", chan_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,8 +352,7 @@ static void iso_chan_send(int chan_idx)
|
||||
sizeof(chan_tx[chan_idx].data),
|
||||
chan_tx[chan_idx].seq_num);
|
||||
if (err) {
|
||||
ESP_LOGD(TAG, "Failed to transmit data on channel 0x%04x",
|
||||
bis_iso_chan[chan_idx].iso->handle);
|
||||
ESP_LOGD(TAG, "[BIS #%d] send failed, err %d", chan_idx, err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -397,7 +401,7 @@ void app_main(void)
|
||||
tx_scheduler_cb,
|
||||
&chan_tx[i]);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to init tx scheduler[%u], err %d", i, err);
|
||||
ESP_LOGE(TAG, "[BIS #%zu] Scheduler init failed, err %d", i, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user