[Problem feedback] 问题报告-Deepin25-USB声卡Sink缺失
Tofloor
poster avatar
Vellichor
deepin
5 hours ago
Author

问题报告:Deepin 25 外置 USB 声卡播放节点(Sink)无法创建

报告日期:2026-11-13
问题等级:高(设备完全不可用于播放,用户侧无任何提示)
涉及组件:pipewire / libspa-0.2-modules / wireplumber / dde-daemon
受影响版本:pipewire 1.6.4-1deepin10 及以后 × wireplumber 0.5.14-1deepin6 及以后
状态:已定位、已复现、已有可用规避方案、上游修复建议待提交


0. 摘要

Deepin 25 在 pipewire 中新增了属性 api.alsa.skip-formats-before-s16(默认关闭),
并在 wireplumber 中以 /etc 级全局规则对所有 USB 声卡的播放节点把它置为 true。
该属性能让格式枚举跳过所有位深高于 16bit 的候选格式。

当设备播放 PCM 只支持高于 16bit 的格式(本例仅 S24_3LE)时,枚举结果为空集,
mod.adapter 拿不到 format,节点创建中止,Sink 从未存在。
于是控制中心/dde-daemon 点击"启用外置声卡"时找不到对应 sink,表现为"点了没反应"。

这不是硬件问题、不是驱动问题、不是权限问题,也不是用户配置问题。
录音方向不受影响,因为规则只匹配 alsa_output.*。


1. 问题现象

1.1 用户可见现象

序号 现象 说明
S1 控制中心「声音 → 输出」中点选外置 USB 声卡,没有反应 选项存在但启用无效
S2 输出设备列表中该卡有时根本不出现 取决于面板刷新时机
S3 系统默认输出始终回落到板载声卡 无法保持选择
S4 录音设备列表里该卡正常存在可用 与 S1 形成强对比
S5 无任何前端报错、无提示、无弹窗 用户完全无从判断

1.2 系统侧现象

dde-daemon 的音频模块在日志中留下唯一一条直接线索:

daemon/audio[3883]: audio.go:913: sink not found for card #52 and port "analog-output"

#52 是 PipeWire 的 object.id,不是 ALSA card 号(本例 ALSA 为 card 2)。
该 id 每次服务重启都会变,不可作为定位依据,请使用 node.name / device.name。

pipewire 侧的真实错误链(每次会话启动、每次切换档案都会重现):

spa.alsa: front:2p: no format found (def:0) formats:S24_3LE
spa.alsa: front:2p: access:MMAP_INTERLEAVED RW_INTERLEAVED
mod.adapter: 0x...: can't get format: 没有那个文件或目录
wireplumber: Failed to create alsa_output.usb-SonicakeAudio...analog-stereo: PipeWire proxy destroyed

1.3 影响范围

  • 设备侧:所有"播放 PCM 仅支持 >16bit 格式"的 USB 音频设备。典型为 UAC 1.0 全速设备
    使用 24bit 打包格式(S24_3LE / S24_BE)、或仅支持 F32LE/S32LE 的 USB DAC。
  • 方向:仅播放。录音不受影响。
  • 范围:全局 /etc 规则,所有用户、所有 USB 声卡,与桌面环境无关(X11/Wayland 均受影响)。

2. 复现步骤

2.1 前置条件

Deepin 25(crimson)
pipewire / libspa-0.2-modules >= 1.6.4-1deepin10
wireplumber             >= 0.5.14-1deepin6
存在一台播放格式仅 >16bit 的 USB 声卡

先确认本机确实满足该条件(这一步是判断问题是否与你有关的关键):

# 找到 USB 声卡的 ALSA card 号
cat /proc/asound/cards

# 以 card 2 为例,查看播放端支持的全部格式
cat /proc/asound/card2/stream0

# 不想手填 card 号时,可直接定位
CARD=$(awk '/USB-Audio/{gsub(/^ +|\[|\]/,"",$1); print $1; exit}' /proc/asound/cards)
cat /proc/asound/card${CARD}/stream0 | sed -n '/Playback:/,/Capture:/p'

