[Internal testing communication] 可能是第一个在deepin25用上AAC蓝牙编码的用户
Tofloor
poster avatar
昨夜的星辰
deepin
2026-09-10 19:58
Author

关于蓝牙编码的问题我折腾了好多次,有时候折腾到半夜,搞的人火都起来https://bbs.deepin.org.cn/post/288847

继前些天让小U同学自动编译内核之后突发奇想让小U同学分析一下这个问题,本来也没想着能解决,想着能理出来思路也行

结果,结果,结果,竟然成了。小U直接把控制中心的选项都给弄出来了

24171f516587a495b92599d90005494b.png

问1:检查一下系统现在使用的蓝牙音频编码格式
问2:请帮我切换到AAC

好的,我先检查一下系统音频服务(PulseAudio 还是 PipeWire)以及 AAC 编解码库是否已安装,再决定怎么切换。

好消息:系统已安装 libfdk-aac(Fraunhofer FDK AAC 库),但当前 PipeWire 的蓝牙插件列表里没看到 AAC 插件。我进一步确认一下 PipeWire 是否编译了 AAC 支持,以及 WirePlumber 的编解码器配置:

发现关键线索:PipeWire 插件已内置 AAC 支持,而且用户配置目录里有个 .bak 备份文件恰好启用了 aac 编码。我再确认下当前生效的配置文件:

情况明确了:

  • ✅ PipeWire 蓝牙插件已内置 AAC 支持
  • ✅ 系统已装 libfdk-aac 库
  • ❌ 当前没有生效的 WirePlumber 配置(只有一个 .bak 备份,内容正是启用 aac 的配置)

现在我来恢复这个配置并重启音频服务,让 AAC 编码生效:

配置文件已恢复。现在重启音频服务使配置生效:

音频服务已重启,但蓝牙设备当前只显示了通话(HFP)配置,A2DP 音频配置暂时消失。我看下完整状态并重新连接设备:

A2DP 音频配置在重启后消失了,这是重启音频服务后的常见现象。我通过重新连接蓝牙设备来恢复:

设备已重新连接,A2DP 配置恢复了(SBC / SBC-XQ),但 AAC 配置仍然没有出现。我需要排查是配置没生效,还是音箱本身不支持 AAC:

日志里没看到编解码协商信息。我再查一下音箱本身通过蓝牙广播支持哪些 A2DP 编码(这是决定能否用 AAC 的关键):

SDP 记录只说明音箱支持 A2DP 协议,具体编码需要看 AVDTP 协商结果。我先确认配置是否被 WirePlumber 正确加载:

配置加载情况还不明确,我深入检查一下 PipeWire 中蓝牙监视器的完整配置和设备协商出的编码列表:

配置信息还没完全确认。我通过开启蓝牙插件的调试日志,直接查看音箱协商时上报的编码端点(SEP)列表,这是判断设备是否支持 AAC 的最可靠方式:

日志没有输出,我检查一下调试日志是否生效并查看更完整的输出:

日志中未捕获到编码协商信息。我改用直接捕获调试输出的方式,彻底确认音箱上报的编码能力:

调试日志级别不够。我用更高级别的调试重试一次,抓取设备上报的编码端点:

pkill 误杀了自身命令,我改用精确的进程名方式重试:

手动进程在运行,但调试输出仍然没有编码细节。我换用 WirePlumber 自身的调试变量确认配置文件是否被加载:

配置文件确认已被加载(日志显示 section 'monitor.bluez.properties' is used as-is from ...51-monitor.bluez.properties.conf)。现在重连设备,在完整调试日志中查找它上报的编码端点:

日志确认了关键信息:音箱只有一个编码端点(sep1),且只用于 SBC/SBC-XQ 协商。我再搜索日志中设备上报的全部编码端点列表,做最终确认:

🎯 找到根本原因了! 日志显示:

Bluetooth codec plugin api.codec.bluez5.media.aac not available
无法打开共享对象文件: .../libspa-codec-bluez5-aac.so: 没有那个文件或目录

系统缺少 AAC 编解码插件文件 libspa-codec-bluez5-aac.so(虽然 FDK AAC 库已装,但 PipeWire 的 AAC 桥接插件缺失)。我来查找安装这个插件:

包已确认:Deepin 编译的 libspa-0.2-bluetooth(1.6.4)没有附带 AAC 插件(依赖列表里也没��� fdk-aac)。在想办法获取插件前,我先确认音箱本身是否支持 AAC(如果不支持,装插件也没用):

