自21世纪初以来,蓝牙一直是我们聆听无线音频的主要方式,从最早的单声道耳机到如今的真无线耳塞,所有这些设备都依赖蓝牙技术来实现音频播放功能。

然而,蓝牙的技术架构并没有跟上我们的实际使用需求。真无线耳塞、全天候使用的助听器以及多人共享音频的功能,在蓝牙最初被设计时都是未曾预料到的。

2022年,蓝牙技术联盟推出了LE Audio技术,这项全新的设计彻底取代了传统的蓝牙音频架构,它基于低功耗蓝牙技术构建了一套全新的系统。LE Audio引入了新的编解码器(LC3)、新的传输机制(同步通道),以及用于统一音频流处理的新型配置文件,同时还具备了名为Auracast的广播功能。

这些变革共同解决了长期以来在音频质量、功耗、多设备同步播放以及易用性方面存在的问题。

这本手册全面深入地介绍了LE Audio技术:它究竟是什么,为何会被开发出来,其在系统各层中的工作原理,以及在Android操作系统中的实现方式。我们将从LE Audio的技术背景和发展动机开始讲起,逐步帮助读者理解其核心概念,随后再深入探讨它的架构与代码实现细节。

你将学到以下内容:

  • 传统蓝牙音频技术为何会遇到各种限制,例如中继传输问题、双配置文件机制的局限性、功耗限制,以及缺乏广播功能和支持助听器的问题

  • LC3编解码器的工作原理,以及它为何能在几乎只有SBC一半的比特率下提供更优质的音频体验

  • 什么是同步通道,这种新的传输机制是如何取代SCO和ACL协议来实现音频传输的,无论是单播还是广播场景

  • LE Audio配置文件体系的构成,从基础服务如BAP和PACS到针对特定应用场景的配置文件如TMAP和HAP

  • 多流音频技术是如何消除传统耳机中继传输带来的问题的,以及它如何为每只耳塞提供同步的音频流

  • Auracast广播功能能够实现什么,以及支持它的基础设施有哪些

  • 所有这些技术在Android操作系统中的实现方式,包括从框架API到原生C++代码层,再到蓝牙控制器的完整实现流程,其中包括状态机管理、编解码器协商机制以及数据流处理过程

无论你是蓝牙工程师、嵌入式系统开发人员、Android平台工程师,还是仅仅对现代无线设备的工作原理感兴趣的人,这本指南都能帮助你更好地理解这一复杂的技术领域。

如果你曾经疑惑过:为什么自己的耳塞在听音乐时音质很好,但在打电话时效果却很差;为什么总有一只耳塞会先没电了;或者为什么不能轻松地与周围的人共享音频文件——那么继续阅读吧,所有答案都在这里。

目录

  1. 曾经在蓝牙的世界里……

  2. 经典蓝牙音频技术存在的问题

  3. LE Audio的出现:我们所需要的解决方案

  4. LC3编解码器:更好的音质、更低的功耗、更多功能

  5. 同步通道:新的技术架构

  6. LE Audio配置文件栈:复杂的规范体系

  7. 多流音频技术:不再需要左耳塞中继

  8. Auracast:面向大众的广播音频服务

  9. Android/AOSP系统中的LE Audio实现

  10. AOSP架构:从应用程序到天线的设计

  11. 服务器端实现方案

  12. 客户端实现方案

  13. 控制整个系统的状态机

  14. 将所有环节结合起来:LE Audio数据包的一天

  15. 总结

1. 曾几何时,在蓝牙的世界里

想象一下:那是2003年,翻盖手机还很流行。第一批蓝牙耳机上市了,从此人们在接电话时就可以看起来像半机械人一样。

那种单声道、质量类似于电话通话的音频效果?其实是依靠一种叫做HFP(免提模式)的技术实现的,它使用CVSD编码格式,传输速率高达64 kbps。不过听起来就好像对方是在潜艇里跟你说话一样……不过至少没有线缆的困扰!

几年后,A2DP(高级音频分发模式)出现了,它可以让人们流畅地播放音乐;而SBC编码格式则为音频传输提供了稳定的支持。这些技术虽然不算特别出色,但确实能够完成自己的任务——A2DP让我们能够享受立体声音乐播放带来的乐趣,生活也因此变得美好起来。

至少有那么一段时间是吧……

负责管理蓝牙技术的蓝牙特殊兴趣小组由数千家公司组成,他们不断对经典的蓝牙音频传输技术进行改进。我们得到了aptXAACLDAC等更先进的编码格式。但问题在于:所有这些新技术都是建立在同样老旧的基础设施之上的。这就好比在房子的地基正在慢慢开裂的情况下还要翻新厨房一样。

蓝牙音频传输技术是建立在BR/EDR(基本速率/增强数据速率)这种“经典蓝牙”无线电技术基础上的。这种技术诞生于21世纪初,当时人们认为从手机向单一耳机传输音频就已经是科技创新的巅峰了。没人能想象到后来会出现真正的无线耳塞、可以直接通过手机收听音乐的助听器,或者能够将音频信号广播到整个机场候机厅的情况。

到了2010年代末,蓝牙音频技术已经显露出明显的局限性,这些问题越来越严重了。

2. 经典蓝牙音频技术存在的问题

让我们来列举一下经典蓝牙音频技术所存在的问题,因为这些问题其实很有参考价值:

问题#1:两种不同的工作模式

经典蓝牙技术具有“双重性格”:如果你想听音乐,就可以使用A2DP模式,并搭配SBC/AAC编码格式来获得高质量的音频效果;但如果你要打电话,就必须切换到HFP模式,而这种模式下使用的编码格式(CVSD或mSBC)会导致音质大幅下降。

你是否注意到过这样的现象:你的无线耳塞在播放Spotify音乐时声音非常清晰,但一旦开始进行Zoom通话,音质就会变得极差,就像是通过纸巾管说话一样?这就是因为系统在A2DP模式和HFP模式之间切换所导致的。不同的工作模式意味着使用不同的编码格式和音频传输路径,这种切换过程往往会导致明显的音质波动,甚至会出现可听见的干扰声。

上面的图表清楚地展示了当从A2DP模式切换到HFP模式时,音频质量会如何下降:在A2DP模式下,音乐可以以SBC/AAC编码格式进行高质量传输;而在HFP模式下,语音通话则使用CVSD/mSBC编码格式,音质会大幅降低。

问题#2:中继问题(真无线耳塞)

当你使用真无线耳塞时(左右耳塞之间没有连线),经典蓝牙技术其实有一个鲜为人知的缺陷:A2DP协议一次只能向一个设备传输音频数据。

那么,这种设计实际上会带来什么后果呢?

  1. 你的手机会将立体声音频流发送到主耳塞(通常是右耳塞)。

  2. 主耳塞会接收左右两个声道的音频数据。

  3. 然后,它会通过另一个蓝牙链接将左声道的音频数据中继到另一只耳塞上。

这种中继机制会产生一些重要的影响。首先,主耳塞的电池消耗会加倍(因此它的续航时间会更短);其次,音频传输的延迟也会增加。此外,左右声道之间也可能会出现同步问题。如果主耳塞的电池耗尽或连接中断,两只耳塞都会停止工作。