若 Playback: 段中 Format: 只出现 S24_3LE / S24_BE / S32_LE / F32_LE 等
没有 S16_LE,则本问题必然命中。

2.2 复现方法 A:观察法(无副作用)

# 1. 列出所有输出节点,确认该卡缺失
pactl list sinks short

# 2. 列出该卡档案,确认配置本身正常(应为 ...analog-stereo...)
#    注意:中文 locale 下 pactl 输出的是「名称:」「活动配置:」,故强制 C locale
LC_ALL=C pactl list cards | awk '/Name: alsa_card.usb-Sonicake/{f=1} f&&/Active Profile:/{print; exit}'

# 3. 确认录音方向正常存在(对照组)
pactl list sources short | grep -i sonic

判定:pactl list sinks 中没有 alsa_output.usb-...,
而 pactl list sources 中有 alsa_input.usb-...,即复现成功。

2.3 复现方法 B:主动重建法(可逆,推荐)

强制切一次档案,触发节点重建,并观察日志:

# 记录当前档案,便于回滚
LC_ALL=C pactl list cards | awk '/Name: alsa_card.usb-Sonicake/{f=1} f&&/Active Profile:/{print; exit}'

# 切到纯输出档案再切回(会短暂静音,不影响数据)
# 注意:这里是 pactl 的卡片索引(如 206),不是 ALSA card 号(如 2),两者无关
PCARD=$(pactl list cards short | awk '/Sonicake/{print $1}')
pactl set-card-profile "$PCARD" output:analog-stereo
sleep 1
pactl set-card-profile "$PCARD" output:analog-stereo+input:analog-stereo

# 读日志(用户级 journal)
journalctl --user --since "-2 min" _COMM=pipewire | grep -E 'no format|can.t get format'

判定:出现 no format found (def:0) formats:S24_3LE 且 sink 依旧不出现,即复现成功。

2.4 复现方法 C:最小代码级复现(可精确定位到属性)

创建两个临时节点,唯一差别是有无该属性。测试完毕必须销毁:

# C1 对照组:不设置该属性 → 应当成功建出 sink
pw-cli create-node adapter '{
  factory.name=api.alsa.pcm.sink
  node.name=usbtest-ctl
  api.alsa.path="hw:2,0"
  media.class=Audio/Sink
  object.linger=true
}'
sleep 1; pactl list sinks short | grep usbtest-ctl     # 预期:出现,s24le 2ch 48000Hz

# C2 实验组:设置该属性 = true → 应当失败
pw-cli create-node adapter '{
  factory.name=api.alsa.pcm.sink
  node.name=usbtest-exp
  api.alsa.path="hw:2,0"
  api.alsa.skip-formats-before-s16=true
  media.class=Audio/Sink
  object.linger=true
}'
sleep 1; pactl list sinks short | grep usbtest-exp     # 预期:不出现

# 清理(按 pw-cli ls Node 里的全局 id 销毁)
pw-cli ls Node | grep -B1 usbtest
pw-cli destroy 

判定:C1 成功、C2 失败,即证明"该属性是唯一变量",与 PCM 名称、档案、端口、驱动均无关。

实测对照(本机,13:04–13:10):
hw:2,0 不设属性 → 成功(s24le 2ch 48000Hz,pw-play 播放 1.5s 无报错);
front:2 不设属性 → 成功;front:2 + 属性= true → 失败;
切换 output:analog-stereo / pro-audio 档案 → 均失败。

2.5 非复现路径(这些操作无效,不必再试)

尝试 结果 原因
切换卡配置档案(analog-stereo / pro-audio / duplex) 无效 失败发生在节点创建阶段,与档案无关
在设置里选择该卡为默认输出 无效 对象不存在,无法成为默认
重启 pipewire / wireplumber 每次重建仍失败 规则是持久配置,重启只会重演
更换 USB 口 无效 与端口/带宽无关
用 pavucontrol 手动路由 无效 同上,无 sink 可路由

3. 问题是如何产生的(时序链路)