从日志看,音箱有 4 个端点(sep1-4),sep1 用于 SBC,其余端点编码不明——但因为本地 AAC 插件缺失,无法确认音箱是否支持 AAC。最稳妥的做法是先把缺失的 AAC 插件装上。我搜索一下哪个软件包提供它:

搜索结果显示系统有编译工具但缺少 meson。我先查询 Debian 官方仓库中该插件是否可用(这是最快的获取途径):

packages.debian.org 被拦截了。我换用 Debian 的 API 查询该插件是否在 Debian 的软件包中:

sudo 需要密码,无法直接安装编译工具。我采用另一条路:直接从 Debian 官方镜像下载软件包索引,确认其是否包含 AAC 插件(不需要 root):

Debian trixie 的版本是 1.4.2,依赖列表同样没有 fdk-aac。我直接下载这个 .deb 包检查内容里是否真的有 AAC 插件:

Debian 官方包也不包含 AAC 插件(Deepin 和 Debian 都没编译它)。在决定是否自行编译前,我先直接读取音箱各端点的编码 ID(0x00=SBC,0x02=AAC),确认它到底支不支持 AAC:

🎯 重大发现!音箱本身是支持 AAC 的!

sep2 的 Codec ID = 2(AAC),capabilities 80 01 8c 84 09 b6 正是 AAC 编码参数!也就是说:问题纯粹在系统侧缺少 AAC 插件。sep1=SBC、sep2=AAC、sep3/sep4=通话编码。

现在确认获取插件的可行途径,先看看 Arch Linux 是否提供预编译的 AAC 插件:

Arch 的页面是动态加载的。我直接查它的 PKGBUILD 构建脚本,看是否编译了 AAC 支持:

Arch 也被反爬拦截。我换用直接下载源码的方式——PipeWire 的 AAC 插件源码是单文件,可以用 gcc 直接编译。先下载 PipeWire 1.6.4 源码(与系统版本一致)和 fdk-aac 开发头文件:

两个文件都下载成功。现在解压源码,检查 AAC 插件源码的结构和编译方式,同时解压 fdk-aac 开发头文件:

源码结构清晰。现在查看编译配置,确认需要哪些头文件和编译参数:

编译配置明确了:需要 a2dp-codec-aac.c + media-codecs.c 两个文件。我检查是否依赖生成的头文件(config.h)和其他编译参数:

编译需要额外的 bluetooth/bluetooth.h 头文件(libbluetooth-dev)和 -DCODEC_PLUGIN 宏。我先确认插件加载器对插件目录的搜索机制(决定如何让系统找到新插件),同时下载缺少的蓝牙开发头文件:

蓝牙头文件已就绪。现在确认插件目录的解析机制:

确认了 SPA_PLUGIN_DIR 是单一路径覆盖机制。我再仔细看下 codec-loader 的具体加载方式,寻找最稳妥的安装途径:

加载机制确认。现在开始编译 AAC 插件(使用刚下载的头文件,编译成与系统 PipeWire 1.6.4 匹配的插件):

链接到了静态库导致失败,改用系统已有的共享库来链接:

使用 -l:libfdk-aac.so 强制链接共享库重新编译:

开发包里的 .so 符号链接是断的(目标文件不在包内)。直接链接系统已装的共享库:

✅ 编译成功! 插件已生成(47KB),导出标准 SPA 工厂符号,正确链接系统 fdk-aac 库。

现在部署插件。由于无法用 sudo 写入系统目录,我采用用户级方案:镜像 spa 插件目录到用户目录并添加新插件,然后仅为 wireplumber 服务设置插件目录环境变量:

镜像完成(6.2MB,仅新增 AAC 插件)。现在为 wireplumber 服务创建配置覆盖,指定用户插件目录:

服务已带新环境变量重启。现在重新连接蓝牙设备,检查 AAC 编码是否出现:

🎉 AAC 编码出现了! 现在音箱的可用配置里多了 a2dp-sink (codec AAC)。立即切换到 AAC:

✅ AAC 切换成功! 确认 bluetoothAudioCodec: "aac"。最后清理之前的调试环境变量,并做完整状态确认:

咦,编码显示又回到了 sbc_xq?让我检查一下实际状态:

AAC 配置仍然可用,但活动配置被自动切回了 sbc_xq。我重新切换到 AAC 并持续监控,确认是否稳定:

AAC 切换后约 10 秒又被自动切回 SBC-XQ。查看 WirePlumber 日志找出是谁在"抢回"配置:

找到关键线索:切换时 spa.audioconvert 报 "out of buffers"(缓冲区不足),导致 AAC 链路建立失败并回退到 SBC-XQ。这通常发生在切换时有音频正在播放的情况。现在没有活动音频流,我再次切换并观察:

仍然回退,且无错误日志。我检查 WirePlumber 的状态恢复文件和完整日志,找出回退的真正触发源:

状态文件里记录着 bluez_card...=a2dp-sink-sbc_xq,说明有恢复机制。我需要弄清楚是谁在回切。先开启调试日志捕捉回切瞬间的详细信息:

切换命令报"无此实体",可能重启后卡片名有变化。先查看当前卡片状态:

重启后设备配置还没协商好(显示 off)。重新连接设备并查看完整配置:

设备已重连,AAC 配置可用。现在开启调试日志的情况下切换到 AAC,捕捉回切瞬间的详细过程:

AAC 传输建立失败(Failure in Bluetooth audio transport)。先确认调试环境变量是否真正生效,并查看完整日志:

调试日志没有完整输出到 journald。我改用之前有效的方式——手动运行 wireplumber 并把完整调试日志写到文件,然后复现 AAC 切换过程:

AAC 切换实际成功过(codec switched status 0),但 0.5 秒后又有请求把编码切回 SBC-XQ。我在日志里找出是谁发起了"回切"请求:

找到模式了:AAC 切换成功后,节点重建时外部程序又把配置切回了 sbc_xq。系统中正好有 Deepin 的控制中心/会话守护进程在运行,很可能是它们保存的"首选配置"在作祟。我检查 Deepin 存储的音频配置:

找到了嫌疑文件:audio-config-keeper.json(音频配置守护)。查看这些配置内容:

找到元凶了! Deepin 音频守护进程的 audio.json 里保存着 "bluez_card.50_88_11_06_15_0B": "a2dp-sink-sbc_xq",它会在设备变化时强制恢复这个配置。我修改它并同步切换:

配置已修改并切换。关键测试:等待一段时间看是否还会被回切:

audio.json 已改但依然回切,说明还有别的恢复源。我查看 WirePlumber 自己的状态文件是否也在强制恢复,并检查调试日志中是谁发出了 SetProfile 请求:

WirePlumber 的自动切换脚本正在保存/恢复 sbc_xq 配置。我读取这个脚本的逻辑,理解它的恢复机制:

脚本的 restoreProfile 逻辑不会在我们处于非通话配置时回切(已排除)。回切发生在 AAC 成功后的 0.018 秒内——这是 PipeWire 内部的编码选择逻辑。查看编码器的优先顺序定义:

AAC 的优先级高于 SBC-XQ(排序中 AAC 在前),所以不是优先级问题。我深入查看 ensure_media_codec 和 check_profiles 的代码逻辑,找出触发回切的内部条件:

回切速度太快(18毫秒),必然是内部调用。我找出所有触发 ensure_media_codec 的调用点:

真相大白! 回切的真正来源是 WirePlumber 的状态文件 default-profile(还存着 a2dp-sink-sbc_xq)。编码切换导致节点重建时,WirePlumber 用这个文件恢复"用户保存的配置",把编码又切回 SBC-XQ。我来修正这个状态文件:

切换完成。现在进行关键的稳定性验证(等待较长时间确认不再回切):

状态文件都改了还是回切。再次运行完整调试捕获,这次精确定位是谁调用了 set_profile:

连接超时了,检查服务状态并重试:

有两个 wireplumber 进程在冲突!清理后重新开始:

环境干净了。现在切换 AAC 并完整捕获回切过程的调用链:

关键日志出现了!setting profile 2 codec:X 记录中 codec 编号需要对照枚举值。查看编码枚举定义:

枚举明确了:codec:2 = SBC_XQ,codec:4 = AAC。日志显示 AAC(codec:4)设置后 0.6 秒又有 codec:2 save:1 的调用。查看回切调用前的上下文找出调用者:

save:1 标记说明这是"用户保存的配置恢复"操作。我搜索是谁通过 D-Bus 发起的这次调用:

看到关键元数据:device.restore-profile = true。检查状态文件当前内容(可能被 WirePlumber 又写回了 sbc_xq):

状态文件在 11:44:42 被 WirePlumber 重新写回了 sbc_xq——恢复机制确认存在。查看 WirePlumber 的配置恢复脚本,弄清恢复触发条件:

配置恢复机制清楚了。现在查看回切(11:44:38.059)前 9 毫秒内的事件流,找出是谁发起:

bluez-profile-changed 钩子只保存不设置,已排除。现在怀疑是 dde-daemon 进程(独立进程,内存里缓存着旧配置 sbc_xq)。查看当前连接的音频客户端:

确认关键嫌疑人:dde-session-daemon(go-pulseaudio 客户端)和 dde-control-center 都连接着音频服务!dde-daemon 内存里缓存了 sbc_xq,会在检测到配置变化时强制恢复。先检查 audio.json 是否被它写回,然后重启 dde 守护进程使其重新加载:

audio.json 保持正确(未被写回)。dde-daemon 运行中缓存了旧值。查找它的 D-Bus 服务,看能否通过接口更新配置或安全重启:

找到 org.deepin.dde.Audio1 接口!查看它的方法,看能否通过它正确更新配置:

🎯 终极元凶找到! dde 音频守护进程有专门的蓝牙音频模式属性:

  • BluetoothAudioMode = "a2dp-sink-sbc_xq" ← 它一直在强制这个!
  • SetBluetoothAudioMode(s) 方法 ← 正确的修改途径!

通过官方接口设置 AAC:

调用报错但属性已变为 a2dp-sink、编码已是 AAC!立即验证稳定性——等待观察是否还会回切:

🎉🎉 AAC 编码稳定保持! 连续 45 秒无回切,dde 与 PipeWire 状态一致。现在收尾:恢复正常服务模式(保留插件目录配置、移除调试日志),并做最终验证:

服务恢复正常(单个实例)。重新连接设备做最终验证:

✅ 最终验证通过!AAC 编码稳定保持! 以下是完整总结:


🎉 切换完成:系统现使用 AAC 蓝牙编码

最终状态

项目 状态
蓝牙设备 Xiaomi Speaker-3511
当前编码 AAC(bluetoothAudioCodec: "aac")✅
活动配置 a2dp-sink(AAC)
稳定性 重连后 30 秒+ 无回切 ✅