问题#3:高功耗

BR/EDR技术诞生于“低功耗”意味着“使用AA电池供电”的时代。而通过经典蓝牙传输音频数据确实会消耗大量电量,因为无线电设备必须保持持续的高带宽连接。对于那些需要依靠小容量电池整天工作的设备来说,这种设计显然是一个致命缺陷。

问题#4:仅支持一对一连接

经典蓝牙音频传输本质上是点对点的。也就是说,必须为每个接收设备建立单独的连接才能进行音频传输。因此,不可能同时向多个听众播放音频。

想象一下,如果你在机场登机口,想让所有人的耳塞都能接收到登机广播,那么使用经典蓝牙技术的话,你就需要分别与每个人的设备配对。在B47登机口尝试这样做,恐怕会遇到很多麻烦吧……

问题#5:助听器没有统一的蓝牙标准

在LE Audio技术出现之前,助听器并没有官方的蓝牙传输标准。苹果开发了自己的MFi助听器协议,而谷歌则为安卓设备推出了ASHA音频传输方案。这两种技术都不是官方认定的蓝牙标准,因此设备之间的互操作性……嗯,可以说还很不理想。

3. LE Audio技术的诞生:我们需要的解决方案

2020年1月,在CES展上,蓝牙技术联盟推出了LE Audio技术。这项技术是在蓝牙低功耗协议的基础上重新设计的,完全取代了传统的BR/EDR技术。

核心的音频传输功能(如同步音频传输、LE功率控制等)早在2019年底/2020年初就被纳入了蓝牙核心规范5.2版本中。不过,完整的LE Audio协议和服务直到2022年7月12日才正式完成制定,当时蓝牙技术联盟宣布所有相关规范都已经获得通过。

这项工作的开展涉及25多个工作组、来自数百家公司的数千名工程师,从最初的概念构思到最终完成总共耗时约7年。这并不是一次简单的规格更新,而是一场彻底的重新设计。

LE Audio带来了以下优势:

功能 传统蓝牙音频 LE Audio
收音机功能 BR/EDR(传统模式) BLE(低功耗模式)
必备编解码器 SBC LC3
相同比特率下的音质 一般 更好(LC3更胜一筹)
功耗 较高 较低
多流传输 不可行(需特殊处理) 可行(原生支持)
广播音频功能 有(Auracast技术)
助听器兼容性 无标准规范(MFi/ASHA) 支持(HAP协议)
双向音频传输 需分别使用不同协议 统一协议支持
音频共享功能 非常有限 内置支持

可以这样理解:传统蓝牙音频就像固定电话系统——可靠且易于使用,但存在诸多局限性。

而LE Audio则相当于向VoIP及流媒体技术的过渡:目标依然是一样的(将声音从A点传输到B点),但所使用的基础设施完全不同,这种新架构使得旧系统无法实现的功能成为可能。

4. LC3编解码器:更佳音质、更低功耗、更多惊喜

LE Audio的核心是一种名为LC3的新编解码器,即“低复杂度通信编解码器”。如果将SBC比作本田Civic,那么LC3就是特斯拉Model 3——它更高效、功能更强大,而且是完全为现代技术环境而设计的。

什么是编解码器?

对于不了解的人来说,编解码器是一种算法:它能够将音频压缩以便通过带宽有限的无线链路进行传输,然后在接收端再将压缩后的音频解压还原。编解码器的质量越高,在相同比特率下输出的音质就越好,同时其消耗的电量也会更少。

LC3的技术规格

LC3是由弗劳恩霍夫IIS研究所(正是他们开发了MP3和AAC编码标准)以及爱立信共同研发的。

以下是它的关键技术参数:

  • 采样率:8千赫、16千赫、24千赫、32千赫、44.1千赫和48千赫

  • 比特深度:16位、24位或32位

  • 帧时长:7.5毫秒或10毫秒

  • 比特率范围:每个声道16千比特/秒至320千比特/秒

  • 算法延迟:使用7.5毫秒帧时为7.5毫秒,使用10毫秒帧时为10毫秒

  • 声道类型:单声道或立体声

为什么LC3比SBC更优秀?

最重要的亮点是:LC3在比特率仅为SBC一半的情况下,仍能提供相当甚至更优质的音频体验。

根据弗劳恩霍夫研究所进行的测试,参与者认为160 kbps版本的LC3在音质上与345 kbps版本的SBC相当,甚至更胜一筹。这种提升并非微不足道,实际上相当于效率提高了近两倍。

SBC与LC3的音频质量对比柱状图

上图直观地展示了不同比特率下LC3与SBC的音频质量评分。160 kbps版本的LC3在音质上与345 kbps版本的SBC相当,这一数据充分证明了其效率提升幅度确实接近两倍。

这种效率的提升直接体现在以下两个方面之一,或两者兼有:

  1. 在相同的功耗下提供更优质的音频体验——即使用更多的比特来保证音质,从而减少资源浪费

  2. 在较低的功耗下保持相同的音质——这意味着设备每次充电后可以使用更长时间

LC3的工作原理(简化版)

LC3采用了改进型离散余弦变换这种数学技术,它能够将音频信号从时域转换为频域,从而分析出其中包含的各个频率成分。这一原理与AAC等现代编码格式类似,但LC3的算法经过优化,计算复杂度较低。

下面是LC3的编码流程简化图:

LC3编码流程示意图

图中显示,PCM音频输入首先经过改进型离散余弦变换,从时域转换到频域;随后通过心理声学模型对频谱信号进行处理,将量化噪声隐藏在人耳无法察觉的频率范围内;最后通过量化和熵编码生成压缩后的LC3比特流。

其中最关键的技术就是频谱噪声处理——LC3利用心理声学模型来调整量化噪声的分布,使其落在人耳难以察觉的频率区域,从而彻底消除音频失真。这个设计真是非常巧妙,对吧?

LC3与LC3plus的区别

你可能还会听说过LC3plus,这是一个经过进一步优化的版本,它增加了以下功能:

  • 超宽带及全频段支持(音频带宽最高可达48 kHz)

  • 提供了多种帧长度选项(2.5毫秒、5毫秒),以适应超低延迟应用场景

  • 在极低的比特率下仍能保持较高的音质

虽然LC3plus并不属于LE Audio标准的必备组件,但它被应用于一些实际产品中,比如DECT NR+无线电话系统。

5. 同步通道:全新的传输机制

在这里,技术架构的设计变得非常有趣。传统的蓝牙音频传输方式中,会使用SCO(同步连接导向)链路来传输语音数据,而通过ACL(异步无连接)链路来使用L2CAP进行A2DP流媒体传输。这些机制虽然能够满足基本需求,但就好比用花园水管来完成完全不同的用途——功能上还可以,但在优化音频传输效果方面显然不够理想。

LE Audio在链路层引入了一种全新的传输机制:同步通道。这种机制专为传输对时间要求严格的数据(如音频数据)而设计。

“同步”意味着什么

