Linux 蓝牙音频软件栈实现分析

Linux 蓝牙音频软件栈实现分析

    • 蓝牙协议栈简介
    • 蓝牙控制器探测
    • BlueZ 插件系统及音频插件

蓝牙协议栈简介

蓝牙协议栈是实现蓝牙通信功能的软件架构,它由多个层次组成,每一层负责特定的功能。蓝牙协议栈的设计遵循蓝牙标准 (由蓝牙技术联盟Bluetooth SIG 定义),支持多种蓝牙配置文件 (Profiles),以满足不同的应用场景 (如音频传输、文件传输、健康设备、键盘鼠标这样的输入输出设备等)。

蓝牙各个应用场景的实现,如音频传输、文件传输和键盘鼠标这样的输入设备,与系统中常规的这些功能的实现大为不同。如对于音频播放和录制,通过 USB 连接的音频设备,或通过 audio codec 实现的音频播放和录制,在 Linux 中,基于 ALSA 框架实现,内核通过导出设备文件向用户空间暴露相应的硬件能力。USB 键盘鼠标,在 Linux 中,基于输入设备框架实现,内核同样通过导出设备文件向用户空间暴露相应的硬件能力。

可与蓝牙协议栈类比的不是系统中常规的各个功能的实现,而是 TCP/IP 网络协议栈。在实现上,与 TCP/IP 网络协议栈类似,蓝牙协议栈不同功能的各个协议层次实现分布于硬件、Linux 操作系统内核、BlueZ 这样的蓝牙系统服务和 PulseAudio 这样系统服务中。

Bluetooth SIG 官方的蓝牙核心规范 (蓝牙核心规范 6.0) 给出的蓝牙核心系统架构如下图所示:
Bluetooth core system architecture
蓝牙协议栈的分层结构如下图所示:

+--------------------------------------------------------------------------------------------+
|                   Application Layer                                                        |
|  (Profiles: A2DP, HFP, HSP, AVRCP, HAP, BAP, ACS, ACAS, GAP, GATT, FTP, OPP, etc.)         |
+--------------------------------------------------------------------------------------------+
|                   Middleware Layer                                                         |
|  (Protocols: AVDTP, AVCTP, SDP, ATT, RFCOMM, OBEX, TCS, BNEP, etc.)    |
+--------------------------------------------------------------------------------------------+
|                   Host Controller Interface (HCI)                                          |
|  (Protocols: HCI Commands, Events, and Data)                                               |
+--------------------------------------------------------------------------------------------+
|                   Logical Link Control and                                                 |
|                   Adaptation Protocol (L2CAP)                                              |
+--------------------------------------------------------------------------------------------+
|                   Baseband Layer                                                           |
|  (Protocols: Link Manager Protocol (LMP), SCO, eSCO, ACL, ISOC, etc.)                            |
+--------------------------------------------------------------------------------------------+
|                   Radio Layer                                                              |
|  (Physical Layer: Bluetooth Radio)                                                         |
+--------------------------------------------------------------------------------------------+

