d331128e88
- 问题: 30-collaplex-eq.conf 的 node.target 是安装时探测一次写死的。开机时设备若还没枚举 (USB 耳机晚到很常见: 09-24 实测开机 08:57、耳机 09:19:43 才出现; 09-23 是 21:01 → 21:03), 建链时目标不存在 → 末段连到别处或干脆不连, 设备出现后不会自己改回来 → 听感"双重混响", 只能 stop + start - 新增 web/output_route.py: 设备清单(pw-dump) + 选择落盘(output.json) + 守护线程(每 3 秒核对 collaplex_eq_out 只连选中设备, 不对就拆错的、按声道补对的) → 设备一出现自动挂上 - web/server.py: GET /api/devices, POST /api/device(落盘 + 立刻挂载), 快照带 output 段, main() 起守护线程 - web/index.html: 「输出设备」卡片(下拉 + 应用 + 状态 + 守护备注; 设备表变化才重建选项, 免得 60 Hz 重建打断点击) - 脚本/安装.sh: 优先用记住的设备(不在位也照样按它建链), 不再"猜第一个 digital" - 实测: 面板真点应用切走再切回 ✓ / 连错 2 秒自动纠回 ✓ / 全拆 3 秒自动挂回 ✓ / start 自检 打印 [在位] ✓ / 面板像素验收 ✓; pyright strict 0 errors 0 warnings - 坑: pw-dump 的 Link 键名是 output-port-id / input-port-id(写 output-port 一条连线都读不到); 面板服务 enable --now 不会重启已在运行的实例(改 web/*.py 必须 restart)
52 lines
2.4 KiB
Plaintext
52 lines
2.4 KiB
Plaintext
# Collaplex 32 段 EQ + 总音量 —— 本文件由 脚本/安装.sh 生成(占位符 __EQ_WRAPPER__ / __TARGET__)
|
|
# 链路: ... -> HRTF 核心 -> [本图] 32 段 EQ + 总音量(pipe DSP) -> 数字输出
|
|
#
|
|
# ★ __TARGET__ 是**用户选定的输出设备**(落盘在 ~/.local/state/cinema-spatial/output.json,
|
|
# 面板「输出设备」卡片可改; 没选过则由安装脚本探测第一个数字输出)。
|
|
# 设备名跨重插是稳定的(含 USB 序列号), 所以设备晚到也不改这一行 —— 由面板守护
|
|
# (web/output_route.py)在设备出现后自动把它挂上去。
|
|
context.modules = [
|
|
{ name = libpipewire-module-filter-chain
|
|
flags = [ nofail ]
|
|
args = {
|
|
node.description = "Collaplex EQ + 总音量"
|
|
media.name = "Collaplex EQ"
|
|
filter.graph = {
|
|
nodes = [
|
|
{ type = builtin label = copy name = c1L }
|
|
{ type = builtin label = copy name = c1R }
|
|
{ type = builtin label = pipe name = eqpL config = { command = "__EQ_WRAPPER__" } }
|
|
{ type = builtin label = pipe name = eqpR config = { command = "__EQ_WRAPPER__" } }
|
|
{ type = builtin label = copy name = c2L }
|
|
{ type = builtin label = copy name = c2R }
|
|
]
|
|
links = [
|
|
{ output = "c1L:Out" input = "eqpL:In" }
|
|
{ output = "c1R:Out" input = "eqpR:In" }
|
|
{ output = "eqpL:Out" input = "c2L:In" }
|
|
{ output = "eqpR:Out" input = "c2R:In" }
|
|
]
|
|
inputs = [ "c1L:In" "c1R:In" ]
|
|
outputs = [ "c2L:Out" "c2R:Out" ]
|
|
}
|
|
capture.props = {
|
|
media.class = Audio/Sink
|
|
node.name = collaplex_eq_in
|
|
audio.channels = 2
|
|
audio.position = [ FL FR ]
|
|
# 同 10-: 整条链都不能空闲休眠, 否则客户端会停推
|
|
node.always-process = true
|
|
node.pause-on-idle = false
|
|
}
|
|
playback.props = {
|
|
node.name = collaplex_eq_out
|
|
audio.channels = 2
|
|
audio.position = [ FL FR ]
|
|
node.target = "__TARGET__"
|
|
node.always-process = true
|
|
node.pause-on-idle = false
|
|
}
|
|
}
|
|
}
|
|
]
|