“同步”这个词来源于希腊语:iso表示“相等”,chronos表示“时间”——因此“同步”指的是“以固定的时间间隔进行传输”。同步通道能够确保数据以可预测的、规律的时间间隔到达接收端,而这正是音频传输所需要的。

可以这样理解:

  • 异步传输(ACL):数据会随机到达接收端。(适合文件传输,但不适合音频传输)

  • 同步传输(SCO):数据必须按时送达,如果未能按时到达,则无法重新传输。(旧式的语音传输方式,不支持重传)

  • 同步通道:数据应该按时送达,系统会通过智能的重传机制来确保这一点。(结合了异步传输的灵活性与同步传输的可靠性)

蓝牙传输类型的对比:异步、同步和同步通道

上图对比了三种蓝牙传输类型:异步传输(ACL)不保证数据传输的准时性;同步传输(SCO)按固定时间表传输数据且不支持重传;而同步通道则能按照固定的时间表进行传输,并通过智能重传机制确保数据的按时到达,从而同时具备异步传输的灵活性与同步传输的可靠性。

两种类型:CIS与BIS

同步通道分为两种类型,而正是这两种类型的存在才让蓝牙音频传输技术变得如此强大:

CIS——连接式同步流

CIS适用于点对点音频传输(即单播方式)。你的手机就是通过这种机制将音乐流式传输到耳塞中。

连接式同步流(CIS)的示意图

上图展示了连接式同步流(CIS)的传输过程:手机作为单播客户端,会通过同一个连接组同时向左耳塞和右耳塞发送两路同步音频数据。箭头表示音频数据是双向流动的——音乐数据传向耳塞,而麦克风采集的声音则传回手机。

CIS的主要特性:

  • 双向传输:音频可以同时向两个方向流动(既可以从主机发送到耳塞,也可以从耳塞通过麦克风传回主机)

  • 确认机制:接收方会发送确认信号,从而允许丢失的数据包被重新传输

  • 分组传输:多个CIS数据流会被组合成一个CIG(同步广播组),以确保它们能够同步传输

最后一点非常重要。CIG机制能确保左右耳塞接收到的音频数据完全同步,从而避免“左耳听到的声音比右耳早50毫秒”这类问题。

BIS——广播同步流

BIS适用于一对多的音频传输场景(即广播模式)。它是Auracast技术的基础。

广播同步流示意图

上图展示了广播同步流的传输原理:一个广播源通过一个包含多个BIS数据流的BIG(广播同步组)来发送音频信号。多个接收设备可以独立地接收到相同的音频内容,而无需与广播源建立连接,这种机制类似于FM收音机的工作方式。

BIS的主要特性:

  • 单向传输:仅支持从源头到接收端的单向传输,因为不可能让上百万人同时进行双向对话

  • 无需确认机制:接收方不会发送确认信号,因此源设备甚至不知道有多少人在收听

  • 分组传输:多个BIS数据流会组合成一个BIG(广播同步组)进行传输

  • 可扩展性:接收设备的数量没有上限,这种技术本质上就是传统的无线电广播方式

ISO数据路径

在底层实现层面,同步数据会通过蓝牙控制器遵循特定的路径进行传输:

蓝牙控制器中的同步数据传输路径示意图

上图详细展示了音频数据在蓝牙控制器中的传输路径。来自主机设备的音频帧首先会经过HCI层,然后进入ISO适配层(ISO-AL),该层负责数据的分割、添加时间戳以及管理数据传输的超时机制,最后这些数据才会被发送到链路层进行无线传输。

其中的关键创新在于ISO-AL(同步适配层)——这个层位于HCI层和链路层之间,它的主要功能包括:

  • 数据分割:将音频帧拆分成适合链路层传输的大小

  • 时间戳添加:为每个音频帧添加时间戳,以便接收端能够准确知道何时开始播放该音频帧

  • 超时处理:如果某个音频帧无法按时送达,系统会自动忽略它(宁可错过这个帧也不愿让它延迟播放)

6. LE Audio配置文件层次结构:规格规范的层层叠加

如果你曾经看过LE Audio的规格列表,然后觉得那些内容让人眼花缭乱,那么你并不孤单。这些规格确实非常多,但它们被组织成了一个逻辑清晰的结构体系,一旦你了解了这个结构,一切就会变得容易理解了。

可视化展示:配置文件层次结构

以下是LE Audio配置文件层次结构的三层结构图:

LE Audio配置文件的三层结构图

第一层(基础层)包括BAP、VCP、MCP、CCP、MICP、CSIP和BASS。第二层(分组层)包含CAP,它负责协调第一层中的各种配置文件。第三层(应用场景专用配置文件)包括用于电话通话的TMAP、用于助听器的HAP以及用于公共广播的PBP。每一层都是建立在前一层的基础之上的。

可以把这个结构想象成一块三层结构的婚礼蛋糕:

第一层:基础层(核心服务与配置文件)

这些就是构建其他所有功能的基础组件:

BAP——基本音频配置文件

BAP是整个系统中最基础的部分。它定义了发现、配置以及建立LE Audio数据流所需的基本流程,并明确了两种角色:

  • 单播客户端:负责发起并控制音频数据流的设备(通常是手机)

  • 单播服务器:负责播放或捕获音频数据的设备(通常是耳塞)

BAP依赖于几项GATT服务来实现其功能:

  • PACS(音频能力公布服务):用于告知对方自己支持哪些音频格式

  • ASCS(音频流控制服务):用于配置和管理音频数据流

VCP——音量控制配置文件

该配置文件用于实现远程音量控制。你的手机可以通过VCS(音量控制服务)来控制耳塞的音量,反之亦然。

MCP——媒体播放控制配置文件

该配置文件允许远程控制媒体的播放功能,包括暂停、播放、跳过等操作,这些都是通过MCS(媒体控制服务)来实现的。其作用类似于LE Audio版本的AVRCP。

CCP——通话控制配置文件

该配置文件用于管理电话通话的状态,包括接听、挂断以及保持通话等操作,这些都是通过TBS(电话承载服务)来实现的。它取代了HFP中的通话控制功能。

MICP——麦克风控制配置文件

该配置文件用于实现远程开启或关闭设备的麦克风功能。这个功能虽然简单,但却非常实用。你是否曾经在通话过程中不知道如何关闭麦克风?MICP正是为了解决这个问题而存在的。

CSIP——协调式设备组识别配置文件

这种配置文件的作用就是让手机能够识别出“这两只耳塞属于同一组”。它通过CSIS(协调式设备组识别服务)向手机发送信号:“我是左耳塞,而我的伙伴是右耳塞,我们是一组。”

如果没有CSIP,手机会将每一只耳塞都视为独立的设备。正是CSIP使得这些设备能够实现无缝的“组合使用”功能。

BASS——广播音频扫描服务

BASS用于检测周围的广播音频源。拥有BASS功能的设备可以扫描附近的广播信号,帮助其他设备(比如助听器)接收到这些信号。

第二层:分组层

CAP——通用音频配置文件

CAP建立在第一层的各种配置文件之上,为更高级别的配置文件提供了通用的操作流程。它负责处理以下功能:

  • 通过CSIP识别属于同一组的设备

  • 使用BAP为这些设备建立单播音频流

  • 启动广播音频流