蓝牙协议栈各层次简单说明如下:

  • 应用层:实现具体的蓝牙应用功能 (如音频传输、文件传输)。通过蓝牙配置文件 (Profiles) 定义设备的行为。常见的应用层协议/配置文件有 A2DP (Advanced Audio Distribution Profile,高质量音频传输),HFP (Hands-Free Profile,免提通话),HSP (Headset Profile,耳机通话),AVRCP (Audio/Video Remote Control Profile,远程控制音频/视频设备),HAP (Hearing Aid Profile,用于助听器设备),BAP (Bluetooth Audio Profile,用于通用音频设备),ACS (Audio Control Service,提供音频控制功能(如音量调节、播放控制),基于 GATT/ATT 实现,通过暴露特性(Characteristics)供应用程序使用),ACAS (Audio Stream Control Service,提供音频流管理功能(如流的创建、配置、删除),基于 GATT/ATT 实现,与 Isochronous Channels(ISOC) 协作,实现低延迟音频流传输),GATT (Generic Attribute Profile,定义基于 ATT 的服务和特性,用于数据传输,提供逻辑信道管理,支持客户端-服务器模型),GAP (Generic Access Profile,定义设备角色 (如广播者、观察者、中心设备、外围设备) 和连接流程,负责设备发现、连接建立和安全控制),FTP (File Transfer Profile,文件传输),OPP (Object Push Profile,对象推送 (如联系人、图片)),PAN (Personal Area Network Profile,个人局域网),HID (Human Interface Device Profile,人机接口设备 (如键盘、鼠标) 等。

  • 中间件层:提供高层协议和服务,支持应用层的功能实现。常见的中间件层协议有,SDP (Service Discovery Protocol,服务发现协议,用于查找设备支持的服务),RFCOMM (Radio Frequency Communication,串口仿真协议,用于模拟 RS-232 串口通信),OBEX (Object Exchange Protocol,对象交换协议,用于文件传输和数据同步),TCS (Telephony Control Protocol Specification,电话控制协议,用于语音通话),BNEP (Bluetooth Network Encapsulation Protocol,网络封装协议,用于蓝牙网络共享),AVDTP (Audio/Video Distribution Transport Protocol,音频/视频传输协议,负责音频流的传输和控制,它定义了音频流的建立、配置、启动、暂停和停止等操作),AVCTP (Audio/Video Remote Control Profile,音频/视频远程控制协议,蓝牙协议栈中的控制传输协议,负责音频/视频控制命令的传输,它定义了控制命令的封装和传输机制),ATT (Attribute Protocol,用于在 BLE 设备之间传输属性数据,提供基于客户端-服务器的数据访问机制) 等。

  • HCI 层:提供主机和蓝牙控制器之间的通信接口。负责传输命令、事件和数据。

  • L2CAP 层:提供多路复用、分段和重组功能,支持上层协议的数据传输。管理逻辑链路,提供可靠的数据传输服务。

  • 基带层:管理物理链路,处理蓝牙设备的连接和通信。负责频率跳变、数据包格式化和错误检测。常见的基带层协议有 LMP (Link Manager Protocol,链路管理协议,负责设备之间的连接建立和维护),SCO (Synchronous Connection-Oriented link,同步面向连接链路,用于语音传输),ACL (Asynchronous Connectionless link,异步无连接链路,用于数据传输),ISOC (Isochronous Channels,提供同步数据传输通道,支持低延迟的音频流传输)。

  • 射频层:负责蓝牙无线电信号的发送和接收。处理频率跳变、调制和解调。使用蓝牙无线电协议,主要工作在 2.4 GHz ISM 频段。

蓝牙协议栈相对于 TCP/IP 网络协议栈,其各层之间并不是那么的各自独立,而是紧密关联的。蓝牙协议栈中与音频相关的有 4 个用于不同场景的子协议栈,它们分别是用于传输高质量音频流的 A2DP,包括 A2DP -> AVDTP -> L2CAP -> ACL;用于通过蓝牙远程控制音频/视频设备的 AVRCP,包括 AVRCP -> AVCTP -> L2CAP -> ACLA2DPAVRCP 常协作实现蓝牙音频;用于语音通话的 HFP/HSP,包括 HFP/HSP -> SCO/eSCO;用于低功耗蓝牙的 HAP/BAP,包括 HAP/BAP -> ACS/ACAS -> GATT -> ATT -> GAP -> ISOC。 除 HAP/BAP 协议栈外,其它的都是经典蓝牙的协议栈。

类比于 TCP/IP 网络协议栈中的 RTP/RTCP 协议,A2DP/AVDTP 协议类似于 RTP 协议,AVRCP/AVCTP 协议类似于 RTCP 协议,L2CAP/ACL 协议类似于 UDP 协议,只是它们是可靠传输协议。

在实现上,HCI 及更下层的协议无疑由 Linux 内核或硬件实现。应用层和中间件层协议的实现则常随着时间的流逝而变化。低功耗蓝牙是比较新的蓝牙标准,对低功耗蓝牙的支持是从 BlueZ 5.55 版本开始逐步添加的。对于 Linux 内核,则是从 Linux 5.13 版本开始,逐步支持 Isochronous Channels。

在早期的 BlueZ 版本中,PulseAudio 这样的音频服务需要将音频流数据通过 Unix Domain Socket 发送给 BlueZ,再由 BlueZ 通过 A2DP 协议发送给蓝牙硬件设备。从 BlueZ 5.0 开始,BlueZ 的音频功能(如 A2DP)逐渐被移出 BlueZ 核心代码库,转而由 PipeWire 或 PulseAudio 这样的系统音频服务器直接处理音频流的传输。BlueZ 不再直接处理音频流数据,而是通过 D-Bus 接口 与音频后端(如 PipeWire 或 PulseAudio)交互。AVDTP 的实现由音频后端负责,BlueZ 仅提供蓝牙协议栈的核心功能(如设备管理、连接管理)。音频后端负责音频流的编码、解码和传输。音频后端直接与蓝牙硬件交互,处理音频流数据。

蓝牙控制器探测

BlueZ 是 Linux 官方蓝牙协议栈,提供对蓝牙无线通信标准的全面支持。核心协议方面,它支持 L2CAP(逻辑链路控制与适配协议),RFCOMM(串口仿真协议),SDP(服务发现协议),HCI(主机控制器接口)。配置文件方面,它支持 A2DP(高级音频分发),AVRCP(音视频远程控制),HFP(免提协议),HID(人机接口设备),PAN(个人局域网)。硬件设备类型方面,它支持音频设备,如蓝牙耳机、音箱;输入设备,如键盘、鼠标;网络连接,如蓝牙 PAN;物联网,如智能家居设备。它还提供一系列与蓝牙设备管理控制有关的工具程序,如 bluetoothd,蓝牙守护进程,管理设备和服务;bluetoothctl,命令行工具,用于设备配对、连接等操作;hcitool,配置蓝牙适配器及查询设备信息;sdptool,浏览和发布 SDP 服务记录。

BlueZ 整个项目的代码丰富而复杂,这里主要关注与蓝牙音频有关的逻辑。

BlueZ 系统服务 bluetoothd 启动时,执行 adapter_init() 函数初始化蓝牙适配器,这个调用过程如下:

#0  adapter_init () at src/adapter.c:10337
#1  0x0000aaaaaaac3398 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:1216

adapter_init() 函数定义 (位于 src/adapter.c) 如下:

int adapter_init(void)
{dbus_conn = btd_get_dbus_connection();mgmt_primary = mgmt_new_default();if (!mgmt_primary) {error("Failed to access management interface");return -EIO;}if (getenv("MGMT_DEBUG"))mgmt_set_debug(mgmt_primary, mgmt_debug, "mgmt: ", NULL);DBG("sending read version command");if (mgmt_send(mgmt_primary, MGMT_OP_READ_VERSION,MGMT_INDEX_NONE, 0, NULL,read_version_complete, NULL, NULL) > 0)return 0;error("Failed to read management version information");return -EIO;
}

adapter_init() 函数访问一下 DBus 连接,调用 mgmt_new_default() 函数创建并初始化 struct mgmt 对象,设置 struct mgmt 的调试配置,并调用 mgmt_send() 函数向 struct mgmt 发送一个读取版本号的请求。

mgmt_new_default() 函数定义 (位于 src/shared/mgmt.c) 如下:

struct mgmt {int ref_count;int fd;bool close_on_unref;struct io *io;bool writer_active;struct queue *request_queue;struct queue *reply_queue;struct queue *pending_list;struct queue *notify_list;unsigned int next_request_id;unsigned int next_notify_id;bool need_notify_cleanup;bool in_notify;void *buf;uint16_t len;uint16_t mtu;mgmt_debug_func_t debug_callback;mgmt_destroy_func_t debug_destroy;void *debug_data;
};. . . . . .
static void mgmt_set_mtu(struct mgmt *mgmt)
{socklen_t len = 0;/* Check if kernel support BT_SNDMTU to read the current MTU set */if (getsockopt(mgmt->fd, SOL_BLUETOOTH, BT_SNDMTU, &mgmt->mtu,&len) < 0) {/* If BT_SNDMTU is not supported then MTU cannot be changed and* MTU is fixed to HCI_MAX_ACL_SIZE.*/mgmt->mtu = HCI_MAX_ACL_SIZE;return;}if (mgmt->mtu < UINT16_MAX) {uint16_t mtu = UINT16_MAX;/* Try increasing the MTU since some commands may go* over HCI_MAX_ACL_SIZE (1024)*/if (!setsockopt(mgmt->fd, SOL_BLUETOOTH, BT_SNDMTU, &mtu,sizeof(mtu)))mgmt->mtu = mtu;}
}struct mgmt *mgmt_new(int fd)
{struct mgmt *mgmt;if (fd < 0)return NULL;mgmt = new0(struct mgmt, 1);mgmt->fd = fd;mgmt->close_on_unref = false;mgmt->len = 512;mgmt->buf = malloc(mgmt->len);if (!mgmt->buf) {free(mgmt);return NULL;}mgmt->io = io_new(fd);if (!mgmt->io) {free(mgmt->buf);free(mgmt);return NULL;}mgmt->request_queue = queue_new();mgmt->reply_queue = queue_new();mgmt->pending_list = queue_new();mgmt->notify_list = queue_new();if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {queue_destroy(mgmt->notify_list, NULL);queue_destroy(mgmt->pending_list, NULL);queue_destr

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/72532.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JetBrains(全家桶: IDEA、WebStorm、GoLand、PyCharm) 2024.3+ 2025 版免费体验方案

JetBrains&#xff08;全家桶: IDEA、WebStorm、GoLand、PyCharm&#xff09; 2024.3 2025 版免费体验方案 前言 JetBrains IDE 是许多开发者的主力工具&#xff0c;但从 2024.02 版本起&#xff0c;JetBrains 调整了试用政策&#xff0c;新用户不再享有默认的 30 天免费试用…

1.8PageTable

页表的作用 虚拟地址空间映射&#xff1a;页表记录了进程的虚拟页号到物理页号的映射关系。每个进程都有自己的页表&#xff0c;操作系统为每个进程维护一个独立的页表。内存管理&#xff1a;页表用于实现虚拟内存管理&#xff0c;支持进程的虚拟地址空间和物理地址空间之间的…

Prosys OPC UA Gateway:实现 OPC Classic 与 OPC UA 无缝连接

在工业自动化的数字化转型中&#xff0c;设备与系统之间的高效通信至关重要。然而&#xff0c;许多企业仍依赖于基于 COM/DCOM 技术的 OPC 产品&#xff0c;这给与现代化的 OPC UA 架构的集成带来了挑战。 Prosys OPC UA Gateway 正是为解决这一问题而生&#xff0c;它作为一款…

数据结构------线性表

一、线性表顺序存储详解 &#xff08;一&#xff09;线性表核心概念 1. 结构定义 // 数据元素类型 typedef struct person {char name[32];char sex;int age;int score; } DATATYPE;// 顺序表结构 typedef struct list {DATATYPE *head; // 存储空间基地址int tlen; …

【WPF】在System.Drawing.Rectangle中限制鼠标保持在Rectangle中移动?

方案一&#xff0c;在OnMouseMove方法限制 在WPF应用程序中&#xff0c;鼠标在移动过程中保持在这个矩形区域内&#xff0c;可以通过监听鼠标的移动事件并根据鼠标的当前位置调整其坐标来实现。不过需要注意的是&#xff0c;WPF原生使用的是System.Windows.Rect而不是System.D…

基于银河麒麟系统ARM架构安装达梦数据库并配置主从模式

达梦数据库简要概述 达梦数据库&#xff08;DM Database&#xff09;是一款由武汉达梦公司开发的关系型数据库管理系统&#xff0c;支持多种高可用性和数据同步方案。在主从模式&#xff08;也称为 Master-Slave 或 Primary-Secondary 模式&#xff09;中&#xff0c;主要通过…

系统思考全球化落地

感谢加密货币公司Bybit的再次邀请&#xff0c;为全球团队分享系统思考课程&#xff01;虽然大家来自不同国家&#xff0c;线上学习的形式依然让大家充满热情与互动&#xff0c;思维的碰撞不断激发新的灵感。 尽管时间存在挑战&#xff0c;但我看到大家的讨论异常积极&#xff…

Figma的汉化

Figma的汉化插件有客户端版本与Chrome版本&#xff0c;大家可根据自己的需要进行选择。 下载插件 进入Figma软件汉化-Figma中文版下载-Figma中文社区使用客户端&#xff1a;直接下载客户端使用网页版&#xff1a;安装chrome浏览器汉化插件国外推荐前往chrome商店安装国内推荐下…

【Go语言圣经2.5】

目标 了解类型定义不仅告诉编译器如何在内存中存储和处理数据&#xff0c;还对程序设计产生深远影响&#xff1a; 内存结构&#xff1a;类型决定了变量的底层存储&#xff08;比如占用多少字节、内存布局等&#xff09;。操作符与方法集&#xff1a;类型决定了哪些内置运算符…

IDEA 一键完成:打包 + 推送 + 部署docker镜像

1、本方案要解决场景&#xff1f; 想直接通过本地 IDEA 将最新的代码部署到远程服务器上。 2、本方案适用于什么样的项目&#xff1f; 项目是一个 Spring Boot 的 Java 项目。项目用 maven 进行管理。项目的运行基于 docker 容器&#xff08;即项目将被打成 docker image&am…

SpringBoot 第一课(Ⅲ) 配置类注解

目录 一、PropertySource 二、ImportResource ①SpringConfig &#xff08;Spring框架全注解&#xff09; ②ImportResource注解实现 三、Bean 四、多配置文件 多Profile文件的使用 文件命名约定&#xff1a; 激活Profile&#xff1a; YAML文件支持多文档块&#xff…

深度解析React Native底层核心架构

React Native 工作原理深度解析 一、核心架构&#xff1a;三层异构协作体系 React Native 的跨平台能力源于其独特的 JS层-Shadow层-Native层 架构设计&#xff0c;三者在不同线程中协同工作&#xff1a; JS层 运行于JavaScriptCore&#xff08;iOS&#xff09;或Hermes&…

对话智能体的正确打开方式:解析主流AI聊天工具的核心能力与使用方式

一、人机对话的黄金法则 在与人工智能对话系统交互时&#xff0c;掌握以下七项核心原则可显著提升沟通效率&#xff1a;文末有教程分享地址 意图精准表达术 采用"背景需求限定条件"的结构化表达 示例优化&#xff1a;"请用Python编写一个网络爬虫&#xff08…

Xinference大模型配置介绍并通过git-lfs、hf-mirror安装

文章目录 一、Xinference开机服务systemd二、语言&#xff08;LLM&#xff09;模型2.1 配置介绍2.2 DeepSeek-R1-Distill-Qwen-32B&#xff08;大杯&#xff09;工具下载git-lfs&#xff08;可以绕过Hugging Face&#xff09; 2.3 DeepSeek-R1-Distill-Qwen-32B-Q4_K_M-GGUF&am…

MyBatis操纵数据库-XML实现(补充)

目录 一.多表查询二.MyBatis参数赋值(#{ }和${ })2.1 #{ }和${ }的使用2.2 #{ }和${ }的区别2.3 SQL注入2.3 ${ }的应用场景2.3.1 排序功能2.3.2 like查询 一.多表查询 多表查询的操作和单表查询基本相同&#xff0c;只需改变一下SQL语句&#xff0c;同时也要在实体类中创建出…

快速导出接口设计表——基于DOMParser的Swagger接口详情半自动化提取方法

作者声明&#xff1a;不想看作者声明的&#xff08;需要生成接口设计表的&#xff09;直接前往https://capujin.github.io/A2T/。 注&#xff1a;Github Pages生成的页面可能会出现访问不稳定&#xff0c;暂时没将源码上传至Github&#xff0c;如有需要&#xff0c;可联系我私…

TS常见内置映射类型的实现及应用场景

以下是 TypeScript 在前端项目中 常用的映射类型&#xff08;Mapped Types&#xff09;&#xff0c;结合具体场景和代码示例&#xff0c;帮助开发者高效处理复杂类型&#xff1a; 一、基础映射类型 1. Partial<T> 作用&#xff1a;将对象类型 T 的所有属性变为可选。 实…

介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测

下面为你详细介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测&#xff0c;包含环境配置、数据准备、模型训练以及推理等步骤。 1. 环境配置 首先&#xff0c;你需要安装必要的库&#xff0c;主要是ultralytics库&#xff0c;它包含了YOLOv8模型。你可以使用以下命令进…

AI-医学影像分割方法与流程

AI医学影像分割方法与流程–基于低场磁共振影像的病灶识别 – 作者:coder_fang AI框架&#xff1a;PaddleSeg 数据准备&#xff0c;使用MedicalLabelMe进行dcm文件标注&#xff0c;产生同名.json文件。 编写程序生成训练集图片&#xff0c;包括掩码图。 代码如下: def doC…

【Python】09、字典

文章目录 1. 字典简介2. 字典的使用2.1 字典创建2.2 字典值获取2.3 字典值修改2.4 字典的删除 3. 字典的遍历 1. 字典简介 字典(dict)属于一种新的数据结构&#xff0c;称为映射(mapping)。 字典的作用和列表类似&#xff0c;但是查询性能比列表好&#xff1b;在字典中每个元…