排查过程(为什么之前不行���

  1. 系统缺少 AAC 插件:Deepin 编译的 libspa-0.2-bluetooth 包没有附带 libspa-codec-bluez5-aac.so(Debian 官方包同样没有)
  2. 音箱本身支持 AAC:通过读取蓝牙端点确认 sep2 的 Codec ID = 2(AAC)
  3. dde 守护进程强制回切:Deepin 音频守护进程内存缓存了旧编码(sbc_xq),每次切换后 0.6 秒内强制恢复

解决方案(无需 root)

  1. 编译插件:从 PipeWire 1.6.4 源码(与系统版本一致)用 gcc 编译出 AAC 编码插件
  2. 用户级部署:
    • 插件安装到 ~/.local/lib/spa-0.2/bluez5/libspa-codec-bluez5-aac.so
    • 通过 systemd 覆盖配置(~/.config/systemd/user/wireplumber.service.d/override.conf)设置 SPA_PLUGIN_DIR 指向用户插件目录
  3. 同步 dde 配置:通过 D-Bus 调用 org.deepin.dde.Audio1 的 SetBluetoothAudioMode("a2dp-sink"),更新了 Deepin 音频守护进程的缓存配置

⚠️ 注意事项

  • 系统更新 PipeWire 时:~/.local/lib/spa-0.2/ 是镜像的系统插件目录,若 PipeWire 大版本更新,建议重新同步(rm -rf ~/.local/lib/spa-0.2 && cp -a /usr/lib/x86_64-linux-gnu/spa-0.2 ~/.local/lib/spa-0.2 再拷贝插件)
  • 若以后发现又被切回 SBC:重新执行 busctl --user call org.deepin.dde.Audio1 /org/deepin/dde/Audio1 org.deepin.dde.Audio1 SetBluetoothAudioMode s a2dp-sink
  • 编译源码和临时文件在 /tmp/,重启后自动清理,不影响使用

现在用 AAC(默认 320 kbps)听音乐,相比 SBC-XQ 在中高频细节和压缩效率上会有更好表现。有其他需要随时告诉我!

Reply Favorite View the author
All Replies
avatar
waittingsummer
deepin
2026-09-11 09:40
#1

好贴,希望官方跟进

Reply View the author
avatar
deepin流云
Super Moderator
Community OP
2026-09-11 10:41
#2
waittingsummer:

好贴,希望官方跟进

有需求在跟进了,研发那边昨天已经构建了本地的包:

企业微信截图_17890201041002.png

等后续某个版本的系统更新即可
企业微信截图_17890205748471.png

Reply View the author
avatar
LiuYongzhang
deepin
2026-09-11 12:23
#3

AAC(高级音频编码)是有专利限制的。以下是关键信息汇总:

专利现状

  • 专利池管理:主要由 Via Licensing Alliance(Via LA) 管理(此前为 MPEG LA),部分专利归 Fraunhofer 等持有方所有。
  • 授权费用:商业使用 AAC 编码器/解码器需缴纳授权费,常见计费方式:
    • 按设备收费:约 0.98 美元/台(售价 ≤$50 的基准费率),售价更高则按售价比例(约 1.95%)计算
    • 按收入分成:年收入高的企业可谈判分成(典型 0.5%–1.5%)
    • 部分协议有年度最低消费(如 ≥10 万美元)
  • 专利到期情况:
    • 基础专利已于 2022 年陆续到期
    • 扩展专利(HE-AAC、HE-AACv2、xHE-AAC 等)持续到 2025–2027 年
  • 侵权风险:未合规使用可能面临高额索赔(美国案例单例赔偿可达 15 万美元)。

各 Profile 费率不同

AAC-LC / HE-AAC / HE-AAC v2 / xHE-AAC 等不同 Profile 的授权费率不同,使用前需确认具体使用的 Profile。

合规/免费方案

方案 说明
Opus 完全开源免费,低延迟,适合实时通信
MP3 专利已于 2017 年全部过期,免费
FFmpeg 原生 AAC 编码器 零专利风险,但音质略逊于 FDK-AAC
libfdk-aac 音质好,但需单独授权,存在专利风险

使用建议

  • 商业项目使用 AAC 前,务必确认是否已获得 Via LA 授权(尤其是硬件设备、流媒体服务场景)。
  • 如果是原型/学习用途,可使用 FFmpeg 内置解码器或原生编码器规避风险。
  • 实时通信等场景优先考虑 Opus,可完全规避专利问题。
Reply View the author
avatar
昨夜的星辰
deepin
2026-09-11 13:01
#4
LiuYongzhang:

AAC(高级音频编码)是有专利限制的。以下是关键信息汇总:

专利现状

  • 专利池管理:主要由 Via Licensing Alliance(Via LA) 管理(此前为 MPEG LA),部分专利归 Fraunhofer 等持有方所有。
  • 授权费用:商业使用 AAC 编码器/解码器需缴纳授权费,常见计费方式:
    • 按设备收费:约 0.98 美元/台(售价 ≤$50 的基准费率),售价更高则按售价比例(约 1.95%)计算
    • 按收入分成:年收入高的企业可谈判分成(典型 0.5%–1.5%)
    • 部分协议有年度最低消费(如 ≥10 万美元)
  • 专利到期情况:
    • 基础专利已于 2022 年陆续到期
    • 扩展专利(HE-AAC、HE-AACv2、xHE-AAC 等)持续到 2025–2027 年
  • 侵权风险:未合规使用可能面临高额索赔(美国案例单例赔偿可达 15 万美元)。

各 Profile 费率不同

AAC-LC / HE-AAC / HE-AAC v2 / xHE-AAC 等不同 Profile 的授权费率不同,使用前需确认具体使用的 Profile。

合规/免费方案

方案 说明
Opus 完全开源免费,低延迟,适合实时通信
MP3 专利已于 2017 年全部过期,免费
FFmpeg 原生 AAC 编码器 零专利风险,但音质略逊于 FDK-AAC
libfdk-aac 音质好,但需单独授权,存在专利风险

使用建议

  • 商业项目使用 AAC 前,务必确认是否已获得 Via LA 授权(尤其是硬件设备、流媒体服务场景)。
  • 如果是原型/学习用途,可使用 FFmpeg 内置解码器或原生编码器规避风险。
  • 实时通信等场景优先考虑 Opus,可完全规避专利问题。

纠结这玩意儿干啥?openSUSE老早可以用AAC,以前deepin上用pulseaudio的时候也有人折腾AAC,用不用得成AAC在deepin一直是一个技术问题,并不是专利什么的原因;

实在不行deepin告诉方法,用户自己找相关的东西安装就行了,但现实是压根就没有相关的操作方法,网上找到的方法在deepin上也行不通。如果不是AI,就算你搞成了,系统又自动切换回sbc,你可能都发现不了,会一直以为是自己没折腾成功

image.png

Reply View the author
avatar
绍贝格尔
deepin
2026-09-11 13:33
#5

厉害

Reply View the author
avatar
泳衡
deepin
2026-09-11 15:08
#6

感谢你的添砖加瓦。

Reply View the author