可以把CAP看作是协调所有第一层配置文件协同工作的“指挥者”。

第三层:场景专用配置文件

这些配置文件是根据实际用户使用场景设计的:

TMAP——电话与媒体音频配置文件

TMAP是一种适用于各种常见音频使用场景的通用配置文件。它定义了以下角色:

  • 通话终端:能够拨打电话和接听电话

  • 单播媒体发送端:可以发送媒体音频信号

  • 单播媒体接收端:可以接收媒体音频信号

  • 广播媒体发送端:能够播放广播媒体音频

  • 广播媒体接收端:能够接收广播媒体音频

如果你正在开发一款普通的手机与耳塞组合产品,那么TMAP就是你应该选择的配置文件。

HAP——助听器接入配置文件

HAP是专为助听器设计的标准化配置文件。它取代了原有的MFi和ASHA技术标准,为助听器提供了统一的蓝牙通信规范。HAP负责实现以下功能:

  • 向助听器传输音频信号

  • 调整助听器的预设设置

  • 控制助听器的音量

这一进展意义重大:如今,所有使用蓝牙技术的助听器都能通过统一的协议与其他设备进行交互了。

PBP——公共广播配置文件

PBP规定了如何设置和检测公共广播信号(如Auracast技术)。正是这一配置文件使得在机场候机厅等场所使用广播音频成为可能。

7. 多流音频技术:不再需要左耳塞中继

还记得经典蓝牙技术中的中继问题吗?LE Audio通过多流音频技术彻底解决了这个问题。

使用LE Audio时,源设备(你的手机)可以直接将独立的、同步的音频流发送到每个耳塞上:

对比经典蓝牙中继架构与LE Audio多流架构的示意图

该示意图展示了经典蓝牙的中继架构(手机将立体声音频发送到主耳塞,再由主耳塞转发给副耳塞)与LE Audio的多流架构的区别:在LE Audio中,手机通过CIG内的独立CIS通道直接将同步的音频流发送到每个耳塞上。这种技术能够更均衡地消耗电池电量,并降低延迟。

工作原理

  1. 两个耳塞都通过BLE技术与手机独立连接

  2. 手机会利用CSIP技术将它们识别为一对协同工作的设备

  3. 手机会建立一个包含两个CIS流的CIG(同步连接组),每个耳塞对应一个CIS流

  4. 手机会通过CIS #1通道发送左声道音频,通过CIS #2通道发送右声道音频

  5. CIG技术能确保两个音频流保持同步,从而使两个耳塞同时播放相同的音频

优势:

  • 电池消耗更均衡:两个耳塞分担相同的处理任务

  • 延迟更低: 无需中继传输,因此延迟更小

  • 可靠性更高:如果一个耳塞失去连接,另一个耳塞仍能继续播放音频

  • 真正的立体声效果:每个耳塞都能接收独立的音频流,无需进行解码或分离处理

8. Auracast:面向大众的广播音频技术

Auracast是LE Audio的一项广播功能,可以说是这项技术中最具革命性的部分。它就像蓝牙版的FM收音机——一个音源可以同时为无数听众提供服务。

Auracast的工作原理

  1. 广播源会创建一个包含一个或多个BIS流的BIG(广播同步连接组)

  2. 广播源会使用扩展广告功能来发布广播信息,其中会包含流名称、语言设置及编解码器配置等元数据

  3. 接收设备会检测到这些广播信息,并通过定期接收的广告信息来获取音频流的详细参数

  4. 接收到这些参数后,接收设备就会加入BIG连接组,开始接收音频流

Auracast广播流程示意图

上图展示了Auracast的广播流程:广播源通过扩展广告功能进行宣传,广播接收端发现这些广告后,会通过周期性广告功能同步获取流媒体参数,进而加入BIG网络以接收音频信号。接收端的数量没有限制。

Auracast的应用场景

实际上,Auracast的应用场景非常丰富:

  • 机场/火车站:将广播信息直接发送到旅客的耳塞中(支持多种语言!)

  • 健身房:墙上的每台电视都可以播放自己的音频内容,用户可以自行选择收听哪一路。

  • 博物馆

    :为游客提供音频导览服务,声音会直接传输到他们的耳塞中。

  • 酒吧/体育赛事现场

    :观众可以在大屏幕上观看比赛,同时通过耳塞收听解说,而不会打扰到周围的人。

  • 会议场合

    :实时翻译频道可以为参会者提供同步翻译服务。

  • 安静的迪斯科场所

    :显然,这种技术也非常适用。

广播辅助设备的角色

还有一个非常重要的辅助概念,那就是广播辅助设备。这类设备(通常是手机)能够帮助其他设备(比如耳塞)发现并接收广播信号。

为什么需要这样的设备呢?因为体积较小的耳塞可能没有足够的处理能力或用户界面来自行搜索和选择广播内容。因此,手机会负责完成这些工作,向用户显示可用的广播选项,并通过BASS(广播音频扫描服务)告诉耳塞应该收听哪一路广播。

展示广播辅助设备功能的示意图

上图详细说明了广播辅助设备的功能:手机会扫描可用的Auracast广播信号,并将结果展示给用户。当用户选择某一路广播后,手机会通过BASS服务指示耳塞开始接收该广播,因为耳塞本身可能不具备自主搜索的能力。

9. Android/AOSP系统中的LE Audio技术实现

现在让我们来看看具体的代码实现。这才是真正考验技术实力的地方。

Android系统中LE Audio技术的支持发展历程

  • Android 12 (2021):首次引入LE Audio相关API,提供开发者预览版本。

  • Android 13 (2022):全面支持LE Audio功能,包括单播客户端/服务器模式以及广播源/接收端模式。

  • Android 14 (2023):稳定性得到提升,广播音频功能得到了优化,同时增加了对LE Audio源设备角色的支持。

  • Android 15 (2024):开始支持Auracast广播接收端功能,引入了广播辅助设备机制,并改善了音频上下文切换的性能。

  • Android 16 (2025):在快速设置和蓝牙设置中加入了原生的Auracast用户界面,进一步优化了音频共享体验。

AOSP系统中LE Audio功能的实现主要位于蓝牙模块中(路径为packages/modules/Bluetooth),这个模块属于主线模块,因此可以通过Google Play系统更新来对其进行升级,而无需等待完整的Android操作系统更新。

AOSP的关键源代码位置

如果你想亲自深入研究这些代码,以下是相关的路径信息:

组件 路径
LE Audio Java服务 packages/modules/Bluetooth/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
JNI桥接层 packages/modules/Bluetooth/android/app/src/com/android/bluetooth/le_audio/LeAudioNativeInterface.java
原生LE Audio客户端 packages/modules/Bluetooth/system/bta/le_audio/le_audio_client.cc
编解码器管理器 packages/modules/Bluetooth/system/bta/le_audio/codec_manager.cc
状态机 packages/modules/Bluetooth/system/bta/le_audio/state_machine.cc
LC3编解码器库 external/liblc3/
框架API frameworks/base/core/java/android/bluetooth/BluetoothLeAudio.java
广播API frameworks/base/core/java/android/bluetooth/BluetoothLeBroadcast.java

