本文记录一台机械革命星耀 14(XINGYAO Series-P916F-STX)在 Ubuntu Linux 下的音频修复过程,供同型号或硬件配置相近的设备参考。
重要:不要直接照抄本文中的 PCI 地址、声卡编号或 HDA 节点。 需要先确认自己的机器使用相同的 Realtek ALC256 和 subsystem ID。
0x1B的修复命令只在本文硬件上验证过。
1. 硬件和软件环境
本文实测环境:
机型:XINGYAO Series-P916F-STX
系统:Ubuntu 26.04.1 LTS
内核:Linux 7.0.0-42-generic
声卡:Realtek ALC256 + AMD ACP-PDM
PipeWire:1.6.2
WirePlumber:0.5.13
确认机型:
cat /sys/class/dmi/id/product_name
cat /sys/class/dmi/id/board_name
确认声卡:
cat /proc/asound/cards
aplay -l
arecord -l
本文机器的相关声卡如下:
card 1: Generic_1 [HD-Audio Generic]
device 0: ALC256 Analog
card 2: acppdmmach [acp-pdm-mach]
device 0: DMIC capture dmic-hifi-0
确认 codec 和 subsystem ID:
grep -H -E '^(Codec:|Vendor Id:|Subsystem Id:)' \
/proc/asound/card*/codec#0
本文目标硬件必须包含:
Codec: Realtek ALC256
Vendor Id: 0x10ec0256
Subsystem Id: 0x1d05e004
如果 subsystem ID 不同,不要直接使用本文的 0x1B 修复命令。
2. 故障表现
本文机器原本有两个相互关联但独立的问题:
- 默认数字麦克风可以显示输入电平,但实际录音没有有效人声,或者只有开头的“嗒”声。
- 内置扬声器音量偏小、低频不足、声音偏薄。
- 3.5mm 耳机不总能被正确识别。原先已经通过脚本切换 codec 输出开关来绕过这个问题。
默认 HiFi/UCM 配置同时暴露了两条录音路径:
AMD ACP-PDM:acppdmmach
Realtek ALC256 HDA:Generic_1
本次排查中,默认 ACP-PDM 路径未获得可用录音;改为 ALC256 HDA 录音路径并调整增益后,使用者反馈麦克风改善。这里没有对 ACP-PDM 做原始样本级根因分析,不能据此断言所有同型号机器的数字麦克风都存在同一故障。
此外,Realtek codec 的 0x1B 节点默认 pin 配置标记为未连接,运行时处于输入、输出放大器静音状态。结合参考文章与本机启用后的实际试听,确认该节点用于缺失的第二组内置扬声器。只使用第一组 0x14 时,声音会比较小、低频不足。
开始前:工具、备份和硬件核对
Ubuntu 可安装以下排查工具:
sudo apt install alsa-utils alsa-tools pulseaudio-utils
command -v hda-verb amixer alsactl pactl wpctl
pulseaudio-utils 在这里仅用于提供 pactl 客户端,不需要把 PipeWire 换成 PulseAudio。wpctl 由 WirePlumber 提供;耳机脚本中的通知命令 notify-send 是可选功能,Ubuntu 可通过 libnotify-bin 安装。
改配置前先备份,尤其不要覆盖已有耳机脚本或其他人的音频规则:
backup="$HOME/audio-backup-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup"
cp -a ~/.config/wireplumber "$backup/user-wireplumber" 2>/dev/null || true
cp -a ~/.local/bin/toggle-audio.sh "$backup/" 2>/dev/null || true
sudo cp -a /etc/wireplumber "$backup/system-wireplumber" 2>/dev/null || true
alsactl -f "$backup/alsa.state" store Generic_1
pactl list cards > "$backup/cards.txt"
pactl list sinks > "$backup/sinks.txt"
pactl list sources > "$backup/sources.txt"
cat /sys/class/sound/hwC1D0/user_pin_configs > "$backup/user_pin_configs.txt"
这里的 Generic_1、hwC1D0 必须先核对再使用。如果 user_pin_configs 中已有其他设置,不要直接使用后文的安装示例:应先确认已有配置的用途,并合并、测试,而不是覆盖它们。后文 helper 面向本机原先没有自定义 pin 配置的情况。
3. 先确认当前 WirePlumber 版本
本文方案使用 WirePlumber 0.5 的配置格式:
wireplumber --version
如果是 WirePlumber 0.4,需要使用旧式 Lua 配置,不能混用本文的 .conf 配置。WirePlumber 0.5 的用户配置目录是:
~/.config/wireplumber/wireplumber.conf.d/
系统级配置目录是:
/etc/wireplumber/wireplumber.conf.d/
如果登录管理器或登录界面也会创建音频会话,建议使用系统级配置。
全文涉及的重启音频服务、重新解析 codec 都可能短暂中断声音,请先暂停会议、录音或重要播放。
4. 绕过错误的 ACP-PDM 路径
创建系统级 WirePlumber 配置:
sudo install -d -m 0755 /etc/wireplumber/wireplumber.conf.d
sudoedit /etc/wireplumber/wireplumber.conf.d/51-xingyao-audio.conf
填入以下内容。先用 pactl list cards short 确认设备名。本文机器是 alsa_card.pci-0000_c2_00.6,参考文章中的机器是不同 PCI 地址,device.name 和 node.name 均需要按本机输出替换。不要在用户级和系统级重复放相同规则;已有的同名文件应先备份、比较再修改。
# XINGYAO P916F-STX / ALC256 / subsystem 1d05:e004
monitor.alsa.rules = [
{
matches = [
{ device.name = "alsa_card.pci-0000_c2_00.6" }
]
actions = {
update-props = {
# 绕过坏掉的 ACP-PDM/UCM 路径,直接枚举 HDA PCM。
api.alsa.use-acp = false
# 让 PipeWire 音量控制使用软件音量,硬件增益由 amixer 固定到 0 dB。
api.alsa.soft-mixer = true
}
}
}
{
matches = [
{ node.name = "alsa_output.pci-0000_c2_00.6.playback.0.0" }
]
actions = {
update-props = {
# 原始 HDA 节点在本机内核上错误地报告了多声道能力。
# 强制使用正常的前左/前右双声道。
audio.channels = 2
audio.position = [ FL FR ]
}
}
}
]
重启 WirePlumber:
systemctl --user restart wireplumber.service
检查是否已经切换到原始 HDA 节点:
pactl list short sinks
pactl list short sources
pactl list cards
本文机器切换后的节点名为:
alsa_output.pci-0000_c2_00.6.playback.0.0
alsa_input.pci-0000_c2_00.6.capture.0.0
节点编号可能不同,不能写死 403、404 等数字。
设置默认输入和输出:
pactl set-default-sink alsa_output.pci-0000_c2_00.6.playback.0.0
pactl set-default-source alsa_input.pci-0000_c2_00.6.capture.0.0
5. 临时恢复音量和麦克风增益
本文机器使用 ALSA 名称 Generic_1,也可以使用声卡数字编号,但数字编号可能因重启和插拔改变,因此更推荐使用稳定名称:
amixer -c Generic_1 sset Master 100% unmute
amixer -c Generic_1 sset Speaker 100% unmute
amixer -c Generic_1 sset Headphone 100% mute
amixer -c Generic_1 sset 'Auto-Mute Mode' Disabled
本文机器最终使用的麦克风增益是:
amixer -c Generic_1 sset Capture 15dB cap
amixer -c Generic_1 sset 'Internal Mic Boost' 20dB
如果录音出现削波、爆音或底噪过大,应逐步降低这两个增益。不要盲目使用最大值。
PipeWire 的桌面音量仍然可以单独调节,例如:
wpctl set-volume @DEFAULT_SINK@ 0.65
wpctl set-mute @DEFAULT_SINK@ 0
6. 验证 0x1B 第二组扬声器
先确认 HDA 设备路径。本文机器是 /dev/snd/hwC1D0,但 C1D0 不保证在其他机器上相同:
ls -l /dev/snd/hwC*D*
再次确认硬件身份:
grep -E '^(Vendor Id:|Subsystem Id:)' /proc/asound/card1/codec#0
仅当输出确实为本文目标硬件时,才执行:
sudo hda-verb /dev/snd/hwC1D0 0x1b SET_PIN_WIDGET_CONTROL 0x40
sudo hda-verb /dev/snd/hwC1D0 0x1b SET_AMP_GAIN_MUTE 0xb000
两个命令分别完成:
0x1B -> 输出模式
0x1B -> 解除输出放大器静音
检查状态:
sed -n '/^Node 0x1b /,/^Node 0x1c /p' \
/proc/asound/card1/codec#0
目标状态包括:
Amp-Out vals: [0x00 0x00]
Pin-ctls: 0x40: OUT
EAPD 0x2: EAPD
Connection:
0x02* 0x03
为什么一次性 hda-verb 可能不够
在本文机器上,单独执行 hda-verb 后,再次播放时观察到 0x1B 回到了输入。推测与 codec/驱动重新初始化有关,但没有追踪到具体的内核写入调用,不能把复位时机或内核调用链视为已证实的结论。本机随后通过 user_pin_configs 让驱动将其作为扬声器管理:
sudo sh -c 'printf "0x1b 0x90170120\n" > /sys/class/sound/hwC1D0/user_pin_configs'
sudo sh -c 'echo 1 > /sys/class/sound/hwC1D0/reconfig'
0x90170120 把 0x1B 声明为内部模拟扬声器输出。命令是示意顺序,不建议在正在使用的桌面中直接照抄。执行 reconfig 前必须确保没有 PipeWire、WirePlumber 或其他程序正在占用该声卡;否则会得到:
Device or resource busy
在已经登录的桌面中,不建议为了测试强行停止所有音频服务。可以通过下面的 systemd 服务在开机、音频设备尚未被桌面打开时完成配置。
7. 开机和唤醒持久化
仅使用 alsactl store 不足以修复 0x1B,因为它不能持久化 pin 的 HDA 配置。本文使用:
user_pin_configs固定0x1B为输出;hda-verb在 codec 初始化后再次确认输出和解除静音;amixer恢复 Master、Speaker、Bass Speaker 和麦克风增益;- systemd-sleep 钩子在休眠唤醒后重新执行。
7.1 修复 helper
创建 /usr/local/libexec/xingyao-e004-speaker-fix:
sudo install -d -m 0755 /usr/local/libexec
sudoedit /usr/local/libexec/xingyao-e004-speaker-fix
内容如下。这个版本会按 codec Vendor ID 和 subsystem ID 自动查找设备,不依赖固定的 card 1:
#!/bin/bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin LC_ALL=C
mode=${1:-boot}
[[ $mode == boot || $mode == resume ]] || exit 2
codec=
for f in /proc/asound/card*/codec#0; do
if grep -qx 'Vendor Id: 0x10ec0256' "$f" && \
grep -qx 'Subsystem Id: 0x1d05e004' "$f"; then
codec=$f
break
fi
done
# 不是目标硬件时安静退出,避免影响其他电脑或其他声卡。
[[ -n $codec ]] || exit 0
card=${codec#/proc/asound/card}
card=${card%/codec#0}
id=$(cat "/proc/asound/card${card}/id")
hw=/sys/class/sound/hwC${card}D0
[[ -d $hw ]] || exit 1
headphones=off
if [[ $mode == resume ]]; then
headphones=$(amixer -c "$id" cget name='Headphone Playback Switch' \
| sed -n 's/^ : values=//p')
fi
if [[ $mode == boot ]]; then
desired='0x1b 0x90170120'
current=$(cat "$hw/user_pin_configs" 2>/dev/null || true)
# 冷启动时写入用户 pin 配置并重新解析 codec。
# 已经配置过且当前桌面占用设备时,不重复 reconfig。
if [[ $current != "$desired" ]] || \
! amixer -c "$id" scontrols | grep -q "'Bass Speaker'"; then
printf '%s\n' "$desired" > "$hw/user_pin_configs"
echo 1 > "$hw/reconfig"
fi
fi
# 重新确认第二组扬声器为输出并解除静音。
hda-verb "/dev/snd/hwC${card}D0" 0x1b \
SET_PIN_WIDGET_CONTROL 0x40 >/dev/null
hda-verb "/dev/snd/hwC${card}D0" 0x1b \
SET_AMP_GAIN_MUTE 0xb000 >/dev/null
if [[ $mode == boot ]]; then
amixer -c "$id" sset Master 100% unmute
amixer -c "$id" sset Speaker 100% unmute
amixer -c "$id" sset 'Bass Speaker' unmute
amixer -c "$id" sset Headphone 100% mute
amixer -c "$id" sset Capture 15dB cap
amixer -c "$id" sset 'Internal Mic Boost' 20dB
amixer -c "$id" sset 'Auto-Mute Mode' Disabled
elif [[ $headphones == on,on ]]; then
# 唤醒时保持耳机模式,不让内置扬声器漏音。
amixer -c "$id" sset Master 100% unmute
amixer -c "$id" sset Headphone 100% unmute
amixer -c "$id" sset Speaker mute
amixer -c "$id" sset 'Bass Speaker' mute
else
amixer -c "$id" sset Master 100% unmute
amixer -c "$id" sset Headphone 100% mute
amixer -c "$id" sset Speaker 100% unmute
amixer -c "$id" sset 'Bass Speaker' unmute
fi
设置权限:
sudo chmod 0755 /usr/local/libexec/xingyao-e004-speaker-fix
7.2 systemd 服务
创建 /etc/systemd/system/xingyao-e004-speaker-fix.service:
[Unit]
Description=Restore XINGYAO ALC256 microphone and speaker routing
After=alsa-restore.service sound.target
Before=display-manager.service
Wants=alsa-restore.service
ConditionPathExists=/proc/asound
[Service]
Type=oneshot
ExecStart=/usr/local/libexec/xingyao-e004-speaker-fix boot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
7.3 休眠恢复钩子
创建 /etc/systemd/system-sleep/xingyao-e004-speaker-fix:
#!/bin/bash
case "$1/$2" in
post/*)
/usr/local/libexec/xingyao-e004-speaker-fix resume || true
;;
esac
设置权限并启用:
sudo chmod 0755 /etc/systemd/system-sleep/xingyao-e004-speaker-fix
sudo systemctl daemon-reload
sudo systemctl enable xingyao-e004-speaker-fix.service
首次安装建议保存工作后自行重启,再检查日志。 如果尚未完成本次会话的 codec 重新解析,不要直接 start 服务;桌面占用声卡时会报 Device or resource busy。本次修复是在停止所有占用者、完成临时重新解析后,才成功手动启动服务的。
服务安排在 ALSA 状态恢复之后、显示管理器之前。若发行版启动音频会话的顺序不同,仍可能发生设备占用竞争,需要结合日志调整,不能保证该排序适用于所有 Linux 发行版。没有匹配到目标硬件时 helper 会直接退出,因此服务“成功”不等于扬声器已通过实机验证。
检查:
systemctl status xingyao-e004-speaker-fix.service
journalctl -b -u xingyao-e004-speaker-fix.service
8. 3.5mm 耳机切换脚本
本文原本通过脚本直接切换 codec 的扬声器/耳机开关,而不是切换 PipeWire profile。这样可以让播放器保持同一个 sink,避免 Chromium、Edge 等应用因为 sink 被销毁重建而卡住。
脚本路径示例:
~/.local/bin/toggle-audio.sh
完整脚本:
#!/usr/bin/env bash
# 在内置扬声器和 3.5mm 耳机之间切换。
# 不切换 PipeWire profile,避免销毁播放节点。
set -u
CARD=Generic_1
# 固定硬件增益,日常听感音量由 PipeWire 控制。
amixer -c "$CARD" sset Master 100% unmute >/dev/null 2>&1
amixer -c "$CARD" cset name='Speaker Playback Volume' 87 >/dev/null 2>&1
amixer -c "$CARD" cset name='Headphone Playback Volume' 87 >/dev/null 2>&1
hp_state=$(amixer -c "$CARD" cget name='Headphone Playback Switch' 2>/dev/null \
| awk -F'values=' '/: values=/{print $2}')
if [ "$hp_state" = "on,on" ]; then
# 耳机 -> 内置扬声器
amixer -c "$CARD" cset name='Headphone Playback Switch' off,off >/dev/null 2>&1
amixer -c "$CARD" cset name='Bass Speaker Playback Switch' on,on >/dev/null 2>&1
amixer -c "$CARD" cset name='Speaker Playback Switch' on,on >/dev/null 2>&1
notify-send -a "音频切换" "已切换到扬声器" \
-i audio-speakers 2>/dev/null
else
# 内置扬声器 -> 耳机
amixer -c "$CARD" cset name='Bass Speaker Playback Switch' off,off >/dev/null 2>&1
amixer -c "$CARD" cset name='Speaker Playback Switch' off,off >/dev/null 2>&1
amixer -c "$CARD" cset name='Headphone Playback Switch' on,on >/dev/null 2>&1
notify-send -a "音频切换" "已切换到耳机" \
-i audio-headphones 2>/dev/null
fi
设置权限:
mkdir -p ~/.local/bin
chmod +x ~/.local/bin/toggle-audio.sh
~/.local/bin/toggle-audio.sh
可以将 ~/.local/bin/toggle-audio.sh 绑定到 KDE 的自定义快捷键。
9. 验证
9.1 查看默认设备和声道
pactl get-default-sink
pactl get-default-source
pactl list sinks | grep -E 'Name:|Sample Specification:|Channel Map:|Mute:|Volume:'
目标输出应包括:
Sample Specification: s32le 2ch 48000Hz
Channel Map: front-left,front-right
9.2 测试左右扬声器
aplay -D pipewire /usr/share/sounds/alsa/Front_Left.wav
aplay -D pipewire /usr/share/sounds/alsa/Front_Right.wav
9.3 测试麦克风
arecord -D pipewire -f S16_LE -r 48000 -c 2 -d 8 /tmp/mic-test.wav
aplay -D pipewire /tmp/mic-test.wav
如果录音有电平但没有人声,应检查默认 source 是否为 HDA 路径,而不是 acppdmmach:
pactl get-default-source
pactl list sources | grep -E 'Name:|Description:|api.alsa.path|Volume:|Mute:'
9.4 检查两个内置扬声器节点
sed -n '/^Node 0x14 /,/^Node 0x15 /p' /proc/asound/card1/codec#0
sed -n '/^Node 0x1b /,/^Node 0x1c /p' /proc/asound/card1/codec#0
0x14 和 0x1B 都应为:
Pin-ctls: 0x40: OUT
Amp-Out vals: [0x00 0x00]
EAPD 0x2: EAPD
10. 回滚
回滚会恢复到原来的 HiFi/UCM 配置,麦克风和扬声器问题可能重新出现。
停止并删除持久化服务:
sudo systemctl disable --now xingyao-e004-speaker-fix.service
sudo rm -f /etc/systemd/system/xingyao-e004-speaker-fix.service
sudo rm -f /etc/systemd/system-sleep/xingyao-e004-speaker-fix
sudo rm -f /usr/local/libexec/xingyao-e004-speaker-fix
sudo rm -f /etc/wireplumber/wireplumber.conf.d/51-xingyao-audio.conf
sudo systemctl daemon-reload
恢复 WirePlumber:
systemctl --user restart wireplumber.service
清除失效的默认设备:
wpctl clear-default
然后从桌面音频设置中重新选择需要的输入和输出。
如果之前设置过 user_pin_configs,该配置只在当前内核运行期间有效,重启后不会写入 BIOS 或固件。要立即恢复固件默认 pin,可以重启电脑;不要把本文的 0x1B 修复配置复制到不同 subsystem ID 的设备上。
11. 常见问题和注意事项
修改后重启 WirePlumber 没有效果
检查配置文件是否放在正确目录:
ls -l /etc/wireplumber/wireplumber.conf.d/
wireplumber --version
journalctl --user -u wireplumber.service -n 50 --no-pager
WirePlumber 0.5 不读取旧版 main.lua.d 配置。
hda-verb 报 Permission denied
访问 HDA hwdep 设备通常需要 root 权限:
sudo hda-verb /dev/snd/hwC1D0 0x1b SET_PIN_WIDGET_CONTROL 0x40
不要为了方便而给所有用户放宽 /dev/snd/hw* 权限,也不要随意增加 sudoers 或 polkit 规则。
reconfig 报 Device or resource busy
说明 PipeWire、WirePlumber 或其他程序仍在使用声卡。可以:
- 在冷启动服务中完成
reconfig; - 暂时停止占用声卡的音频服务后再执行;
- 不要在正在播放视频时强行重新解析 codec。
耳机插拔仍不自动切换
本文方案重点是绕过错误的 UCM/ACP 路径并保留稳定播放节点。禁用 ACP 后,系统可能失去原本的自动端口策略,所以使用手动切换脚本更可靠。不同机型需要额外确认耳机检测节点和 mixer 控件。
声音仍然小或偏薄
按顺序检查:
amixer -c Generic_1 sget Master
amixer -c Generic_1 sget Speaker
amixer -c Generic_1 sget 'Bass Speaker'
sed -n '/^Node 0x1b /,/^Node 0x1c /p' /proc/asound/card1/codec#0
Master 和 Speaker 应为 100% / 0.00dB / on,Bass Speaker 应为 on,0x1B 应为 OUT 且 Amp-Out vals 为 0x00。
12. 结论
这台机器的最终方案不是简单地把声卡切到 Pro Audio,而是组合使用:
api.alsa.use-acp = false
↓
绕过错误的 ACP-PDM/UCM 麦克风路径
user_pin_configs: 0x1b 0x90170120
↓
把第二组内置扬声器固定为输出
hda-verb + amixer
↓
解除 0x1B 静音、恢复硬件增益和麦克风增益
PipeWire 双声道规则
↓
避免原始 HDA 节点错误使用多声道映射
独立切换脚本
↓
在内置扬声器和 3.5mm 耳机之间切换,同时保持播放节点不变
该方案适用于本文验证过的 ALC256 + subsystem 1d05:e004 硬件。其他机型应先确认 codec 拓扑、mixer 控件、麦克风路径和 HDA pin 定义,再逐项调整,不能把 0x1B 命令当作通用 Realtek 修复方法。
