【Nordic博文分享系列】LEAudioBIS模式流程解析

Nordic半导体 2023-10-13 17:01



作者:Steed Li, Nordic Semiconductor

在LE Audio中,Broadcast Isochronous Streams,简称BIS,即基于广播的同步音频流。与CIS不同,在BIS中,传输同步音频流的设备不知道可能有多少个设备在接收音频。设备之间没有连接,没有应答,也不需要 ACL 链路。广播音频的好处在于它允许多个设备同时监听一个广播音源,类似FM广播,其主要应用场景是在公共场所中的一群人可以佩戴耳机来共同收听音频信息。

不管是CIS还是BIS模式,都需BAP中定义的各项流程,如发送广播,接收广播音频和单播音频。接下来我们重点了解BAP中BIS广播音频的配置和建立流程,并尝试在BIS模式下,加入ACL连接和NUS服务。

BAP即Basic Audio Profile,它在GATT和GAP的基础上,定义了音频流控制的各项基本流程。BAP是实现在低功耗蓝牙上进行高效音频通信的重要组件。

广播音源设备通过BIG中的BISes来传输广播音频,与此同时,广播音源设备也会广播EA (扩展广播)PDU和PA(周期性广播) PDU。

扩展广播:

  • ADV_EXT_IND PDU——扩展广播PDU

  • AUX_ADV_IND PDU——辅助广播PDU

  • AUX_CHAIN_IND PDU——辅助链广播PDU(可选)

周期性广播:

  • AUX_SYNC_IND PDU——周期性同步广播PDU

ADV_EXT_IND PDU在37,38,39主频段进行广播,它的扩展头字段包含一个AuxPtr字段,其中包含使其能够与辅助AUX_ADV_IND PDU同步的数据。ADV_EXT_IND PDU的AuxPtr字段指向AUX_ADV_IND,即AuxPtr的值指向ADV_EXT_IND PDU广播所在的其余0~36个频段中的一个。


AUX_ADV_IND PDU的扩展头字段包含一个SyncInfo字段,其中包含使其能够与PA同步的数据。AUX_ADV_IND PDU的SyncInfo字段指向PA。

AUX_ADV_IND PDU还包含一个AdvData字段,其中包含了Broadcast Audio Announcement Service UUID和Broadcast_ID。Broadcast Audio Announcement Service UUID将PA与包含一个或多个BISes的BIG关联起来,Broadcast_ID用于帮助扫描设备确定当前EA指向的PA所指向的BIG是否它需要同步的BIG。

ADV_EXT_IND PDU和从属于它的AUX_ADV_IND PDU,都属于一个广播集合,不同的广播集合由这些PDU中的SID来指定。

周期性广播(PA)由AUX_SYNC_IND PDU和AUX_CHAIN_IND PDU(可选)组成。这里主要讨论AUX_SYNC_IND PDU。

AUX_SYNC_IND PDU的header中有一个AdvData字段,其中包含Service Data AD data type。

Service Data AD data type包 Basic Audio Announcement Service UUID,其广播内容描述一个或多个广播音频流的BASE配置,BASE用于告知扫描设备,BIG中的音频流参数,比如是哪一种Codec,Codec参数,采样频率等等。

AUX_SYNC_IND PDU扩展头字段可能携带一个ACAD字段,其中包含BIGInfo。BIGInfo数据使得可以与包含一个或多个用于传输广播音频流的BIS的BIG进行同步。因此,BIGInfo提供了接收广播音频流所需的信息。BIGInfo指向相应的BIG。

了解了以上提到的广播的PDU后,我们再来看看这些PDU的相互关系。

如上图所示,首先,在37,38,39三个主广播信道广播ADV_EXT_IND。每个BIG都需要拥有自己的广告集(advertising set)和ADV_EXT_IND。每个ADV_EXT_IND的header域都包括广告地址(AdvA),ADI(其中包括用于此组扩展广播的Set ID),以及指向AUX_ADV_IND的指针AuxPtr。

然后,在0~36个频段广播AUX_ADV_IND PDU,它们包含了描述某个特定的BIG的广告数据。AUX_ADV_IND还包括SyncInfo字段,该字段为扫描设备提供了同步AUX_SYNC_IND的信息。

最后,在辅助同步信息AUX_SYNC_IND PDU中,包含两个重要的信息。第一个是ACAD(Additional Controller Advertising Data),描述BIG及其组成的BIS的结构,也就是之前提到的BIG info。第二个是提供给接收设备信息,包含在AdvData字段中,也就是之前提到的BASE。AdvData字段包含基本音频公告服务UUID和BASE,其中包含BIG中音频流的详细定义,包括编解码器配置和元数据,以用户可读的格式描述音频流的用例和内容。