高层架构

AOSP系统中用于LE Audio功能的蓝牙堆栈遵循Android的经典分层架构:

AOSP Bluetooth LE Audio堆栈的分层架构图

在这张AOSP Bluetooth LE Audio堆栈的分层架构图中,从上到下依次包括:应用层、框架API(BluetoothLeAudio、BluetoothLeBroadcast)、LeAudioService(Java实现)、JNI桥接层、原生C++代码栈(包含le_audio_client、codec_manager、state_machine、iso_manager等组件)、HCI层以及蓝牙控制器硬件。

10. AOSP架构:从应用到天线

让我们详细了解一下每一层的功能。

第1层:框架API

Android通过android.bluetooth包中的几个公共API类提供了LE Audio功能:

BluetoothLeAudio

这是用于单播LE Audio通信的主要API。应用程序可以通过它来:

  • 连接LE Audio设备

  • 设置用于音频播放/录制的设备

  • 查询组信息

  • 选择编解码器配置

// 示例:连接LE Audio设备
BluetoothLeAudio leAudio = bluetoothAdapter.getProfileProxy(
    context, listener, BluetoothProfile.LE_AUDIO);

// 将LE Audio设备设置为媒体播放的活跃设备
leAudio.setActiveDevice(leAudioDevice);

BluetoothLeBroadcast

用于广播音频的API(Auracast)。应用程序可以使用该API来:

  • 开始/停止音频广播

  • 设置广播元数据(名称、语言等)

  • 配置广播密码

// 启动音频广播
BluetoothLeBroadcast broadcast = bluetoothAdapter.getProfileProxy(
    context, listener, BluetoothProfile.LE_AUDIO_BROADCAST);

broadcast.startBroadcast(contentMetadata, audioConfig, broadcastCode);

BluetoothLeBroadcastAssistant

用于辅助其他设备接收广播音频的API。

BluetoothVolumeControl

通过VCP实现远程音量控制的API。

BluetoothHapClient

用于控制助听器预设设置及音频流传输的API。

第二层:LeAudioService(核心服务)

LeAudioService是蓝牙应用程序中的核心服务,它负责协调所有与LE Audio相关的功能。正是这个服务实现了各种音频处理操作。

其主要职责包括:

  • 设备管理:跟踪已连接的LE Audio设备及其功能

  • 组管理:管理属于同一组的设备

  • 音频路由

    :决定哪些设备应负责播放或录音任务

  • 状态机管理:处理音频连接的生命周期相关事务

  • 配置文件协调:确保各种配置文件能够正常协同工作

以下是LeAudioService的结构示意图:

public class LeAudioService extends ProfileService {
    
    // 设备地址与状态机的映射关系
    private Map〈BluetoothDevice, LeAudioStateMachine〉 mStateMachines;
    
    // 组ID与组信息的映射关系
    private Map〈Integer, LeAudioGroupDescriptor〉 mGroupDescriptors;
    
    // 用于连接本地系统的接口桥接层
    private LeAudioNativeInterface mNativeInterface;
    
    // 当前活跃的音频输出设备与输入设备
    private BluetoothDevice mActiveAudioOutDevice;
    private BluetoothDevice mActiveAudioInDevice;
    
    // 编解码器配置信息
    private BluetoothLeAudioCodecConfig mInputLocal CodecConfig;
    private BluetoothLeAudioCodecConfig mOutputLocal CodecConfig;
    
    public void connect(BluetoothDevice device) {
        // 1. 检查该设备是否支持LE Audio功能
        // 2> 为该设备创建相应的状态机
        // 3> 通过本地系统建立连接
        // 4> 发现该设备支持的GATT服务
        // 5> 读取该设备的音频功能信息
    }
    
    public void setActiveDevice(BluetoothDevice device) {
        // 1> 查找该设备所属的组
        // 2> 找出与该设备同属一个组的其它设备
        // 3> 通过BAP配置音频流
        // 4> 建立同步通信通道
        // 5> 启动音频路由功能
    }
}

第3层:原生堆栈(C++)

在Java层之下,所有繁重的处理工作都是由C++完成的。LE Audio的原生实现部分位于蓝牙堆栈中(历史上这一部分被称为“Fluoride”,而较新的组件则属于“Gabeldorsche”模块)。

主要的原生组件包括:

le_audio_client.cc / le_audio_client_impl

这是LE Audio客户端的主要C++实现代码,其功能包括:

  • 处理GATT客户端相关操作(发现服务、读取特性信息)

  • 管理ASE(音频流端点)的状态机

  • 与远程设备进行编解码器协商

  • 创建并管理CIS/BIS对象

state_machine.cc

该模块负责管理每个LE Audio设备的连接状态机:

原生LE Audio连接状态机的状态图,包括断开连接、连接中、已连接以及正在断开连接等状态。

上图展示了原生LE Audio连接状态机的状态变化过程。这种状态机是由C++层为每个设备单独管理的,它负责控制GATT连接的建立、服务的发现以及特性信息的读取等操作,直到设备进入“已连接”状态。

codec_manager.cc

该模块负责编解码器的配置管理:

  • 列出设备支持的编解码器功能

  • 根据设备的性能及使用场景选择最优的编解码器配置方案

  • 与LC3编码器/解码器进行交互

iso_manager.cc

该模块负责管理同步通道:

  • 为单播通信创建或销毁CIG/CIS通道

  • 为广播通信创建或销毁BIG/BIS通道

  • 处理同步数据的HCI接口相关操作

audio_hal_client.cc

该模块负责将蓝牙堆栈与Android音频HAL框架连接起来:

  • 从Android音频框架中接收PCM格式的音频数据

  • 将这些音频数据传递给LC3编码器进行编码处理

  • 通过同步通道发送已编码的音频数据

第4层:控制器硬件

蓝牙控制器负责处理低级别的无线电操作:

  • 安排同步事件的传输时序

  • 控制PHY层的操作(1M、2M或编码PHY模式)

  • 负责数据包的格式化及CRC校验

  • 重新发送丢失的同步数据包

主机系统(Android)通过HCI(主机控制器接口)与控制器进行通信,并使用特定的HCI命令来控制同步通道的相关操作。

  • HCI_LE_Set_CIG_Parameters:配置连接的同步组

  • HCI_LE_Create_CIS:创建连接的同步流

  • HCI_LE>Create_BIG:创建广播同步组

  • HCI_LE_Setup_ISO_Data_Path:设置ISO数据的路径(通用接口规范标准路径或厂商自定义路径)

  • HCI_LE_big Созд_Sync:与广播同步组进行同步(适用于广播接收端设备)

11. 服务器端实现

在LE Audio的术语中,“服务器端”实际上指的是单播服务器,也就是负责播放音频的设备(例如你的耳塞)。虽然将接收设备称为“服务器”可能会让人感到困惑,但你可以将其理解为一个GATT服务器:它提供了客户端需要连接的GATT服务。

单播服务器的功能

单播服务器(即耳塞设备)会提供多种GATT服务:

单播服务器(耳塞)提供的GATT服务