① 会话启动 / 声卡热插拔 / 用户切换配置档案
        │
        ▼
② WirePlumber 的 ALSA 监控创建 ACP 设备与节点
        │  同时应用 /etc/wireplumber/wireplumber.conf.d/skip-before-s16.conf
        │  → alsa_output.* 且 alsa.driver_name=snd_usb_audio
        │  → update-props: api.alsa.skip-formats-before-s16 = true
        ▼
③ mod.adapter 请求节点格式 → 进入 spa.alsa 的 enum_pcm_formats()
        │  ALSA 硬件实际能力:仅 S24_3LE
        │  补丁逻辑:跳过一切非 S16_LE/S16_BE 的候选,遇到 S16 才停止跳过
        │  本设备没有 S16 → 整个候选表被跳过 → 候选数 j == 0
        ▼
④ 日志:spa.alsa: front:2p: no format found (def:0) formats:S24_3LE
        ▼
⑤ mod.adapter: can't get format → 节点创建中止
        ▼
⑥ 结果:alsa_output.usb-...analog-stereo 从未存在
        │   (而 alsa_input.usb-... 正常,因为规则只匹配 alsa_output.*)
        ▼
⑦ dde-daemon 音频模块尝试对 card 的 analog-output 端口找 sink
        │  找不到 → audio.go:913: sink not found for card #52 and port "analog-output"
        ▼
⑧ 前端表现:点击"启用"无反应,默认输出回落板载

关键点:失败在 ⑥ 之前。所有在 ⑦⑧ 层面做的操作(选默认、改端口、改档案)都治不了。


4. 由谁引入、在哪个版本/场景引入

4.1 两个独立变更,缺一不可

环节 组件与版本 变更内容 作者 / 时间 证据来源
A. 机制 pipewire 1.6.4-1deepin10(含 libspa-0.2-modules) 新增属性 api.alsa.skip-formats-before-s16,默认关闭 qaqland ``,2026-05-28 包内 changelog.Debian.gz;补丁 debian/patches/Fix-Skip-audio-formats-before-S16.patch
B. 策略 wireplumber 0.5.14-1deepin6 下发全局规则把该属性置 true,匹配 node.name=~alsa_output.* + alsa.driver_name=snd_usb_audio anguoli ``,2026-10-14 包内 changelog.Debian.gz 首条;/etc/wireplumber/wireplumber.conf.d/skip-before-s16.conf

A 单独存在不会造成任何行为变化(属性位域默认 0)。只有 B 落地后问题才会显现。
因此问题的暴露起点是 wireplumber 0.5.14-1deepin6(2026-10-14)。

4.2 该配置并非新写

wireplumber 0.5.14-1deepin6 的变更说明是"从 os-config 迁移配置片段":

* Migrate WirePlumber configuration snippets from os-config,
  now installed to /etc/wireplumber/wireplumber.conf.d/:
    - bluetooth-autoswitch-off.conf: disable Bluetooth profile auto-switching
    - skip-before-s16.conf: skip formats before S16 on USB audio output
                                               — anguoli, 2026-10-14

对应 PR:deepin-community/wireplumber#15,集成工单 BUG-379319。
即:这是一条历史遗留的现场 workaround,此前由 os-config 包投递,2026-10 才搬进
wireplumber 自己的 /etc conffile,从而对所有安装该版本的机器默认生效。

4.3 触发场景(满足全部三条才会命中)

  1. 系统处于上述版本区间;
  2. 使用 USB 音频设备(alsa.driver_name = snd_usb_audio);
  3. 该设备的播放 PCM 不支持任何 ≤16bit 格式。

三者缺一,问题不会出现。这也解释了为什么绝大多数用户没有感知。


5. 根本原因分析

5.1 直接原因:格式枚举产生空集,且没有兜底

补丁 Fix-Skip-audio-formats-before-S16.patch 的核心逻辑(原文摘录):

+	unsigned int skip_formats_before_s16:1;                 /* 位域,默认 0 */