接下来我们通过抓包来更直观地观察上述广播的过程:

首先任意挑选一个ADV_EXT_IND PDU包,通过AuxPtr找到属于它的AUX_ADV_IND PDU所在的频段6和偏移位置2.07ms。

然后通过AUX_ADV_IND PDU中的Header中的Sync info字段信息,找到属于它的AUX_SYNC_IND PDU,这里是偏移大约31.83ms。

再来看这个AUX_SYNC_IND包中,对BIG的描述信息的解读,主要在BIG info中:

BIG Offset——对应的BIG的偏移位置,这里大约为960us。

ISO interval——ISO间隔,也就是BIG的间隔,10ms。

Sub Interval —— 354us, Sub event的间隔。

BIS Spacing —— 相邻两组BISes的起始点的间距,这里大约为1.062ms。

  • Num BIS —— 2,BIS的组数2,即有两组BISes。

  • NSE —— 3,在一个BIG里面,每组BIS的sub event的数量。

  • Max PDU —— 40,BIS PDU最大字节数。

  • SDU Interval —— 10ms,可等同理解为ISO Interval。

  • Max SDU Size —— 40,BIG中每个SDU最大字节数,可等同理解为Max PDU。

BN,PTO,IRC控制着BIG事件中有哪些数据被传输。

BAP中定义了广播设备的状态机,并包含以下几个流程:

  • The Broadcast Audio Stream configuration procedure —— 广播音频流配置

  • The Broadcast Audio Stream establishment procedure —— 广播音频流建立

  • The Broadcast Audio Stream disable procedure —— 广播音频流关闭

  • The Broadcast Audio Stream Metadata update procedure —— 广播音频流元数据更新

  • The Broadcast Audio Stream release procedure —— 广播音频流释放

  • The Broadcast Audio Stream reconfiguration procedure —— 广播音频流重配置

下面我们结合nRF Connect SDK中LE Audio的应用代码来解析一个广播音频流的建立过程:

  • 配置BASE,将其添加到周期性广播(PA)的广播数据(adv_data)中。

int bt_bap_broadcast_source_get_base(struct bt_bap_broadcast_source *source,    struct net_buf_simple *base_buf){    CHECKIF(source == NULL) {        LOG_DBG("source is NULL");        return -EINVAL;    }
   CHECKIF(base_buf == NULL) {        LOG_DBG("base_buf is NULL");        return -EINVAL;    }
   if (!encode_base(source, base_buf)) {        LOG_DBG("base_buf %p with size %u not large enough", base_buf, base_buf->size);        return -EMSGSIZE;    }    return 0;}
/* Setup periodic advertising data */ret = bt_bap_broadcast_source_get_base(broadcast_source, &base_buf);
if (ret) {    LOG_ERR("Failed to get encoded BASE: %d", ret);    return ret;}
per_ad.type = BT_DATA_SVC_DATA16;per_ad.data_len = base_buf.len;per_ad.data = base_buf.data;
ret = bt_le_per_adv_set_data(adv, &per_ad, 1);
if (ret) {    LOG_ERR("Failed to set periodic advertising data: %d", ret);    return ret;}
  • 建立BIG

/* Create BIG */param.num_bis = bis_count;param.bis_channels = bis;param.framing = source->qos->framing;param.packing = source->packing;param.interval = source->qos->interval;param.latency = source->qos->latency;param.encryption = source->encryption;
if (param.encryption) {    (void)memcpy(param.bcode, source->broadcast_code,        sizeof(param.bcode));
}
err = bt_iso_big_create(adv, ¶m, &source->big);
if (err != 0) {    LOG_DBG("Failed to create BIG: %d", err);    return err;}
  • 设置扩展广播和周期性广播

int le_audio_enable(le_audio_receive_cb recv_cb, le_audio_timestamp_cb timestmp_cb){    int ret;    ARG_UNUSED(recv_cb);    LOG_INF("Starting broadcast gateway %s", CONFIG_BT_AUDIO_BROADCAST_NAME);    ret = initialize(timestmp_cb);
   if (ret) {        LOG_ERR("Failed to initialize");        return ret;    }
   service_init();    advertising_start();
   /* Start extended advertising */    ret = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
   if (ret) {        LOG_ERR("Failed to start extended advertising: %d", ret);        return ret;    }
   /* Enable Periodic Advertising */    ret = bt_le_per_adv_start(adv);
   if (ret) {        LOG_ERR("Failed to enable periodic advertising: %d", ret);        return ret;    }
   /*    ret = bt_le_ext_adv_start(adv_conn, BT_LE_EXT_ADV_START_DEFAULT);
   if (ret) {        LOG_ERR("Failed to start connectable extended advertising: %d", ret);        return ret;    }    */
   LOG_DBG("Starting broadcast source");    ret = bt_bap_broadcast_source_start(broadcast_source, adv);
   if (ret) {        return ret;    }
   LOG_DBG("LE Audio enabled");
   return 0;}
  • 建立广播音频流