上图展示了单播服务器(耳塞设备)提供的GATT服务。该服务器会暴露四种关键服务:

  • PACS(发布的音频功能服务),用于说明设备支持的编解码器、采样率、帧时长以及音频相关参数

  • ASCS(音频流控制服务),其中包含一个或多个ASE(音频流端点)特性,客户端可以通过这些特性来配置和控制音频流

  • VCS(音量控制服务),允许客户端读取并设置设备的音量等级

  • CSIS(协调组识别服务),用于标识该设备属于某个协调组(例如“我是左耳塞,我的配对设备是右耳塞”)

单播客户端(手机等设备)可以通过GATT连接到这些服务,从而发现设备的功能、配置音频流并控制播放过程。

ASE状态机(服务器端实现)

服务器上的每个ASE(音频流端点)都对应着一个状态机。这个状态机是音频流管理的核心机制:

单播服务器上ASE(音频流端点)状态机的状态图

上图展示了单播服务器上ASE(音频流端点)的状态机。状态包括:空闲状态、编解码器配置完成状态、服务质量配置完成状态、启用状态、流传输状态、禁用状态以及释放状态。客户端可以通过向ASE控制点特性写入相应的操作命令(如“配置编解码器”、“配置服务质量”、“启用”“禁用”或“释放”),来触发状态的转换。

状态转换:

  1. 空闲状态 → 编解码器配置完成:客户端向ASE控制点发送Config Codec指令,指定编解码器类型(LC3)、采样率、帧时长等参数。

  2. 编码解码器配置完成 → QoS配置完成:客户端发送Config QoS指令,指定以下参数:

    • SDU间隔(音频帧的发送频率)

    • 数据帧格式(是否进行分帧传输)

    • 最大SDU大小

    • 重传次数限制

    • 最大传输延迟

    • 呈现延迟

  3. QoS配置完成 → 启用状态:客户端发送Enable指令,服务器此时准备接收音频数据。

  4. 启用状态 → 流媒体传输状态:当客户端建立完通信连接且双方都准备好时,音频数据开始流动。

  5. 流媒体传输状态 → 关闭状态:客户端发送Disable指令,或连接被主动断开。

  6. 任何状态 → 空闲状态

    :客户端发送Release指令,终止当前的流媒体配置。

标准编解码器配置

BAP定义了一组具有特定名称的编解码器配置选项,这些配置对应于特定的LC3参数。设备在通信过程中会协商使用这些“预设配置”:

>

)

>

>

配置名称 采样率 帧时长 每帧数据位数 比特率 典型应用场景
8_1 8千赫兹 7.5毫秒 26 约27.7千比特/秒 低带宽语音通信
8_2 8千赫兹 10毫秒 30 24千比特/秒 低带宽语音通信
16_1 16千赫兹 7.5毫秒 30 32千比特/秒 电话通话(低延迟)
16_2 16千赫兹 10毫秒 40 32千比特/秒 电话通话(标准配置)
24_2 24千赫兹 10毫秒 60 48千比特/秒 宽带语音通信
32_1 32千赫兹 7.5毫秒 60 64千比特/秒 超宽带语音通信
32_2 32千赫兹 10毫秒 80 64千比特/秒 超宽带语音通信
48_1 48千赫兹 7.5毫秒 75 80千比特/秒 音乐播放(低延迟)
48_2 48千赫兹 10毫秒 100 80千比特/秒 音乐播放(均衡音质)
48_4 48千赫兹 10毫秒 120 96千比特/秒 高质量音乐播放
48_6 48千赫兹 10毫秒 155 124千比特/秒 最高音质音乐播放

对于大多数消费级耳塞来说,媒体播放通常使用48_4配置(48千赫兹采样率,96千比特/秒比特率),而电话通话则使用16_2配置(16千赫兹采样率,32千比特/秒比特率)。这种统一的LC3编解码器配置能够同时满足这两种应用场景——无需在SBC和mSBC之间切换!

音频上下文类型

LE Audio定义了音频上下文类型,这类元数据能够告知接收设备当前正在传输的是哪种类型的音频。这样一来,设备就能根据这些信息优化自身的运行方式(例如,在通话时启用降噪功能,或在播放音乐时增强低音效果):

>

上下文类型 位长度 使用场景
未指定 0x0001 通用音频,无需进行任何特定优化
对话类音频 0x0002 电话通话、VoIP通信,双向传输,低延迟要求
媒体内容音频 0x0004 音乐、播客、视频,高质量音频流
游戏类音频 0x0008 游戏播放,要求极低延迟
指令提示类音频 0x0010 导航提示音、公告信息
语音助手相关音频 0x0020 如“嘿,谷歌”/“嘿,Siri”等语音指令
实时音频 0x0040 现场演出或广播中的实时音频流
音效类音频 0x0080 界面点击声、键盘敲击声等
通知提示类音频 0x0100 消息提醒、应用程序通知音
来电铃声 0x0200 来电时的铃声
警报提示类音频 0x0400 闹钟提醒音、计时器提示音
紧急报警音 0x0800 紧急广播提示音

与传统的音频传输方式相比,LE Audio提供了更为细致的分类。传统方式基本上只区分两种状态:“正在播放音乐”或“正在进行通话”。而利用LE Audio,设备能够根据不同的音频类型做出智能化的处理决策,比如“这是游戏音频,应使用7.5毫秒的帧间隔以降低延迟”,或者“这是一个通知信息,需要将其融入音频流中但不要中断音乐的播放”。

AOSP单播服务器实现机制

在AOSP系统中,单播服务器功能主要用于那些Android设备作为接收端的情况(例如,基于Android系统的助听器或接收音频信号的Chromebook设备)。

相关关键类包括:

  • LeAudioService.java:当设备处于接收角色时,负责处理服务器端的操作

  • 在原生代码中:le_audio_server.cc负责管理用于承载PACS、ASCS等数据的GATT服务器

广播源实现机制

对于Auracast广播音频而言,AOSP系统中的广播源相关实现包括以下步骤:

// 在LeAudioService.java或BroadcastService中
public void startBroadcast(BluetoothLeBroadcastSettings settings) {
    // 1. 使用广播参数配置LC3编码器
    // 2> 设置扩展广告信息,并添加相应的广播元数据
    // 3> 根据流传输参数设置周期性广告功能
    // 4> 通过HCI创建BIG对象
    // 5> 开始在BIS通道上发送ISO格式的数据

<原生实现方式:>

  • broadcaster.cc / broadcaster_impl:负责管理广播连接的生命周期。

  • 使用广播名称和元数据来配置扩展广告功能

  • 配置周期性广告,以传输BASE(广播音频源端点)数据结构。

  • 创建包含适当数量BIS流的BIG对象。

  • 将编码后的音频数据路由到BIS数据路径中。

12. 客户端端实现

“客户端”指的是单播客户端,通常就是用户的手机。该客户端负责发现、连接并控制LE Audio设备。

连接流程

以下是您连接LE Audio耳塞时所经历的步骤:

手机(单播客户端)与耳塞(单播服务器)之间的LE Audio连接流程图。

连接流程包括:BLE扫描与设备发现、GATT连接、服务发现(查找PACS、ASCS、CSIP、VCS)、读取PAC记录以了解音频功能、读取CSIS以确定是否属于协调组,随后进行ASE配置(配置编解码器、服务质量等),最后创建CIS并开始音频流传输。

AOSP客户端实现细节

步骤1-3:设备发现与连接

// LeAudioService.java
public void connect(BluetoothDevice device) {
    // 为该设备创建一个新的LeAudioStateMachine对象
    LeAudioStateMachine sm = getOrCreateStateMachine(device);
    sm.sendMessage(LeAudioStateMachine.CONNECT);
    
    // 这个状态机负责处理以下操作:
    // - GATT连接流程
    // - 服务发现过程
    // - 特性读取操作
}

LeAudioStateMachine负责管理整个连接生命周期:

// LeAudioStateMachine.java (简化版)
class LeAudioStateMachine extends StateMachine {
    
    class Disconnected extends State {
        void processMessage(Message msg) {
            if (msg.what == CONNECT) {
                // 通过原生接口启动GATT连接
                mNativeInterface.connectLeAudio(mDevice);
                transitionTo(mConnecting);
            }
        }
    }
    
    class Connecting extends State {
        void processMessage(Message msg) {
            if (msg.what == CONNECTION_STATE_CHANGED) {
                if (newState == CONNECTED) {
                    transitionTo(mConnected);
                }
            }
        }
    }
    
    class Connected extends State {
        void enter() {
            // GATT服务已发现
            // 音频功能信息已获取
            // 设备已准备好进行流传输
            broadcastConnectionState(BluetoothProfile.STATE_CONNECTED);
        }
    }
}

步骤4-6:功能识别

底层模块会读取PACS文件,以了解远程设备支持哪些功能:

// 在le_audio_client_impl(C语言实现)中
void OnGattServiceDiscovery(BluetoothDevice device) {
    // 从PACS文件中读取相关数据
    ReadPacsCharacteristics(device);
    
    // 读取CSIS信息以获取协调设置详情
    ReadCsisCharacteristics(device);
    
    // 读取ASCS信息以获取ASE的数量及状态
    ReadAscsCharacteristics(device);
}

void OnPacsRead(BluetoothDevice device, PacRecord sink_pac) {
    // sink_pac中包含以下信息:
    //   codec_id: LC3
    //   sampling_frequencies: 48000, 44100, 32000, 24000, 16000, 8000
    //   frame_durations: 10ms, 7.5ms
    //   channel_counts: 1
    //   octets_per_frame: 40-155 (对应不同的比特率)
    //   supported_contexts: MEDIA, CONVERSATIONAL, GAME
    
    // 将这些功能信息保存起来,以便后续进行编解码器配置协商
    device_info.sinkcapabilities = sink_pac;
}

步骤7-12:流媒体设置

当音频播放开始时,客户端会配置并启用相应的流媒体通道:

// 在codec_manager(C语言实现)中
CodecConfig SelectCodecConfiguration(
    PacRecord remote_capabilities,
    AudioContext context  // 如MEDIA、CONVERSATIONAL等
) {
    // 对于媒体播放,优先选择高质量配置:
    //   48 kHz采样频率,10ms的帧长,每个通道32 kbps的比特率
    
    // 对于语音通话,则需要优化延迟:
    //   16 kHz采样频率,7.5ms的帧长,每个通道32 kbps的比特率
    
    // 进行协商,选择双方都支持的最佳配置方案
}

// 在le_audio_client_impl中
void GroupStreamStart(int group_id, AudioContext context) {
    auto group = GetGroup(group_id);
    auto codec_config = SelectCodecConfiguration(
        group->GetRemoteCapabilities(), context);
    
    // 遍历组中的每个设备:
    for (auto& device : group->GetDevices()) {
        // 遍历设备上的每个ASE:
        for (auto& ase : device->GetAses()) {
            // 步骤8:配置编解码器
            WriteAseControlPoint(device, OPCODE_CONFIGCodec, {
                .ase_id = ase->id,
                .codec_id = LC3,
                .codec_specific = {
                    .sampling_freq = 48000,
                    .frame_duration = 10ms,
                    .channel_allocation = LEFT,  // 或RIGHT
                    .octets_per_frame = 120
                }
            });
        }
    }
    // 在编解码器配置完成后,进行后续操作:
    //   步骤9:配置QoS参数 → 步骤10:启用流媒体传输 → 步骤11:创建CIS信息
}

步骤13:音频数据流动过程

一旦开始流媒体播放,音频数据就会按照以下方式在AOSP框架中传递:

显示LE Audio流媒体播放过程中音频数据流动方式的示意图

上图展示了LE Audio流媒体传输过程中音频数据流动的路径:来自Android音频框架的PCM音频数据首先到达蓝牙音频HAL层,然后被LC3编码器进行编码,随后被打包成带有时间戳的ISO SDU格式的数据包,通过HCI协议发送给控制器,再通过CIS无线技术传输到耳塞设备中。在耳塞设备内部,这些数据包会由LC3解码器进行解码,最终被转换为音频信号并播放出来。

广播接收机制的实现

为了接收广播音频信号(例如Auracast功能),AOSP采用了以下实现方式:


// 广播接收流程(原生代码)
void OnBroadcastSourceFound(AdvertisingReport report) {
    // 解析广告数据以获取广播相关元信息
    BroadcastMetadata metadata = ParseBroadcastMetadata(report);
    
    // 显示相关信息,例如:“机场B47登机口——英语频道”
    NotifyBroadcastSourceFoundmetadata);
}

void SyncToBroadcast(BroadcastMetadata metadata) {
    // 1. 与周期性广告信号同步
    HCI_LE_Periodic_Advertising>Create_Sync(metadata.sync_info);
    
    // 2. 当与广播信号的同步建立后,解析BASE数据
    BASE base = ParseBASE(periodic_adv_data);
    
    // 3. 选择相应的子组及BIS流
    // 4. 与BIG信号同步
    HCI_LE_BIG_Create_Sync(base.big_params, selected_bis);
    
    // 5. 设置ISO数据传输路径
    HCI.LE_Setup_ISO_Data_Path(bis_handle, HCI_DATA_PATH);
    
    // 6. 开始接收并解码音频数据
}

13. 负责整体流程控制的状态机

AOSP的LE Audio实现机制实际上依赖于多个相互关联的状态机来完成各项功能:

连接状态机

该状态机负责管理所有设备的连接生命周期过程:

状态图显示了LE Audio连接状态机的四种状态:断开连接、连接中、已连接以及正在断开连接。

该状态图清晰地展示了LE Audio连接状态机的四种状态变化过程:断开连接、连接中、已连接以及正在断开连接。

状态转换规则如下:当发生“连接”事件时,系统会从“断开连接”状态进入“连接中”状态;如果连接成功,就会进入“已连接”状态;而“断开连接”事件会导致系统返回“断开连接”状态;如果在尝试连接过程中出现超时或失败情况,系统同样会回到“断开连接”状态。

组音频状态机

该状态机用于管理由多台设备组成的音频组的运行状态:

状态图显示了组音频状态机的各种状态:空闲、编码器配置完成、服务质量配置完成、启用中、正在流式传输以及已禁用。<此状态图展示了群组音频的状态机,其包含以下几种状态:空闲状态、编解码器配置完成状态、服务质量配置完成状态、启用状态、流传输状态以及禁用状态。在音频流被建立起来的过程中,系统会按照一定的顺序依次经过这些状态;而“释放”操作则会使系统恢复到空闲状态。

各部分是如何协同工作的(代码演示)

以下是当你连接了LE Audio耳塞后,在音乐应用中按下“播放”按钮时,各项操作的具体流程的简化说明:

当用户在使用LE Audio耳塞的音乐应用中按下‘播放’按钮时,各事件会按照这一顺序发生

上图展示了当用户在使用LE Audio耳塞的音乐应用中按下“播放”按钮时,各项事件发生的先后顺序。

具体流程如下:

  1. 音乐应用会将PCM音频数据写入到AudioTrack中。

  2. Android的AudioFlinger会将这些音频数据转发给蓝牙音频HAL。

  3. 蓝牙音频HAL会通知LeAudioService音频播放已经开始。

  4. LeAudioService会查找当前处于活动状态的音频组,并在原生代码栈中触发GroupStreamStart函数。

  5. 原生代码栈会通过向每只耳塞上的ASCS控制点发送指令,来配置这两只耳塞的相关参数(包括编码格式、服务质量设置等)。

  6. 原生代码栈会通过HCI机制创建一个包含两个CIS通道的CIG结构。

  7. 这两个CIS通道会被建立起来,以便音频数据能够在它们之间传输。

  8. ISO数据传输路径也会被设置完毕。

  9. PCM音频数据会从蓝牙音频HAL传递给LC3编码器,编码器会将这些音频数据压缩成帧结构。

  10. 压缩后的帧会被作为ISO SDU格式的数据,通过HCI机制传输给控制器。

  11. 控制器会在预定的时间间隔内,将这些帧通过无线信号发送出去。

  12. 耳塞接收到这些数据后,会对其进行解码,并在规定的延迟时间内播放出来。

14. 整体流程概述:一个LE Audio数据包的“一天”

让我们追踪一下从一个音乐应用发送到耳塞的一个音频数据包的完整传输过程:

示意图展示了音频数据包在LE Audio传输管道中经过的各个环节

上图详细展示了音频数据包在LE Audio传输管道中经过的每一个环节。

从最顶端开始:音乐应用生成PCM音频数据,这些数据会通过Android的AudioFlinger传递给蓝牙音频HAL。蓝牙音频HAL会将每10毫秒内的480个样本(采样频率为48 kHz)压缩成一个约120字节的帧。

这个压缩后的帧会被封装成ISO SDU格式的数据包,其中会包含时间戳和序列号等信息,然后通过HCI机制传输给蓝牙控制器。控制器会将这些SDU数据分割成链路层的PDU格式,然后在下一个预定的传输间隔内,通过协商好的物理层协议(例如2M PHY协议)将这些数据发送出去。

在耳塞端,控制器会接收这些数据包,重新组合ISO SDU格式的数据,然后将LC3帧传递给耳塞中的解码器。解码器会将这些数据还原成480个PCM采样值,这些采样值会被暂时存储起来,直到达到预定的显示延迟时间点,之后才会被发送到扬声器驱动芯片中进行播放。

总延迟:从手机到耳机的延迟约为40毫秒(其中包括10毫秒的帧处理时间、数据传输延迟以及音频呈现延迟)。相比之下,传统的蓝牙A2DP技术的延迟通常在100到200毫秒之间!

音频呈现延迟:实现同步的关键因素

音频呈现延迟是蓝牙LE Audio技术中的一个关键概念。这种延迟是在数据流建立阶段由双方共同确定的固定值。所有音频内容都必须严格按照以下公式进行播放:

渲染时间 = 参考点位置 + 音频呈现延迟

这样的设计能够确保:

  • 左右耳机的音频会同时被播放出来

  • 即使数据传输在两个声道之间存在差异,也不会影响音频的同步播放

  • 音频呈现延迟为接收端提供了“缓冲区”,有助于消除信号抖动

可以把这个过程想象成合唱团指挥:“所有人都在数字‘3’的时候开始唱歌,不能提前也不能推迟,必须正好在‘3’这个时刻。”

15. 总结

蓝牙LE Audio可以说是自蓝牙音频技术诞生以来最重要的升级。让我们回顾一下它的优势:

它解决了哪些问题

  • 更优秀的编解码器(LC3)——在相同的比特率下能够提供更好的音质,或者在较低的比特率下保持同样的音质

  • 多数据流传输——不再需要使用中继耳塞结构,从而延长电池续航时间

  • 广播音频功能(Auracast)——支持一对多的音频传输,为新的应用场景打开了大门

  • 适用于助听器——终于有了一个标准化、可互操作的解决方案

  • 统一的音频处理机制(BAP)——无论是播放音乐还是接听电话,都使用相同的设置,无需在A2DP和HFP模式之间切换

AOSP技术栈

  • 框架层:提供了`BluetoothLeAudio`和`BluetoothLeBroadcast`等API

  • 服务层`LeAudioService`负责协调所有音频处理流程

  • 原生层

    C++编写的`le_audio_client_impl`模块负责处理GATT协议、ASE状态机以及编解码器的协商过程

  • 控制器层CIS/BIS同步通道通过HCI接口进行管理

未来发展方向

蓝牙LE Audio技术仍在不断完善中。目前需要重点开发的领域包括:

  • 提高不同品牌设备之间的互操作性

  • 完善Auracast广播基础设施——相关场所需要安装广播发射设备

  • 支持双模式运行——在过渡期内,许多设备将同时支持传统蓝牙音频和蓝牙LE Audio技术

  • 进一步提升音质——随着蓝牙传输带宽的提高,LC3编解码器能够支持更高的比特率

  • 推动其在游戏领域的应用——超低延迟配置(7.5毫秒的帧处理时间,极小的音频呈现延迟)将为游戏带来更好的体验

从经典音频格式向LE音频格式的过渡不会一蹴而就。这一过程更类似于从IPv4向IPv6的过渡——是渐进的,有时会带来一些不便,但最终却是必要的。值得庆幸的是,这两种格式可以共存,而且AOSP系统也支持那些不支持LE音频功能的设备在无法使用LE音频时切换回经典音频格式。

所以下次当你戴上耳塞,聆听音乐并惊叹于其音质时,你就会清楚地知道:在这个庞大的协议栈中,究竟是哪些部分在正常工作,又是哪些部分出了问题,才导致声音无法从手机顺利传达到你的耳朵里。

祝编程愉快,愿你们发送的数据包总能保持同步传输!

参考资料

  1. 蓝牙技术联盟 — LE音频规范

  2. 蓝牙技术联盟 — LC3技术的详细介绍

  3. AOSP蓝牙模块代码库 — packages/modules/Bluetooth

  4. Zephyr项目官网 — LE音频协议栈文档

  5. Fraunhofer IIS研究所 — LC3编解码器

Comments are closed.