+	} else if (spa_streq(k, "api.alsa.skip-formats-before-s16")) {
+		state->skip_formats_before_s16 = spa_atob(s);        /* 需显式给属性 */

+		if (skip_before_s16) {
+			if (fi->spa_format != SPA_AUDIO_FORMAT_S16_LE &&
+			    fi->spa_format != SPA_AUDIO_FORMAT_S16_BE) {
+				... continue;                                /* 一律跳过 */
+			}
+			skip_before_s16 = false;                          /* 遇 S16 即停止跳过 */
+		}

其语义是"从格式表开头逐个跳过,直到遇见 S16 才停"。
设计假设是"设备至少支持 S16"。当这个假设不成立时(本例),整张表被跳空,
enum_pcm_formats() 以 j == 0 结束,上层必然拿不到格式。

代码中没有空集兜底——这是缺陷的核心:

/* 缺失的保护,等价于: */
if (j == 0 && state->skip_formats_before_s16) {
        /* 回退:不跳过,重新枚举一遍 */
}

5.2 策略层原因:命中面过宽

matches = [ { node.name = "~alsa_output.*", alsa.driver_name = "snd_usb_audio" } ]
  • 以驱动名为判据:snd_usb_audio 名下覆盖数千种设备,无 VID/PID 白名单;
  • 以位深为唯一手段:把 24/32bit 设备统一压到 16bit;
  • 无前置判断:不去检查"该设备是否支持 S16",也不检查"该设备是否真的有问题"。

代价与收益严重不对称:可能出问题的设备是少数,但降级(乃至本例的完全不可用)
由所有 USB 声卡用户承担。24bit 理论动态范围约 120 dB,16bit 约 96 dB,
对正经外置解码器是可测量的倒退。

5.3 动机推断(官方未说明,按证据强度排序)

公开的 changelog、PR 描述、补丁注释均只写 what,未写 why。以下为基于代码形态与硬件特征的推断:

排序 可能动机 支持证据 反证/存疑
1 USB 1.0 全速设备高位深下爆音/断流 规则仅针对 alsa_output + USB → 投诉集中在放音;本机设备恰为 bcdUSB 1.00 + 仅 S24_3LE;Synch Type: None(无显式同步端点,靠隐式回馈),该组合在 24bit 打包格式下周期边界易出问题 无公开 bug 编号可佐证
2 带宽余量为零 本机端点 wMaxPacketSize 0x0120 = 288 字节/帧,bInterval 1,即 288000 B/s,恰好等于 48k×2ch×3B,余量为 0;降到 16bit 后仅需 192000 B/s(降 33%) 补丁未限制采样率,若纯为带宽应优先压采样率
3 部分设备描述符虚标能力 业界常见:报 F32/S32 实际仅 16bit 稳定 无本机证据
4 直通高位深后音量/增益异常(Windows 侧驱动带 DSP,Linux 直通后偏响/失真) 与同批次的 Fix-Optimize-the-volume-algorithm.patch 时间相近 属推测

上一版报告中我曾判定"不是带宽问题"。核对 USB 描述符后需修正:该设备等时端点
余量精确为 0,降位深确实能显著降低带宽占用,故带宽动机不能排除。
无论动机为何,都不影响本次缺陷的定性:手段过宽 + 空集无兜底。

5.4 已排除的其他原因(附判断依据)

类别 期望证据 实测 结论
设备未识别 aplay -l 缺卡 / dmesg 枚举失败 card 2 存在,播放/录音 PCM 齐备 排除
驱动缺失 snd_usb_audio 未加载 正常加载,stream0 可读 排除
权限问题 /dev/snd 不可访问 节点齐全,录音可开流 排除
设备被占用 pcm0p/sub0/status 为 RUNNING 恒为 closed 排除
服务异常 多实例 / 崩溃重启 单实例,无崩溃 排除
用户配置干扰 ~/.config/pipewire* 覆盖 排查期间为空,问题依旧 排除
双工/档案冲突 换档案即恢复 换档案、pro-audio 均无效 排除
硬件故障 ALSA 层直接播放失败 pw-cli 直建节点可正常出声 排除

6. 解决办法

适用范围警告(必读)
本方案仅适用于:设备播放 PCM 不支持任何 ≤16bit 格式,且已按 §2 复现出
no format found 的机器。
不要把它当作"USB 声卡通用优化"批量下发:对本来正常工作的设备,它会把 24bit
播放能力白扔掉;对没有此问题的发行版版本,它是一条无效配置。

6.1 方案一:用户级覆盖(推荐,改动最小)

原理:~/.config/wireplumber/wireplumber.conf.d/ 在 /etc 之后加载,
同名数组 monitor.alsa.rules 追加,后应用的规则覆盖前者,从而把该属性改回 false。
不要修改 /etc 下那个文件本身——它是 dpkg conffile,改动会在升级时触发冲突提示。

步骤 1:创建配置文件

mkdir -p ~/.config/wireplumber/wireplumber.conf.d

写入 ~/.config/wireplumber/wireplumber.conf.d/51-usb-soniccube.conf:

# 针对 Sonicake Sonic Cube USB Audio (84ef:0038)
# 该设备播放 PCM 仅支持 S24_3LE,会被 skip-formats-before-s16 跳过导致 sink 建不出来。
# 仅对本设备关闭该开关,不改变系统对其他 USB 声卡的行为。

monitor.alsa.rules = [
  {
    matches = [
      { device.name = "alsa_card.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00" }
    ]
    actions = {
      update-props = {
        api.alsa.skip-formats-before-s16 = false
      }
    }
  }
  {
    matches = [
      { node.name = "~alsa_(output|input).usb-SonicakeAudio" }
    ]
    actions = {
      update-props = {
        api.alsa.skip-formats-before-s16 = false
      }
    }
  }
]

设备级 + 节点级各写一条,用于覆盖两种属性生效时机(设备 Props 与节点 Props)。

步骤 2:重启会话管理器

systemctl --user restart wireplumber
sleep 2

步骤 3:验证

# 期望输出形如:... alsa_output.usb-SonicakeAudio_...analog-stereo  PipeWire  s24le 2ch 48000Hz  SUSPENDED
pactl list sinks short | grep -i sonic

# 期望输出:该设备路径
pactl get-default-sink

# 期望:无任何输出(计数为 0)
journalctl --user --since "-2 min" _COMM=pipewire | grep -c 'no format found'

预期结果:sink 出现,格式为 s24le 2ch 48000Hz;默认输出自动指向该卡
(若此前 ~/.local/state/wireplumber/default-nodes 中已设定,会自行恢复)。
suspend 状态是空闲挂起,有音频流即转 running,不是故障。

步骤 4(可选):若控制中心仍显示板载,重启托盘或面板以刷新缓存

pkill -f dde-control-center; dde-control-center &

回滚:

rm ~/.config/wireplumber/wireplumber.conf.d/51-usb-soniccube.conf
systemctl --user restart wireplumber

6.2 方案二:系统级覆盖(多用户环境)

在 /etc/wireplumber/wireplumber.conf.d/ 下新增一个文件(新增文件不会与包管理的
conffile 冲突)。

文件名必须以排在 s 之后的字符开头(如 zz-)。同一目录内按文件名字典序加载、
后加载的规则后应用;若命名为 99-*.conf 会排在 skip-before-s16.conf 之前
('9' < 's'),反而被后者覆盖,方案失效。

sudo tee /etc/wireplumber/wireplumber.conf.d/zz-usb-soniccube.conf >/dev/null <<'EOF'
monitor.alsa.rules = [
  {
    matches = [ { device.name = "alsa_card.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00" } ]
    actions = { update-props = { api.alsa.skip-formats-before-s16 = false } }
  }
]
EOF
systemctl --user restart wireplumber   # 每个登录会话各执行一次

用户级方案(§6.1)不受此限制:~/.config/wireplumber/ 整目录在 /etc 之后加载。

6.3 方案三:对这张卡关闭 ACP(备用,非首选)

若方案一生效不稳定,可让 WirePlumber 不走 ACP、直接用原生 ALSA 建节点。
代价是设置中不再出现"声卡"条目(失去端口/档案抽象,只剩输出设备):

monitor.alsa.rules = [
  {
    matches = [ { device.name = "alsa_card.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00" } ]
    actions = { update-props = { api.alsa.use-acp = false } }
  }
]

本机未采用(方案一已足够),仅作降级路径记录。

6.4 明确不建议的做法(避免误用)

做法 为什么不建议
直接编辑 /etc/wireplumber/wireplumber.conf.d/skip-before-s16.conf dpkg conffile,升级会弹冲突;且对全局所有 USB 声卡生效,波及他人
全系统关闭该属性(= false 不加设备匹配) 会移除发行版对所有 USB 声卡的兼容策略,可能让原本靠降级才稳定的设备重新爆音
audio.format = "S16LE" 强制指定 本设备硬件不支持 S16,会直接 ENOTSUP,症状不变
卸载/降级 wireplumber 或 pipewire 破坏系统音频栈完整性,且会连带丢失其他 deepin 补丁(CVE 修复等)
用 pulseaudio 替换 PipeWire 与 DDE 当前架构冲突,代价远大于收益
改 alsa.driver_name 判据的 alsa.conf 影响所有 USB 声卡,且不在问题路径上
换成 32bit float 声卡/换设备 掩盖问题,不解决

7. 相关硬件与软件参数(针对性依据)

7.1 整机

项 值
机型 Jiaolong15K Series GM5BG5E(机械革命 蛟龙 15K)
主板 GM5BG5E
CPU AMD Ryzen 7 7435H
显卡 NVIDIA AD107M GeForce RTX 4050 Max-Q [10de:28a1]
核显 无(单显卡机型)
板载音频控制器 AMD Ryzen HD Audio [1022:15e3]
板载 codec Realtek ALC256
音频协处理器 AMD Audio Coprocessor [1022:15e2]
显卡 HDMI 音频 NVIDIA AD107 HDA [10de:22be]
USB 控制器(本设备所在) AMD Rembrandt USB4 XHCI #4 [1022:161e],PCI 0000:06:00.4

7.2 外置声卡(问题设备)

项 值
产品名 SonicakeAudio Sonic Cube USB Audio
USB ID 84ef:0038
USB 版本 bcdUSB 1.00(UAC 1.0)
速率 full speed(12 Mbps)
拓扑路径 usb-0000:06:00.4-1,Bus 003 / Device 007
ALSA card card 2,id Audio(USB-Audio - Sonic Cube USB Audio)
PCM 节点 pcm0p(播放)/ pcm0c(录音),共享同一 PCM 设备 0
播放格式 仅 S24_3LE,2ch,44100 / 48000 Hz,24 bit
录音格式 仅 S24_3LE,2ch,44100 / 48000 Hz,24 bit
端点 播放 0x02 (OUT),录音 0x81 (IN),均 Isochronous / Synch Type: None
包大小 wMaxPacketSize 0x0120 = 288 字节,bInterval 1
带宽余量 288 B/ms = 288000 B/s,恰好等于 48k×2ch×3B,余量为 0
混音器 usbmixer 无任何控件(ctrlif=0, ctlerr=0)
子帧/位深 bSubframeSize 3、bBitResolution 24
通道 bNrChannels 2

为什么这组参数是决定性的:bBitResolution 24 + bSubframeSize 3 决定了 ALSA
只能提供 S24_3LE;stream0 中播放侧不存在任何 S16_*,因此
"跳过 S16 之前的格式"必然跳空。换任何只在 16bit 有候选的设备,都不会复现。

7.3 软件版本

组件 版本 与问题关系
发行版 Deepin 25(crimson,社区版,Build build1) —
内核 6.18.56-amd64-desktop-rolling(#25.01.01.40,2026-10-13) 无关(ALSA/USB 层正常)
会话 X11(XDG_SESSION_TYPE=x11) 无关
pipewire / pipewire-bin / pipewire-pulse 1.6.4-1deepin22 含问题补丁(自 deepin10 起)
libpipewire-0.3-0 1.6.4-1deepin22 同上
libspa-0.2-modules 1.6.4-1deepin22 补丁实际所在(spa/plugins/alsa)
wireplumber 0.5.14-1deepin6 下发全局规则(自该版本起)
libasound2 / libasound2-data 1.2.15.3-1deepin7 无关
dde-daemon 6.1.111 报错呈现方(audio.go:913)
deepin-desktop-schemas 6.0.13 无关

7.4 对象命名(跨重启稳定,可用于配置匹配)

device.name  alsa_card.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00
node.name    alsa_output.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00.analog-stereo
node.name    alsa_input.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00.analog-stereo
alsa.driver_name  snd_usb_audio
card.profile  output:analog-stereo+input:analog-stereo

PipeWire 的 object.id(如 #52、#206、sink #219)每次重启都会变化,
配置与沟通中一律不要使用数字 id。


8. 是否适用于你的设备:三步判定

# ① 确认全局规则存在且生效(存在即说明系统带此策略)
grep -r 'skip-formats-before-s16' /etc/wireplumber/ 2>/dev/null

# ② 列出你设备播放端支持的格式
CARD=$(awk '/USB-Audio/{gsub(/^ +|\[|\]/,"",$1); print $1; exit}' /proc/asound/cards)
echo "ALSA card = $CARD"
sed -n '/^Playback:/,/^Capture:/p' /proc/asound/card${CARD}/stream0 | grep 'Format:'

# ③ 看日志是否真的踩中
journalctl --user --since "-1 day" _COMM=pipewire | grep -c 'no format found'
① 有规则 ② 播放格式含 S16_LE/S16_BE ③ 有 no format found 结论与动作
是 是 否 不需要任何改动。规则正在把你降到 16bit,能出声;若在意音质,可按 §6.1 对本设备关闭
是 否 是 命中本问题,按 §6.1 处理
是 否 否 观察即可;若换设备/换版本后出现无声,优先怀疑本问题
否 — — 与本问题无关,另找原因

③ 的注意事项:若你已经应用 §6.1 的修复,no format found 计数会变为 0,
此时"② 否 + ③ 否"不代表没命中过,而是"已修好"。想确认历史命中情况,用更长的时间窗:

journalctl --user --since "-7 day" _COMM=pipewire | grep -c 'no format found'

或临时移走用户配置后重启 wireplumber,观察 sink 是否消失(可逆)。


9. 附录

9.1 证据采集命令清单(可直接复跑)

# 系统与版本
cat /etc/os-release; uname -a
awk '/^Package: (pipewire|libspa-0.2-modules|wireplumber)$/{p=$2} p&&/^Version:/{print p,$2;p=""}' /var/lib/dpkg/status

# 硬件
cat /proc/asound/cards
cat /proc/asound/card2/stream0
lsusb -v -d 84ef:0038
cat /proc/asound/card2/usbmixer
lspci -nn | grep -iE 'usb|audio'

# PipeWire 对象
pactl list cards short; pactl list sinks short; pactl list sources short
pw-dump > /tmp/dump.json
journalctl --user -b _COMM=pipewire | grep -E 'no format|can.t get format'
journalctl --user -b _COMM=wireplumber | grep -i 'failed to create'

# 策略来源
cat /etc/wireplumber/wireplumber.conf.d/skip-before-s16.conf
zcat /usr/share/doc/libspa-0.2-modules/changelog.Debian.gz | grep -n -i 's16'
zcat /usr/share/doc/wireplumber/changelog.Debian.gz | head -20

9.2 关键日志原文(本机实测)

# 11:56:16 会话启动,首次失败
spa.alsa: front:2p: no format found (def:0) formats:S24_3LE
spa.alsa: front:2p: access:MMAP_INTERLEAVED RW_INTERLEAVED
mod.adapter: 0x...: can't get format: 没有那个文件或目录
wireplumber: Failed to create alsa_output.usb-SonicakeAudio...analog-stereo: PipeWire proxy destroyed

# 打开 log.level=4 后的枚举过程
I spa.alsa [alsa-pcm.c:1222:spa_alsa_open]: ALSA device open 'front:2' playback
D spa.alsa [alsa-pcm.c:1741:debug_hw_params]: enum_pcm_formats:
D spa.alsa [alsa-pcm.c:726:log_write]: FORMAT:  S24_3LE
I spa.alsa [alsa-pcm.c:1762:enum_pcm_formats]: front:2p: skip audio formats before S16
I spa.alsa [alsa-pcm.c:1812:enum_pcm_formats]: front:2p: skip format F32LE
I spa.alsa [alsa-pcm.c:1812:enum_pcm_formats]: front:2p: skip format S32LE
I spa.alsa [alsa-pcm.c:1812:enum_pcm_formats]: front:2p: skip format S24_32LE
I spa.alsa [alsa-pcm.c:1812:enum_pcm_formats]: front:2p: skip format S24LE
I spa.alsa [alsa-pcm.c:1818:enum_pcm_formats]: front:2p: reached S16LE, stop skipping
W spa.alsa [alsa-pcm.c:1860:enum_pcm_formats]: front:2p: no format found (def:0) formats:S24_3LE

# DDE 侧
daemon/audio[3883]: audio.go:913: sink not found for card #52 and port "analog-output"

注意 reached S16LE, stop skipping 这行的含义:它只是把"继续跳过"的开关关掉
(因为表里存在 S16LE 条目),并不代表硬件支持 S16LE。硬件实际只有 S24_3LE,
所以在跳过阶段结束后,snd_pcm_format_mask_test() 对所有候选都不成立,最终仍为空集。
这是该补丁最容易误读、也最容易写错的地方。

9.3 修复后验证记录(2026-11-13 13:11:32)

215  alsa_output.pci-0000_01_00.1.hdmi-stereo                                  s32le 2ch 48000Hz  SUSPENDED
219  alsa_output.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00.analog-stereo s24le 2ch 48000Hz  SUSPENDED
223  alsa_output.pci-0000_06_00.6.analog-stereo                                 s32le 2ch 48000Hz  SUSPENDED

默认音频入口:alsa_output.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00.analog-stereo
默认信源:    alsa_input.usb-SonicakeAudio_Sonic_Cube_USB_Audio_V1.0.0-00.analog-stereo
重启后 'no format found' 计数:0

9.4 参考

  • 补丁原文:deepin-skip-before-s16.patch(本目录,取自 pipewire_1.6.4-1deepin22.debian.tar.xz)
  • 迁移 PR:https://github.com/deepin-community/wireplumber/pull/15(工单 BUG-379319)
  • 上游对照:spa/plugins/alsa/alsa-pcm.c(PipeWire master 中不存在该属性,确认为发行版定制)
  • 排查过程记录:同目录 外置声卡无法启用-排查报告.md

10. 结论

  1. 现象:外置 USB 声卡在设置中启用无效,输出设备缺失,录音正常。
  2. 机制:格式枚举被 skip 策略跳空 → can't get format → Sink 未创建 →
    dde-daemon 报 sink not found。
  3. 引入:机制来自 pipewire 1.6.4-1deepin10(2026-05-28,qaqland);
    策略来自 wireplumber 0.5.14-1deepin6(2026-10-14,anguoli,由 os-config 迁入)。
    暴露起点是后者。
  4. 根因:api.alsa.skip-formats-before-s16 假设"设备至少支持 S16",
    对仅高位深设备无空集兜底;下发规则以驱动名为判据,命中面过宽。
  5. 解决:按 device.name 精确匹配,把该属性对本设备置 false,重启 wireplumber。
    已实测生效,播放恢复为 s24le 2ch 48000Hz。
  6. 推广警示:仅当设备播放端没有任何 ≤16bit 格式时才适用;
    对正常设备使用会造成 24bit 能力白丢,属滥用。
Reply Favorite View the author
All Replies

No replies yet