当扩展广播和周期性广播开始运行的时候,就要开始建立一个广播音频流。首先进入同步广播模式(Broadcast Isochronous Broadcasting Mode ),为发送BISes PDU做准备,然后开启Broadcast Isochronous Synchronizability Mode,在周期性广播(PA)中发送BIGinfo,通知所有扫描设备其所携带的BIG和BIS的信息。最后通过the LE Setup ISO Data Path HCI command来设置广播音频流的路径。

if (IS_ENABLED(CONFIG_BT_ISO_BROADCASTER) &&    iso->iso.info.type == BT_ISO_CHAN_TYPE_BROADCASTER && in_path) {
   dir = BT_HCI_DATAPATH_DIR_HOST_TO_CTLR;    err = hci_le_setup_iso_data_path(iso, dir, in_path);
   if (err != 0) {        LOG_DBG("Failed to set broadcaster data path: %d", err);    }
   return err;
} else if (IS_ENABLED(CONFIG_BT_ISO_SYNC_RECEIVER) &&        iso->iso.info.type == BT_ISO_CHAN_TYPE_SYNC_RECEIVER &&        out_path) {
   dir = BT_HCI_DATAPATH_DIR_CTLR_TO_HOST;    err = hci_le_setup_iso_data_path(iso, dir, out_path);
   if (err != 0) {        LOG_DBG("Failed to set sync receiver data path: %d", err);    }}

接下来我们尝试在BIS模式下的gateway添加NUS服务。

应用场景:在广播数据的过程中,需要将数据上传到BLE主机,比如老师在教学过程中,将教学信息上传到蓝牙网关。

实现:参考peripheral_uart的例子。首先,建立一个可连接的扩展广播,并初始化广播参数和广播包内容。

static int adv_create(void){    int ret;
   /* Broadcast Audio Streaming Endpoint advertising data */    NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
   /* Buffer for Public Broadcast Announcement */    NET_BUF_SIMPLE_DEFINE(base_buf, 128);
   #if (CONFIG_AURACAST)        NET_BUF_SIMPLE_DEFINE(pba_buf, BT_UUID_SIZE_16 + 2);        struct bt_data ext_ad[4];        uint8_t pba_features = 0;    #else        struct bt_data ext_ad[3];    #endif /* (CONFIG_AURACAST) */
   struct bt_data per_ad;    uint32_t broadcast_id = 0;
   /* Create a non-connectable non-scannable advertising set */    ret = bt_le_ext_adv_create(LE_AUDIO_EXTENDED_ADV_NAME, NULL, &adv);
   if (ret) {        LOG_ERR("Unable to create extended advertising set: %d", ret);        return ret;    }
   /* Create a connectable scannable advertising set */    ret = bt_le_ext_adv_create(LE_AUDIO_EXTENDED_ADV_CONN_NAME, NULL, &adv_conn);
   if (ret) {        LOG_ERR("Unable to create connectable extended advertising set: %d", ret);        return ret;    }}
static const struct bt_data ad_peer[] = {
   BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),    BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL)
   };

开启广播:

int le_audio_enable(le_audio_receive_cb recv_cb, le_audio_timestamp_cb timestmp_cb){    int ret;    ARG_UNUSED(recv_cb);    LOG_INF("Starting broadcast gateway %s", CONFIG_BT_AUDIO_BROADCAST_NAME);    ret = initialize(timestmp_cb);
   if (ret) {        LOG_ERR("Failed to initialize");        return ret;    }
   service_init();    advertising_start();}

然后,初始化NUS服务:

int service_init(void){    int err = 0;    err = uart_init();
   if (err) {        LOG_ERR("Failed to initialize UART driver (err: %d)", err);        return 0;    }
   LOG_INF("Bluetooth initialized");    k_sem_give(&ble_init_ok);
   /*if (IS_ENABLED(CONFIG_SETTINGS)) {        settings_load();    }*/
   err = bt_nus_init(&nus_cb);
   if (err) {        LOG_ERR("Failed to initialize UART service (err: %d)", err);        return 0;    }
   return 0;}

注册蓝牙连接回调事件:

static struct bt_conn_cb conn_callbacks = {    .connected = connected_cb,    .disconnected = disconnected_cb,//  .security_changed = security_changed_cb,};

在connected回调事件中,请求连接参数更新,这一步很重要,因为LE audio的controller中 广播音频流的优先级是最高的,在广播音频流传输的过程中很容易打断ACL连接,之前已经知道iso interval为10ms,因此这里把ACL的连接间隔调整到100~200ms。

static void connected_cb(struct bt_conn *conn, uint8_t err){    int ret;    char addr[BT_ADDR_LE_STR_LEN];    uint16_t conn_handle;    enum ble_hci_vs_tx_power conn_tx_pwr;
   struct bt_le_conn_param param = {        .interval_min = 80,        .interval_max = 160,        .latency = 2,        .timeout = 400,    };
   LOG_INF("Request conn param min=%d max=%d", param.interval_min, param.interval_max);    bt_conn_le_param_update(conn, ¶m);
   if (err) {        default_conn = NULL;        return;    }
   bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));    LOG_INF("Connected: %s", addr);    ret = bt_hci_get_conn_handle(conn, &conn_handle);
   if (ret) {        LOG_ERR("Unable to get conn handle");    } else {
       #if (CONFIG_NRF_21540_ACTIVE)            conn_tx_pwr = CONFIG_NRF_21540_MAIN_DBM;        #else            conn_tx_pwr = CONFIG_BLE_CONN_TX_POWER_DBM;        #endif /* (CONFIG_NRF_21540_ACTIVE) */
       ret = ble_hci_vsc_conn_tx_pwr_set(conn_handle, conn_tx_pwr);
       if (ret) {            LOG_ERR("Failed to set TX power for conn");        } else {            LOG_DBG("TX power set to %d dBm for connection %p", conn_tx_pwr, (void *)conn);            }    }
   default_conn = bt_conn_ref(conn);}

将代码烧录到Nordic audio DK,打开手机的nRF Connect app,可以看到有一个可连接广播和一个不可连接广播,连接到可连接广播,即可发现NUS服务并与手机进行数据通信。

观看网络研讨会:LE Audio BIS 模式流程解析

本文相关链接

LE Audio BIS 模式流程解析:https://www.nordicsemi.cn/news/le-audio-bis-video/


参考文献

① Basic Audio Profile v1.0.1:https://www.bluetooth.com/specifications/specs/basic-audio-profile-1-0-1/

② Bluetooth Core Specification v5.2:https://www.bluetooth.com/specifications/specs/core-specification-5-2/

③ Introducing-Bluetooth-LE-Audio-boo:https://www.bluetooth.com/bluetooth-resources/le-audio-book/

【联系我们】

中文官网:www.nordicsemi.cn

英文官网:www.nordicsemi.com

微信公众号:nordicsemi


【Nordic 开发者论坛】

https://devzone.nordicsemi.com


【销售接洽】

北京分公司: +86 010 8438 2767

上海分公司: +86 21 6330 0620

深圳分公司: +86 755 8322 0147

sales.cn@nordicsemi.no


按下方提示星标 Nordic🌟

以免错过半导体行业深度好文👇




点击阅读原文” 进入Nordic半导体中文官网

Nordic半导体 Nordic 半导体开发支持蓝牙智能、ANT+和2.4GHz应用的超低功耗短距无线通信技术,用于物联网 、可穿戴产品、智能家居、玩具等应用。Nordic 提供现成可用的设计框架、世界级文档资料和支持,以加快专业工程师和业余爱好者的开发速度。
评论
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 200浏览
  • 书接上回:【2022年终总结】阳光总在风雨后,启航2023-面包板社区  https://mbb.eet-china.com/blog/468701-438244.html 总结2019,松山湖有个欧洲小镇-面包板社区  https://mbb.eet-china.com/blog/468701-413397.html        2025年该是总结下2024年的喜怒哀乐,有个好的开始,才能更好的面对2025年即将
    liweicheng 2025-01-24 23:18 40浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 206浏览
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 97浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 391浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 137浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 157浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 800浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 170浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 737浏览
  • 飞凌嵌入式基于瑞芯微RK3562系列处理器打造的FET3562J-C全国产核心板,是一款专为工业自动化及消费类电子设备设计的产品,凭借其强大的功能和灵活性,自上市以来得到了各行业客户的广泛关注。本文将详细介绍如何启动并测试RK3562J处理器的MCU,通过实际操作步骤,帮助各位工程师朋友更好地了解这款芯片。1、RK3562J处理器概述RK3562J处理器采用了4*Cortex-A53@1.8GHz+Cortex-M0@200MHz架构。其中,4个Cortex-A53核心作为主要核心,负责处理复杂
    飞凌嵌入式 2025-01-24 11:21 99浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