ESP-BLE-ISO 详解:在 ESP-IDF 中使用 BLE 等时信道实现 CIS 与 BIS 流传输
【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf
ESP-BLE-ISO 是 ESP-IDF 蓝牙子系统中专用于Bluetooth LE Isochronous Channels(LE 等时信道)的传输层组件,为上层提供创建/加入 Connected ISO Group(CIG)、创建/同步 Broadcast ISO Group(BIG)、配置 ISO 数据路径以及收发等时数据(如 LC3 音频)的完整 API,是 LE Audio 功能(esp-ble-audio组件)的底层承载。阅读本文后,你将掌握 ESP-BLE-ISO 的两种信道模型(CIS/BIS)、核心 API 与数据结构、Kconfig 配置项,并能基于仓库自带的 four 个官方示例搭建广播(BIG)与单播(CIS)的端到端等时流传输方案。
本文基于当前仓库(ESP-IDF)中的 docs/zh_CN/api-reference/bluetooth/esp-ble-iso.rst(其正文 include 自 docs/en/api-reference/bluetooth/esp-ble-iso.rst),并结合 components/bt/esp_ble_iso 组件源码、examples/bluetooth/esp_ble_iso 示例工程展开。
ESP-BLE-ISO 是什么
ESP-BLE-ISO 提供 Bluetooth LE等时信道(Isochronous Channels)的 API,支持时间同步的、面向连接(CIS)与无连接(BIS)的流传输。该实现构建在蓝牙控制器(Controller)的 ISO 支持之上,设计用于配合 esp-ble-audio 组件使用——也就是说,它是 LE Audio 协议栈的传输底座,本身不包含任何音频编解码或 profile 逻辑。
其核心组件位于 components/bt/esp_ble_iso,源码结构包括:
api/include/esp_ble_iso_common_api.h—— 对外公开的全部宏、类型定义与函数声明(本组件唯一的公共头文件);api/esp_ble_iso_common_api.c—— 公共 API 的 C 实现,内部调用 Zephyr 风格的bt_*/bt_le_*接口;host/—— 双 Host(Bluedroid 与 NimBLE)适配层、GAP/GATT/HCI/L2CAP/ISO 事件处理与 ISO 任务;include/—— 移植自 Zephyr 的蓝牙头文件(zephyr/bluetooth/iso.h等),提供底层数据结构定义;Kconfig.in—— 组件功能开关与内存布局等配置。
两种等时信道模型
| 信道类型 | 英文全称 | 方向 | 前提 | 典型用途 |
|---|---|---|---|---|
| CIS | Connected Isochronous Stream | 双向 | 必须先建立 ACL 连接 | 时间同步的单播音频(LE Audio 通话/音乐) |
| BIS | Broadcast Isochronous Stream | 单向(Broadcaster → Synchronized Receiver) | 无需连接 | 广播音频、群体收听(如助听、场馆广播) |
借助这些 API,你可以:
- 创建或加入 CIG(Connected ISO Group,连接等时组)——由 Central 侧创建、Peripheral 侧通过 ISO Server 接受;
- 创建或同步 BIG(Broadcast ISO Group,广播等时组)——Broadcaster 创建并加密,Synchronized Receiver 通过周期广播(PA)同步并解码;
- 设置 ISO 数据路径(Data Path)——决定等时数据走 HCI 透传还是厂商自定义路径;
- 发送/接收等时数据(SDU)——例如承载 LC3 编码的音频帧。
更上层的 LE Audio profile 与编解码 API 见 esp-ble-audio;架构总览与集成细节见 Bluetooth LE Audio 文档,特别是 ESP-BLE-ISO 架构 一章。
⚠️预览版声明:当前 ESP-BLE-ISO API、数据结构与配置参数在后续版本中可能变更。未来版本可能在不另行通知的情况下引入破坏性改动——例如类型重命名/重组、函数签名修改、字段移除等。在依赖这些接口做产品化时需评估风险。
从源码理解组件架构
在深入 API 之前,先了解 ESP-BLE-ISO 在仓库中的底层运行模型,这对理解回调时机与线程安全至关重要(详见 ble-audio-architecture-iso.rst)。
单一 ISO 任务与全局锁
- ISO 任务(
iso_task):所有位于 Host 栈之上的处理都在这个单一 FreeRTOS 任务中执行。外部通过bt_le_iso_task_post()向它投递工作,投递队列分为三级优先队列(Critical/Normal/Floodable),按优先级严格调度。Critical 级(深 32,满则丢弃最新)承载等时收/发数据路径,保证突发 GAP 上报不会阻塞音频数据;Normal 级(深 64,满则阻塞)承载定时器、GAP 生命周期、GATT 与 ISO HCI 事件;Floodable 级(深 32,满则丢弃最新)承载扩展广播、周期广播与 BIGInfo 上报等大流量尽力而为事件。 - ISO 锁(
bt_le_host_lock):一把全局递归互斥锁,序列化应用线程直接调用公共 API、NimBLE 同步回调与 ISO 任务处理程序对共享状态(连接表、PA sync 表、GATT 订阅表、ISO 簿记)的访问。获取超时会主动abort(),防止带锁竞争。 _safe后缀约定:内部操作成对出现——核心函数假定锁已持有,_safe包装函数先加锁再调用核心函数。公共入口与 ISO 任务外的调用方一律使用_safe变体。
对应用开发者的启示:所有注册的回调(GAP 事件、ISO connected/recv/sent 等)基本都在 ISO 任务上执行,该任务栈仅4 KB,回调内应避免深层调用链与大栈上缓冲,也不要在回调里阻塞等待。
双 Host 适配
组件同时支持 Bluedroid 与 NimBLE 两种 Host,由 Kconfig 在构建期选择(见下文)。bt_前缀符号是 Host 无关接口,定义在host/common;bt_le_bluedroid_*/bt_le_nimble_*是适配层实现,每次构建只编译其一。这一点在示例工程的main/bluedroid/与main/nimble/双份适配文件中体现得很直观(例如 big_broadcaster 的 adv.c 与 nimble 版本)。
ESP-BLE-ISO Common API 详解
ESP-BLE-ISO 的公共 API 全部集中在 esp_ble_iso_common_api.h,划分为:宏定义(BIS 索引与数据路径宏、控制器延迟与间隔上下限)、CIG/BIG 参数与结构体、ISO Server 与信道操作、数据路径设置、BIG 创建/同步/终止、GAP 事件类型与ISO 通用初始化。对应的实现见 esp_ble_iso_common_api.c,其中大部分函数是对 Zephyr 接口的_safe封装,并做了参数校验(ESP_ERR_INVALID_ARG/ESP_ERR_NOT_FOUND/ESP_FAIL等错误码映射)。
常用宏:常量与上下限
组件把控制器/Host 相关的等时参数边界暴露为一组ESP_BLE_ISO_*宏(定义在 esp_ble_iso_common_api.h),供应用在编译期引用,避免硬编码越界。分类如下:
| 类别 | 宏 | 含义 |
|---|---|---|
| BIS 索引 | ESP_BLE_ISO_BIS_INDEX_BIT(x) | 把 1 起始的 BIS 索引转成位域(要同步 BIS 0x01 与 0x02 用BIT(0)\|BIT(1));另有ESP_BLE_ISO_BIS_INDEX_MIN/MAX |
| 数据路径 | ESP_BLE_ISO_DATA_PATH_VS_ID_MIN/MAX | 厂商自定义数据路径 ID 范围 |
| 时序参数 | ESP_BLE_ISO_CONTROLLER_DELAY_MIN/MAX(μs)、ESP_BLE_ISO_SDU_INTERVAL_MIN/MAX(μs)、ESP_BLE_ISO_ISO_INTERVAL_MIN/MAX(N×1.25 ms)、ESP_BLE_ISO_LATENCY_MIN/MAX(ms)、ESP_BLE_ISO_SYNC_TIMEOUT_MIN/MAX(N×10 ms) | 等时时序各参数合法范围 |
| 打包/帧格式 | ESP_BLE_ISO_PACKING_SEQUENTIAL/INTERLEAVED、ESP_BLE_ISO_FRAMING_UNFRAMED/FRAMED | 组内多信道的打包方式与是否成帧 |
| 尺寸 | ESP_BLE_ISO_MIN_SDU/MAX_SDU、ESP_BLE_ISO_CONNECTED_PDU_MIN/BROADCAST_PDU_MIN/PDU_MAX、ESP_BLE_ISO_BN_MIN/MAX、ESP_BLE_ISO_FT_MIN/MAX、ESP_BLE_ISO_NSE_MIN/MAX、ESP_BLE_ISO_MAX_GROUP_ISO_COUNT | SDU/PDU/突发数/刷新超时/子事件数等边界 |
| 重传与加密 | ESP_BLE_ISO_CONNECTED_RTN_MIN/MAX、ESP_BLE_ISO_BROADCAST_RTN_MIN/MAX、ESP_BLE_ISO_BROADCAST_CODE_SIZE(16 字节) | 重传次数与广播码长度 |
| 数据路径方向 | ESP_BLE_ISO_DATA_PATH_DIR_INPUT(Host→Controller,音频输入)、ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT(Controller→Host,音频输出) | setup_data_path 的方向参数 |
| 编码格式 | ESP_BLE_ISO_CODING_FORMAT_TRANSPARENT、ESP_BLE_ISO_CODING_FORMAT_LC3、ESP_BLE_ISO_DATA_PATH_HCI | 透明编码 / LC3 编码 / 数据路径走 HCI |
| 收包状态 | ESP_BLE_ISO_FLAGS_VALID/ERROR/LOST/TS | 接收元数据中包的合法性、错误、丢失与时间戳有效位 |
| PHY | ESP_BLE_ISO_PHY_1M/2M/CODED | 物理层速率 |
| 时钟精度 | ESP_BLE_ISO_SCA_UNKNOWN/251_500/.../0_20 | Peripheral 睡眠时钟精度(Sleep Clock Accuracy) |
| 安全等级 | ESP_BLE_ISO_SECURITY_NONE/NO_MITM/MITM | 对应 BT Security Level 1/2/3 |
| GAP 事件 | ESP_BLE_ISO_GAP_EVENT_EXT_SCAN_RECV/PA_SYNC/PA_SYNC_PAST/PA_SYNC_LOST/ACL_CONNECT/ACL_DISCONNECT/SECURITY_CHANGE/BIGINFO_RECV | ISO 内部使用的应用层 GAP 事件 |
核心结构体
所有公开类型都是对 Zephyr 结构体的 typedef(见 esp_ble_iso_common_api.h),字段语义以 zephyr/bluetooth/iso.h 为准。常用的有:
esp_ble_iso_chan_t(信道):ops(回调)、qos(收发 QoS)、iso(连接引用)、state。见 iso.h#L204-L216。esp_ble_iso_chan_io_qos_t(IO QoS):sdu(SDU 大小)、phy(PHY,不能是 NONE)、rtn(重传次数)、max_pdu、burst_number。见 iso.h#L218-L256。esp_ble_iso_chan_qos_t(信道 QoS):rx/tx指向 IO QoS,置 NULL 即禁用对应方向的数据路径(如纯发送端把rx设为 NULL);num_subevents为每个 CIS/BIS 事件的最大子事件数。见 iso.h#L258-L286。esp_ble_iso_chan_path_t(数据路径):pid(HCI 或厂商路径)、format(编码格式)、cid/vid(厂商编解码 ID)、delay(控制器延迟,μs)、cc_len/cc(编解码配置 LTV 数据)。见 iso.h#L288-L321。esp_ble_iso_cig_param_t(CIG 参数):cis_channels/num_cis、c_to_p_interval/p_to_c_interval(双向 SDU 间隔)、c_to_p_latency/p_to_c_latency、sca(取所有 Peripheral 中最差睡眠时钟精度,未知则用SCA_UNKNOWN)、packing、framing、c_to_p_ft/p_to_c_ft、iso_interval。见 iso.h#L378-L473。esp_ble_iso_big_create_param_t(BIG 创建参数):bis_channels/num_bis、interval(SDU 间隔 μs)、latency、packing、framing、encryption、bcode(16 字节广播码,字符串不足 16 字节时剩余字节填 0)、irc/pto/iso_interval(高级参数)。见 iso.h#L487-L572。esp_ble_iso_big_sync_param_t(BIG 同步参数):bis_channels/num_bis、bis_bitfield(用ESP_BLE_ISO_BIS_INDEX_BIT组装)、mse(最大子事件数,可让控制器自选)、sync_timeout、encryption、bcode。见 iso.h#L574-L631。esp_ble_iso_chan_ops_t(信道回调):connected、disconnected(携带 BT_HCI_ERR_* reason)、alloc_buf、recv(携带esp_ble_iso_recv_info_t元数据)、sent(携带 user_data)。见 iso.h#L678-L749。esp_ble_iso_server_t(ISO Server):accept回调,Peripheral 侧在收到新 CIS 请求时被调用,应用在此决定是否接受并交出信道对象。见 iso.h#L771-L784。esp_ble_iso_accept_info_t:包含请求授权的 ACL 连接、Central 侧的cig_id与cis_id。见 iso.h#L751-L769。esp_ble_iso_recv_info_t:接收元数据——ts(时间戳,仅当 flags 含ESP_BLE_ISO_FLAGS_TS时有效)、seq_num、flags(VALID/ERROR/LOST/TS 位域)。见 iso.h#L347-L361。esp_ble_iso_biginfo_t:BIGInfo 上报内容——广播地址/SID、BIS 数量、子事件数、ISO 间隔、突发数、预传输偏移、重复次数、最大 PDU/SDU、PHY、framing、加密标志。见 iso.h#L633-L676。esp_ble_iso_ext_adv_info_t:BIG 关联的扩展广播信息(adv_handle、地址类型、地址、sid),为 ESP 扩展类型,见 esp_ble_iso_common_api.h#L288-L293。
公共函数一览
| 函数 | 作用 | 关键实现点(esp_ble_iso_common_api.c) |
|---|---|---|
esp_ble_iso_data_parse() | 解析 LTV 编码数据,逐元素回调 | 校验ltv/func非空;元素格式[len][type][value...];回调返回 false 即中止解析并返回ESP_FAIL,见 L11-L54 |
esp_ble_iso_server_register()/unregister() | 注册/注销 ISO Server(仅 Peripheral) | 受CONFIG_BT_ISO_PERIPHERAL门控 |
esp_ble_iso_cig_create()/reconfigure()/terminate() | 创建/重配/终止 CIG(仅 Central) | 受CONFIG_BT_ISO_CENTRAL门控,最终调用bt_iso_cig_*_safe |
esp_ble_iso_chan_connect() | 建立 CIS(仅 Central) | 参数为 NULL 或 count 为 0 返回ESP_ERR_INVALID_ARG;按conn_handle查找 ACL 连接,找不到返回ESP_ERR_NOT_FOUND,找到则把acl填入每个connect_param后调用bt_iso_chan_connect,见 L122-L153 |
esp_ble_iso_chan_disconnect() | 断开 ISO 信道 | 受CONFIG_BT_ISO_UNICAST门控 |
esp_ble_iso_setup_data_path()/remove_data_path() | 设置/移除信道数据路径 | 校验方向必须是 INPUT/OUTPUT(valid_dir);CIS 需在connected回调中调用;广播信道仅 INPUT、同步接收仅 OUTPUT |
esp_ble_iso_big_register_cb() | 注册广播源回调 | 受CONFIG_BT_ISO_BROADCAST门控 |
esp_ble_iso_big_ext_adv_add()/delete() | 为 BIG 添加/删除扩展广播(仅 Broadcaster) | 基于adv_handle调用bt_le_ext_adv_new_safe/delete_safe |
esp_ble_iso_big_create() | 创建 BIG(仅 Broadcaster) | 用adv_handle查找扩展广播对象,找不到返回ESP_ERR_NOT_FOUND |
esp_ble_iso_big_sync() | 同步 BIG(仅 Synchronized Receiver) | 用sync_handle查 PA sync,找不到返回ESP_ERR_NOT_FOUND |
esp_ble_iso_big_terminate() | 终止 BIG | 同时清除关联数据路径 |
esp_ble_iso_chan_get_info() | 查询信道信息 | — |
esp_ble_iso_chan_get_tx_sync()/send()/send_ts() | 获取 TX 同步信息、发送 SDU(可带时间戳) | send内部构造net_buf后调用bt_iso_chan_send_safe;sdu与sdu_len必须同时非空/为空,否则ESP_ERR_INVALID_ARG,见 L352-L399 |
esp_ble_iso_gap_app_post_event() | 投递应用层 GAP 事件(仅 NimBLE 需要) | 直接转发bt_le_gap_app_post_event |
esp_ble_iso_common_init() | ISO 通用初始化 | 注册gap_cb后调用bt_le_host_init();失败时回滚注销,见 L407-L435 |
esp_ble_iso_bluedroid_get_gattc_if() | 获取 Bluedroid 引擎内部 GATTC 接口句柄 | 传给esp_ble_gattc_aux_open()使 ACL 事件路由回引擎;GATTC 未注册完成时返回ESP_GATT_IF_NONE(0xFF),见 L437-L442 |
数据路径的生命周期(重要细节)
关于esp_ble_iso_remove_data_path(),头文件注释 给出了与蓝牙核心规范 6.0 对齐的规则:
- CIS(Peripheral 侧):CIS 断开后数据路径由控制器自动删除,Peripheral 无需(也无法)手动移除;
- CIS(Central 侧):断开后数据路径仍有效,Central 若不打算再使用该 CIS,应在断开时主动调用
esp_ble_iso_remove_data_path();CIG 被esp_ble_iso_cig_terminate()终止时,Central 创建的全部数据路径随之清除; - BIG(Synchronized Receiver 侧):BIG sync 丢失或终止时由控制器删除数据路径,无需手动处理;
- BIG(Broadcaster 侧):BIG 被
esp_ble_iso_big_terminate()终止时全部数据路径随之清除。
esp_ble_iso_setup_data_path()必须在信道已关联 BIS/CIS 句柄之后调用——也就是在esp_ble_iso_chan_ops_t.connected()回调中调用(见 头文件说明)。
Kconfig 配置:功能开关与资源预算
ESP-BLE-ISO 的所有功能开关定义在 components/bt/esp_ble_iso/Kconfig.in,由CONFIG_BT_ISO_*前缀控制:
| 配置项 | 说明 |
|---|---|
BT_ISO | 总开关,自动被 UNICAST/BROADCAST 选中;自动选择对应 Host 的 ISO 支持 |
BT_ISO_TX/BT_ISO_RX | 等时发送 / 接收能力 |
BT_ISO_UNICAST | 单播等时(CIS)支持,隐式开启 TX+RX |
BT_ISO_PERIPHERAL | CIS Peripheral 角色支持 |
BT_ISO_CENTRAL | CIS Central 角色支持 |
BT_ISO_BROADCAST | 广播等时(BIS)支持 |
BT_ISO_BROADCASTER | Broadcaster 角色支持(隐式开启 TX) |
BT_ISO_SYNC_RECEIVER | Synchronized Receiver 角色支持(隐式开启 RX) |
BT_ISO_MAX_CHAN | 最大同时 ISO 信道数,默认 1,范围 1–64 |
BT_ISO_MAX_CIG | 最大 CIG 数(Bluedroid 下 1–2,默认 1;NimBLE 下取BT_NIMBLE_ISO_CIG) |
BT_ISO_MAX_BIG | 最大 BIG 数(Bluedroid 下 1–2,默认 1;NimBLE 下取BT_NIMBLE_ISO_BIG),一个 BIG 同一时刻只能用于发送或接收 |
BT_ISO_TEST_PARAMS | ISO 测试参数支持(默认 Bluedroid 开启),允许 Host 设置通常由控制器控制的参数 |
BT_ISO_BSS_SEG_EXTERNAL_MEMORY | 把组件.bss段放入外部 SPIRAM(需SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) |
BT_ISO_HEAP_EXTERNAL_MEMORY | 控制面堆分配走 SPIRAM;实时数据路径(TX/RX SDU 缓冲)仍留在内部 DRAM |
BT_ISO_DISPATCH_MONITOR | ISO 任务回调分发延迟监控(默认关),配合BT_ISO_DISPATCH_THRESHOLD_US(默认 2000 μs)与BT_ISO_DISPATCH_DUMP_PERIOD_S(默认 10 s)使用 |
BT_ISO_NO_LOG/BT_ISO_LOG_LEVEL | 关闭 ISO 调试日志或设置日志级别(同时影响 esp_ble_audio 的LEA_*日志) |
以官方示例 big_broadcaster/sdkconfig.defaults 为例,一个典型的 BIS 广播端最小配置是:
CONFIG_BT_ENABLED=y CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_CONTROLLER_ENABLED=y CONFIG_BT_BLE_ENABLED=y CONFIG_BT_BLE_50_FEATURES_SUPPORTED=y CONFIG_BT_BLE_FEAT_ISO_EN=y CONFIG_BT_ISO_BROADCASTER=y CONFIG_BT_ISO_MAX_CHAN=2如需在 PSRAM 目标上释放内部 RAM,可打开SPIRAM并启用BT_ISO_BSS_SEG_EXTERNAL_MEMORY/BT_ISO_HEAP_EXTERNAL_MEMORY(见该文件 L21-L26 注释)。
官方示例:从广播到单播的完整链路
官方提供了四个配对示例(examples/bluetooth/esp_ble_iso),支持 ESP32-H4 / ESP32-S31 等带 BLE 5.2 ISO 能力的芯片,构建时通过 Kconfig 在 NimBLE 与 Bluedroid 之间二选一:
| 示例 | 角色 | 演示内容 |
|---|---|---|
big_broadcaster | Broadcaster | 创建 BIG 并通过 BIS 发送等时数据 |
big_receiver | Synchronized Receiver | 同步 BIG 并从 BIS 接收等时数据 |
cis_central | CIS Central | 创建 CIG/CIS 并发送等时数据 |
cis_peripheral | CIS Peripheral | 接受 CIS 并接收等时数据 |
这四个示例共享common_components/下的example_init(BLE 初始化)与example_utils(TX 调度器、RX 统计等工具),方便直接对照学习。
BIG 广播链路:big_broadcaster ↔ big_receiver
big_broadcaster(核心逻辑见 main/main.c)的流程是:
- 初始化 NVS(存放 PHY 校准数据)→
bluetooth_init()→app_host_init()→esp_ble_iso_common_init(); - 为 2 个 BIS 信道各初始化一个软件 TX 调度器(注释明确说明
esp_timer精度不够,必须用调度器保证 10 ms 节拍); - 配置并启动扩展广播 + 周期广播(handle 0,非连接、非可扫描,主信道 1M / 次信道 2M);
esp_ble_iso_big_ext_adv_add()把广播句柄绑定到 BIG,再用esp_ble_iso_big_create()下发 HCILE Create BIG:2 个 BIS、加密开启、广播码"1234"(最多 16 字节,不足部分补 0);- 每个 BIS 就绪后,
connected回调安装 HCI 输入数据路径(ESP_BLE_ISO_DATA_PATH_DIR_INPUT+ 透明编码); - 两个 BIS 全部连接后,调度器每 10 ms 触发一次
esp_ble_iso_chan_send(),发送 120 字节哑元 SDU(内容为序号字节值),seq_num自增; - 全部 BIS 断开时停止调度器并清空 BIG 句柄。
关键参数(硬编码于 main.c):BIG_SDU_INTERVAL_US = 10000、BIG_LATENCY_MS = 10、BIG_PHY = ESP_BLE_ISO_PHY_2M、BIG_RTN = 2、BIG_PACKING = 0(sequential)、BIG_FRAMING = 0(unframed)、BIS_ISO_CHAN_COUNT = 2、BIS_SDU_SIZE = 120、BIG_ENCRYPTION = true。
big_receiver(核心逻辑见 main/main.c)走的是"扫描发现 → PA 同步 → BIGInfo → BIG Create Sync"的经典链路:
- 在
esp_ble_iso_common_init()注册gap_cb,处理四类 GAP 事件:EXT_SCAN_RECV、PA_SYNC、PA_SYNC_LOST、BIGINFO_RECV; EXT_SCAN_RECV中先用esp_ble_iso_data_parse()解析广播数据里的完整设备名,匹配"BIG Broadcaster"后调用pa_sync_create()建立 PA sync;PA_SYNC成功后停止扩展扫描(后续 BIGInfo 会经由 PA 信道到达);BIGINFO_RECV中组装esp_ble_iso_big_sync_param_t:bis_bitfield = BIT_MASK(2)、mse = event->biginfo_recv.nse、sync_timeout = 100(100×10 ms = 1 s)、encryption与bcode取自 BIGInfo/本地配置,然后调用esp_ble_iso_big_sync();- 每个 BIS 就绪后
connected回调安装输出数据路径(ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT),recv回调统计收到的 SDU 并打印[BIS #N] Connected; PA_SYNC_LOST时复位状态并重启扫描,自动重连。
接收端断开原因注释值得注意:0x08(CONN_TIMEOUT,广播方消失/超出范围,常见)与0x3D(TERM_DUE_TO_MIC_FAIL,加密 BIG 下广播方在超时窗口内重启导致旧会话密钥失效,低概率),两者都是正常现象,接收方会重新发现。
编译烧录(默认 Bluedroid Host,目标 ESP32-H4):
idf.py set-target esp32h4 idf.py -p PORT flash monitor使用 NimBLE Host(叠加sdkconfig.defaults.nimble):
idf.py set-target esp32h4 idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32h4;sdkconfig.defaults.nimble" -p PORT flash monitorESP32-S31 目标替换对应的 chip overlay(sdkconfig.defaults.esp32s31)即可。串口监视器用Ctrl-]退出。
预期日志(标签BIG_BRD):
I (xxx) BIG_BRD: Advertising started (handle 0) 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 I (xxx) BIG_BRD: [BIS #0] TX: <N> packets I (xxx) BIG_BRD: [BIS #1] TX: <N> packets I (xxx) BIG_BRD: [BIS #0] Disconnected, reason 0x<rr> I (xxx) BIG_BRD: All BIS channels disconnected, TX stoppedCIS 单播链路:cis_central ↔ cis_peripheral
cis_central(核心逻辑见 main/main.c)演示 Central 主动建链:
- 扫描发现
"CIS Peripheral"后建立 ACL 连接(EXT_SCAN_RECV→conn_create),随后触发ACL_CONNECT; - 按安全等级(
ESP_BLE_ISO_SECURITY_NO_MITM,即 L2 加密)发起配对,SECURITY_CHANGE成功后进入建链流程; create_cig_and_cis()填充esp_ble_iso_cig_param_t(双向间隔 10 ms、双向延迟 10 ms、sca = ESP_BLE_ISO_SCA_UNKNOWN、sequential packing、unframed),先esp_ble_iso_cig_create(),再esp_ble_iso_chan_connect()下发LE Create CIS;- CIS 就绪后
connected回调安装输入数据路径并启动 10 ms TX 调度器,循环esp_ble_iso_chan_send()发送 120 字节哑元数据; - 断开处理中演示了 Central 侧必须显式移除数据路径的规范要求(对比 Peripheral 由控制器自动删除,见 main.c 注释)。
cis_peripheral(核心逻辑见 main/main.c)演示被动接受 CIS:
- 注册
esp_ble_iso_server_t(.accept回调);收到新 CIS 请求时检查信道是否空闲,空闲则交出iso_chan,否则返回-ENOMEM拒绝(见 L80-L97); - 通过
esp_ble_iso_server_register()注册 Server; ACL_CONNECT后等待 Central 的 CIS 建立请求,connected回调安装输出数据路径(ESP_BLE_ISO_DATA_PATH_DIR_OUTPUT),recv回调统计并打印收到的 SDU;ACL_DISCONNECT时重新开始扩展广播,等待下一次连接。
收发数据路径与元数据语义
无论 CIS 还是 BIS,等时数据的收发都围绕SDU(Service Data Unit)展开:
- 发送:
esp_ble_iso_chan_send(chan, sdu, sdu_len, seq_num)或带时间戳的esp_ble_iso_chan_send_ts(chan, sdu, sdu_len, seq_num, ts)。seq_num由应用维护并自增,供接收端按序重组与丢包检测。sent回调在控制器标记 SDU 完成时触发(何时标记由控制器实现决定,可能是在入队、空中发出或刷新之后),因此不能以sent回调作为真正的发送完成时刻。 - 接收:
recv(chan, info, data, len)中,esp_ble_iso_recv_info_t提供三个关键元数据:seq_num——SDU 首个分片的包序号;flags——ESP_BLE_ISO_FLAGS_VALID(有效)/ERROR(CRC 失败或 SDU 不完整,可能含错)/LOST(丢包)/TS(时间戳有效);ts——ISO 时间戳,仅当flags含TS位时才有效,是音频渲染对齐(音画同步、多设备同步)的基础。
- TX 同步信息:Central/Broadcaster 可通过
esp_ble_iso_chan_get_tx_sync()获取esp_ble_iso_tx_info_t(CIG/BIG anchor 点时间ts、时间偏移offset、包序号),用于精确规划发送时隙。
硬件约束提示:BIG/CIG 的调度由控制器基于 ISO anchor 点驱动,应用层的 10 ms 发送节拍必须由高精度软件调度器承担(示例中封装为
example_iso_tx_scheduler_t),仓库示例注释明确指出现有esp_timer精度不足以直接驱动等时发送。
典型错误处理与调试建议
- 参数校验:公共 API 对 NULL 指针、非法方向(
setup_data_path的dir不是 INPUT/OUTPUT)、chan_send中sdu/sdu_len不一致等场景返回ESP_ERR_INVALID_ARG;找不到 ACL/PA sync/扩展广播对象时返回ESP_ERR_NOT_FOUND;底层 Zephyr 接口失败统一映射为ESP_FAIL。 - CIS 断开后 Central 的数据路径残留:必须按规范在断开回调中显式
esp_ble_iso_remove_data_path(),否则复用同一 CIS 时控制器会返回 Command Disallowed(示例 cis_central 有完整注释)。 - 加密广播失步:
0x3D(MIC 校验失败)通常意味着广播方以新会话密钥重启而接收方尚未超时,属正常现象,接收方会走PA_SYNC_LOST重发现流程。 - 调试工具:
CONFIG_BT_ISO_DISPATCH_MONITOR用于定位在 ISO 任务上耗时过长的回调(默认 2000 μs 阈值);CONFIG_BT_ISO_NO_LOG可裁剪日志以节省 rodata;CONFIG_BT_DEBUG_ISO_DATA可开启所有 ISO 收发数据的调试日志。 - 内存规划:
CONFIG_BT_ISO_MAX_CHAN、BT_ISO_MAX_CIG、BT_ISO_MAX_BIG决定 Host 侧资源;大并发信道或大量 SDU 缓冲时,可借助BT_ISO_BSS_SEG_EXTERNAL_MEMORY/BT_ISO_HEAP_EXTERNAL_MEMORY将控制面搬入 SPIRAM,但实时数据路径(TX/RX SDU 缓冲)始终保留在内部 DRAM。
小结
ESP-BLE-ISO 把 BLE 等时信道的复杂性(CIG/BIG 生命周期、数据路径、双 Host 适配、任务调度与线程安全)封装为一套简洁的esp_ble_iso_*API。上手路径很清晰:先用big_broadcaster+big_receiver验证广播链路,再用cis_central+cis_peripheral验证单播链路,然后以 esp_ble_iso_common_api.h 为索引、以 Kconfig.in 为资源预算表,替换哑元数据为真实 LC3 音频流,即可过渡到上层 esp-ble-audio 的完整 LE Audio 应用。由于当前为预览版本,请留意后续版本中的 API 变更公告。
【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考