docs(kaisa): make UCM HiFi the only supported path

Promote UCM2/HiFi (Jack-driven) as the primary delivery, add HISTORY.md,
remove ProAudio/REPRO docs and non-UCM scripts, and fix repo-wide references.

Made-with: Cursor
This commit is contained in:
2026-04-08 15:22:45 +08:00
parent 17f0a4521f
commit bda6b60c15
33 changed files with 384 additions and 1780 deletions

View File

@@ -1,240 +0,0 @@
#!/usr/bin/env bash
# 一键应用 Kaisa pro-audio 基线(见 docs/linux-hdmi/OPERATION_PipeWire_Kaisa_ProAudio.md
# deb 不作为当前交付(见 ProAudio §4.4 存档);默认仍会 purge 已装的 kaisa-hdmi-pipewire-fix避免历史安装与脚本路线冲突。
# 默认purge kaisa-hdmi-pipewire-fix、reinstall alsa-ucm-conf、禁用 60-kaisa-ucm.lua、
# 禁用系统级 50-kaisa*.conf、安装用户 50-kaisa、重启 PipeWire 栈、pactl + IEC958、跑 verify-kaisa-pro-audio.sh。
#
# 用法(仓库根,登录用户图形/会话):
# ./scripts/apply-kaisa-pro-audio.sh
# ./scripts/apply-kaisa-pro-audio.sh --keep-deb
# ./scripts/apply-kaisa-pro-audio.sh --verify-only
# ./scripts/apply-kaisa-pro-audio.sh --restore-only /path/to/baseline-stash/...
# ./scripts/apply-kaisa-pro-audio.sh --restore /path/to/baseline-stash/...
# ./scripts/apply-kaisa-pro-audio.sh --restore-stash-substring 20260406
# ./scripts/apply-kaisa-pro-audio.sh --no-verify
#
# 若只想卸载历史 debpurge + reinstall alsa-ucm-conf、不跑整套 apply
# ./scripts/remove-kaisa-hdmi-deb.sh
#
# 需要sudo、systemctl --user、pactl、amixer建议 pulseaudio-utils。
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
VERIFY_SH="${REPO_ROOT}/scripts/verify-kaisa-pro-audio.sh"
RESTORE_SH="${REPO_ROOT}/scripts/restore-ubuntu-audio-baseline.sh"
CONF_SRC="${REPO_ROOT}/docs/linux-hdmi/wireplumber/50-kaisa-sof-rt5682-hdmi.conf"
KEEP_DEB=0
VERIFY_ONLY=0
NO_VERIFY=0
RESTORE_DIR=""
RESTORE_ONLY=0
RESTORE_SUBSTR=""
resolve_stash_substring() {
local sub="$1"
local base="${REPO_ROOT}/audio_topology/baseline-stash"
if [[ ! -d "$base" ]]; then
echo "apply-kaisa-pro-audio: 无目录 $base(请先 capture-ubuntu-audio-baseline.sh" >&2
exit 1
fi
local matches=()
shopt -s nullglob
for d in "$base"/*"${sub}"*/; do
[[ -d "$d" ]] || continue
matches+=("$d")
done
shopt -u nullglob
if ((${#matches[@]} == 0)); then
echo "apply-kaisa-pro-audio: 未找到基线目录名含「${sub}」于 $base" >&2
echo "现有目录:" >&2
ls -la "$base" 2>/dev/null | head -20 >&2 || true
exit 1
fi
local latest
latest="$(ls -td "${matches[@]}" | head -1)"
realpath "$latest"
}
usage() {
sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'
exit "${1:-0}"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--keep-deb) KEEP_DEB=1 ;;
--verify-only) VERIFY_ONLY=1 ;;
--no-verify) NO_VERIFY=1 ;;
--restore-only)
RESTORE_ONLY=1
if [[ -n "${2:-}" && "${2:0:1}" != - ]]; then
RESTORE_DIR="$2"
shift
fi
;;
--restore)
RESTORE_DIR="${2:?--restore 需要目录参数}"
shift
;;
--restore-stash-substring)
RESTORE_SUBSTR="${2:?--restore-stash-substring 需要子串,如 20260406}"
shift
;;
-h|--help) usage 0 ;;
*)
echo "未知参数: $1" >&2
usage 1
;;
esac
shift
done
if [[ "$VERIFY_ONLY" -eq 1 ]]; then
exec "$VERIFY_SH"
fi
if [[ -n "$RESTORE_SUBSTR" ]]; then
RESTORE_DIR="$(resolve_stash_substring "$RESTORE_SUBSTR")"
echo ">>> 解析基线目录: $RESTORE_DIR"
fi
if [[ "$RESTORE_ONLY" -eq 1 && -z "$RESTORE_DIR" ]]; then
echo "apply-kaisa-pro-audio: --restore-only 需要目录参数,或与 --restore-stash-substring 同用。" >&2
exit 1
fi
if [[ $EUID -eq 0 && -z "${SUDO_USER:-}" ]]; then
echo "apply-kaisa-pro-audio: 请勿以 root 直接运行(无法正确操作 user pipewire。请用登录用户执行。" >&2
exit 1
fi
if [[ ! -f "$CONF_SRC" ]]; then
echo "apply-kaisa-pro-audio: 缺少仓库 conf: $CONF_SRC" >&2
exit 1
fi
if ! command -v sudo &>/dev/null; then
echo "apply-kaisa-pro-audio: 需要 sudo。" >&2
exit 1
fi
# pactl 前缀root+sudo 时代理会话用户
PACTL_PREFIX=()
if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" ]] && id -u "$SUDO_USER" &>/dev/null; then
_VU="$(id -u "$SUDO_USER")"
if [[ -d "/run/user/${_VU}" ]]; then
_VH="$(getent passwd "$SUDO_USER" | cut -d: -f6)"
_VH="${_VH:-/home/$SUDO_USER}"
PACTL_PREFIX=(sudo -u "$SUDO_USER" env XDG_RUNTIME_DIR="/run/user/${_VU}" HOME="$_VH")
fi
fi
run_pactl() { "${PACTL_PREFIX[@]}" pactl "$@"; }
restart_audio_stack() {
if ((${#PACTL_PREFIX[@]})); then
sudo -u "${SUDO_USER}" env XDG_RUNTIME_DIR="/run/user/$(id -u "$SUDO_USER")" \
systemctl --user restart wireplumber pipewire pipewire-pulse
else
systemctl --user restart wireplumber pipewire pipewire-pulse
fi
}
if [[ -n "$RESTORE_DIR" ]]; then
echo ">>> 执行基线恢复: $RESTORE_SH $RESTORE_DIR"
"$RESTORE_SH" "$RESTORE_DIR"
if [[ "$RESTORE_ONLY" -eq 1 ]]; then
echo ">>> --restore-only已恢复跳过 pro-audio 应用。"
exit 0
fi
fi
if [[ "$KEEP_DEB" -eq 0 ]]; then
if dpkg -s kaisa-hdmi-pipewire-fix &>/dev/null; then
echo ">>> apt purge -y kaisa-hdmi-pipewire-fix"
sudo apt purge -y kaisa-hdmi-pipewire-fix
else
echo "(未安装 kaisa-hdmi-pipewire-fix跳过 purge)"
fi
echo ">>> apt install --reinstall -y alsa-ucm-conf"
sudo apt install --reinstall -y alsa-ucm-conf
else
echo "(--keep-deb跳过 purge / reinstall alsa-ucm-conf)"
fi
LUA="/usr/share/wireplumber/main.lua.d/60-kaisa-ucm.lua"
if [[ -f "$LUA" ]]; then
echo ">>> sudo mv $LUA -> ${LUA}.disabled"
sudo mv -n -- "$LUA" "${LUA}.disabled"
else
echo "(无激活的 $LUA,跳过)"
fi
if [[ -d /etc/wireplumber/wireplumber.conf.d ]]; then
echo ">>> 禁用系统级 50-kaisa*.conf避免与用户级重复"
sudo bash -c '
shopt -s nullglob
for f in /etc/wireplumber/wireplumber.conf.d/50-kaisa*.conf; do
[[ -f "$f" ]] || continue
t="${f}.disabled"
[[ -e "$t" ]] && t="${f}.disabled.$(date +%s)"
echo "mv $f -> $t"
mv -n -- "$f" "$t"
done
'
fi
USER_CONF_DIR="${HOME}/.config/wireplumber/wireplumber.conf.d"
mkdir -p "$USER_CONF_DIR"
echo ">>> cp $CONF_SRC -> $USER_CONF_DIR/50-kaisa-sof-rt5682-hdmi.conf"
cp -f -- "$CONF_SRC" "$USER_CONF_DIR/50-kaisa-sof-rt5682-hdmi.conf"
echo ">>> strip-kaisa-default-profile-state避免 WirePlumber 从 default-profile 恢复 stereo-fallback"
"$REPO_ROOT/scripts/strip-kaisa-default-profile-state.sh" || true
if systemctl --user is-system-running &>/dev/null; then
echo ">>> systemctl --user restart wireplumber pipewire pipewire-pulse"
restart_audio_stack
sleep 2
else
echo "apply-kaisa-pro-audio: 警告user systemd 会话不可用,请登录桌面后手动: systemctl --user restart wireplumber pipewire pipewire-pulse" >&2
fi
if ! command -v pactl &>/dev/null; then
echo "apply-kaisa-pro-audio: 未找到 pactl无法 set-card-profile。请安装 pulseaudio-utils 后重试。" >&2
exit 1
fi
CARD="$(run_pactl list cards short 2>/dev/null | awk '/cml_rt5682/ {print $2; exit}')" || true
if [[ -z "$CARD" ]]; then
echo "apply-kaisa-pro-audio: 无法从 pactl list cards short 解析 cml_rt5682 卡名PCI 是否与 conf 中 pci-0000_00_1f.3 一致?)" >&2
exit 1
fi
echo ">>> pactl set-card-profile $CARD pro-audio"
run_pactl set-card-profile "$CARD" pro-audio
SINK="$(run_pactl list short sinks 2>/dev/null | awk '/cml_rt5682/ && /\.pro-output-2/ {print $2; exit}')" || true
if [[ -z "$SINK" ]]; then
echo "apply-kaisa-pro-audio: 未找到 …pro-output-2 sink请核对 profile 是否已为 pro-audio。" >&2
exit 1
fi
echo ">>> pactl set-default-sink $SINK"
run_pactl set-default-sink "$SINK"
echo ">>> amixer IEC958 0/1/2 on"
amixer -c0 sset 'IEC958',0 on
amixer -c0 sset 'IEC958',1 on
amixer -c0 sset 'IEC958',2 on
if [[ "$NO_VERIFY" -eq 1 ]]; then
echo ">>> --no-verify跳过门禁不推荐。"
exit 0
fi
echo ">>> $VERIFY_SH"
if ! "$VERIFY_SH"; then
echo "" >&2
echo "apply-kaisa-pro-audio: 门禁未通过。可查看上文,或运行: $REPO_ROOT/scripts/verify-kaisa-audio-environment.sh --output /tmp/kaisa-verify.txt" >&2
exit 1
fi
echo "apply-kaisa-pro-audio: 完成。"

View File

@@ -1,128 +0,0 @@
#!/usr/bin/env bash
# 在安装 kaisa-hdmi-pipewire-fix 或其它大改前采集「Ubuntu / 当前机」音频基线并落盘。
# 输出目录默认audio_topology/baseline-stash/<时间戳>_<hostname>/
# 用法:./scripts/capture-ubuntu-audio-baseline.sh [输出目录]
# 详见docs/linux-hdmi/OPERATION_PipeWire_Kaisa_ProAudio.md「基线备份与恢复」
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
STAMP="$(date +%Y%m%d_%H%M%S)_$(hostname)"
if [[ -n "${1:-}" ]]; then
STASH="$(realpath "$1")"
else
STASH="${REPO_ROOT}/audio_topology/baseline-stash/${STAMP}"
fi
mkdir -p "$STASH/backup/root"
write_manifest() {
local mf="$STASH/manifest.txt"
{
echo "# capture-ubuntu-audio-baseline"
echo "created_iso: $(date -Iseconds)"
echo "hostname: $(hostname)"
echo "stash_dir: $STASH"
echo ""
echo "## uname"
uname -a
echo ""
echo "## dpkg (相关包)"
dpkg -l 2>/dev/null | grep -E '^(ii|rc)\s+(alsa-ucm-conf|wireplumber|pipewire|pipewire-pulse|kaisa-hdmi-pipewire-fix)\s' || true
echo ""
if dpkg -s kaisa-hdmi-pipewire-fix &>/dev/null; then
echo "## kaisa-hdmi-pipewire-fix: installed"
dpkg -s kaisa-hdmi-pipewire-fix 2>/dev/null | grep -E '^(Package|Version|Status):' || true
else
echo "## kaisa-hdmi-pipewire-fix: not installed"
fi
echo ""
echo "## deb 相关路径(存在性与 sha256"
} >"$mf"
local paths=(
/etc/wireplumber/wireplumber.conf.d/50-kaisa-sof-rt5682-hdmi.conf
/usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf
/usr/share/alsa/ucm2/GoogleKaisa/sof-rt5682/HiFi.conf
)
local p
for p in "${paths[@]}"; do
if [[ -e "$p" ]]; then
echo "PATH $p exists=yes" >>"$mf"
if [[ -f "$p" ]]; then
sha256sum "$p" >>"$mf" 2>/dev/null || echo "(sha256sum failed)" >>"$mf"
fi
else
echo "PATH $p exists=no" >>"$mf"
fi
done
echo "" >>"$mf"
echo "## /usr/share/doc/kaisa-hdmi-pipewire-fix/" >>"$mf"
if [[ -d /usr/share/doc/kaisa-hdmi-pipewire-fix ]]; then
ls -la /usr/share/doc/kaisa-hdmi-pipewire-fix >>"$mf" 2>&1 || true
else
echo "(目录不存在)" >>"$mf"
fi
}
backup_vendor_ucm() {
local src="/usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf"
if [[ -f "$src" ]]; then
install -D -m0644 "$src" "$STASH/backup/root/usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf"
echo "已备份 vendor UCM: $src -> backup/root/..."
fi
}
backup_user_wireplumber() {
local d="${HOME}/.config/wireplumber/wireplumber.conf.d"
local names=()
if [[ -d "$d" ]]; then
shopt -s nullglob
local f
for f in "$d"/*; do
[[ -e "$f" ]] || continue
local b
b="$(basename "$f")"
if [[ "$b" == *kaisa* ]] || [[ "$b" == 50-kaisa* ]]; then
names+=("$b")
fi
done
fi
if ((${#names[@]} > 0)); then
tar -C "$d" -czf "$STASH/user-wireplumber-conf.tar.gz" "${names[@]}"
echo "已打包用户 WirePlumber 片段: ${names[*]} -> user-wireplumber-conf.tar.gz"
else
echo "(未找到 ~/.config/wireplumber/... 下含 kaisa 的片段,跳过 user-wireplumber-conf.tar.gz)"
fi
}
pack_system_overlay() {
if [[ -f "$STASH/backup/root/usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf" ]]; then
tar -C "$STASH/backup/root" -czf "$STASH/system-overlay.tar.gz" \
usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf
echo "已生成 system-overlay.tar.gz可配合 restore 还原安装 deb 前的 vendor sof-rt5682.conf"
else
echo "(未备份 vendor sof-rt5682.conf不生成 system-overlay.tar.gz)"
fi
}
write_manifest
backup_vendor_ucm
backup_user_wireplumber
pack_system_overlay
TOPO="$STASH/topology.txt"
echo "正在调用 collect_linux_audio_topology.sh -> $TOPO"
bash "${REPO_ROOT}/audio_topology/collect_linux_audio_topology.sh" "$TOPO"
echo ""
echo "========== 基线已写入: $STASH =========="
echo " manifest.txt — 包状态与 deb 路径清单"
echo " topology.txt — 完整音频拓扑"
echo " system-overlay.tar.gz — 若存在vendor sof-rt5682.conf 快照"
echo " user-wireplumber-conf.tar.gz — 若存在:用户 kaisa WirePlumber 片段"
echo ""
echo "恢复至「尽量接近本次采集时」的系统文件状态:"
echo " ./scripts/restore-ubuntu-audio-baseline.sh $STASH"
echo ""
echo "若曾启用 §4.3 user systemd 自动 restore恢复基线前可先禁用该 user 单元(见 OPERATION。"

View File

@@ -1,51 +0,0 @@
#!/usr/bin/env bash
# 在用户会话里把 cml_rt5682 拉回 pro-audio + 默认 pro-output-2 + IEC958。
# 用于:开机/登录后 profile 变回 stereo-fallback导致 pro-output-*「出现又消失」。
# 根因常为 ~/.local/state/wireplumber/default-profile 里持久了 stereo-fallback见 strip-kaisa-default-profile-state.sh
# 可重复执行;建议由 systemd --user oneshot 在 pipewire-pulse 之后延迟调用(见 systemd-user/kaisa-pro-audio-reapply.service
set -euo pipefail
# 与 strip-kaisa-default-profile-state.sh 同逻辑(本脚本常被单独 symlink 到 ~/.local/bin勿依赖同目录 strip
_wp_state="${HOME}/.local/state/wireplumber/default-profile"
if [[ -f "$_wp_state" ]] && grep -q 'cml_rt5682' "$_wp_state" 2>/dev/null; then
_tmp="${_wp_state}.tmp.$$"
grep -v 'cml_rt5682' "$_wp_state" > "$_tmp"
mv -f -- "$_tmp" "$_wp_state"
echo "kaisa-reapply-pro-audio-session: 已清除 default-profile 中含 cml_rt5682 的持久行" >&2
fi
if ! command -v pactl &>/dev/null; then
echo "kaisa-reapply-pro-audio-session: 未找到 pactl" >&2
exit 1
fi
apply_once() {
local card sink
card="$(pactl list cards short 2>/dev/null | awk '/cml_rt5682/ {print $2; exit}')" || true
[[ -z "$card" ]] && return 1
pactl set-card-profile "$card" pro-audio 2>/dev/null || true
# 给 WirePlumber 一点时间生成 sink
sleep 0.4
sink="$(pactl list short sinks 2>/dev/null | awk '/cml_rt5682/ && /\.pro-output-2/ {print $2; exit}')" || true
[[ -n "$sink" ]] && pactl set-default-sink "$sink" 2>/dev/null || true
if command -v amixer &>/dev/null; then
amixer -c0 sset 'IEC958',0 on 2>/dev/null || true
amixer -c0 sset 'IEC958',1 on 2>/dev/null || true
amixer -c0 sset 'IEC958',2 on 2>/dev/null || true
fi
return 0
}
# 首次:栈可能尚未完全就绪
for _ in 1 2 3 4 5 6 7 8 9 10; do
if apply_once; then
# 再等一会GNOME 常在登录后数秒内改 profile第二次拉回去
sleep 6
apply_once || true
exit 0
fi
sleep 1
done
echo "kaisa-reapply-pro-audio-session: 超时未找到 cml_rt5682 卡pactl list cards short" >&2
exit 1

View File

@@ -1,52 +0,0 @@
#!/usr/bin/env bash
# 卸载历史上可能安装过的 kaisa-hdmi-pipewire-fixapt purge并 reinstall alsa-ucm-conf
# 以恢复发行版自带的 UCM 文件(与 apply-kaisa-pro-audio.sh 中 KEEP_DEB=0 时前两步一致)。
#
# 不改动用户级 WirePlumber不自动重启 PipeWire。若曾用手工 UCM overlay另见
# ./scripts/remove-kaisa-ucm-overlay.sh
# 若要走 pro-audio 主路线purge 完成后可执行:
# ./scripts/apply-kaisa-pro-audio.sh --keep-deb
#
# 用法:
# ./scripts/remove-kaisa-hdmi-deb.sh
# ./scripts/remove-kaisa-hdmi-deb.sh --no-reinstall-ucm # 仅 purge不 touch alsa-ucm-conf
set -euo pipefail
NO_REINSTALL=0
while [[ $# -gt 0 ]]; do
case "$1" in
--no-reinstall-ucm) NO_REINSTALL=1 ;;
-h|--help)
sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
echo "未知参数: $1(用 --help" >&2
exit 1
;;
esac
shift
done
if ! command -v sudo &>/dev/null; then
echo "需要 sudo。" >&2
exit 1
fi
if dpkg -s kaisa-hdmi-pipewire-fix &>/dev/null; then
echo ">>> apt purge -y kaisa-hdmi-pipewire-fix"
sudo apt purge -y kaisa-hdmi-pipewire-fix
else
echo "(dpkg 无已登记包 kaisa-hdmi-pipewire-fix跳过 purge若曾改名安装请自行 apt purge 包名)"
fi
if [[ "$NO_REINSTALL" -eq 0 ]]; then
echo ">>> apt install --reinstall -y alsa-ucm-conf"
sudo apt install --reinstall -y alsa-ucm-conf
else
echo "(--no-reinstall-ucm跳过 alsa-ucm-conf reinstall)"
fi
echo "remove-kaisa-hdmi-deb: 完成。建议登录用户会话下: systemctl --user restart wireplumber pipewire pipewire-pulse"
echo "若仍有手工 UCM: ./scripts/remove-kaisa-ucm-overlay.sh"
echo "若应用 pro-audio: ./scripts/apply-kaisa-pro-audio.sh --keep-deb"

View File

@@ -2,7 +2,7 @@
# 卸载本仓库安装的 Kaisa UCM2 overlay 与系统级 60-kaisa-ucm.lua需 sudo
# 不卸载 alsa-ucm-conf 整包;仅删除 install-kaisa-ucm-overlay.sh 写入的路径。
# 用法:在仓库根目录执行 ./scripts/remove-kaisa-ucm-overlay.sh
# 卸载后若走 pro-audio请再执行 ./scripts/apply-kaisa-pro-audio.sh
# 卸载后请按发行版默认策略重新选择输出配置。
set -euo pipefail
if ! command -v sudo &>/dev/null; then
@@ -51,5 +51,5 @@ fi
echo "完成。sof-rt5682 将不再使用本仓库的 HiFi UCMHDMI1/2/3 等端口名来自该 overlay。"
if [[ "$removed" -eq 1 ]]; then
echo "建议:走 pro-audio 时在仓库根执行 ./scripts/apply-kaisa-pro-audio.sh"
echo "提示:卸载后将回到发行版默认音频配置;如需继续使用 HDMI请按 docs/linux-hdmi/OPERATION_PipeWire_Kaisa_UCM_HiFi.md 重新安装。"
fi

View File

@@ -1,80 +0,0 @@
#!/usr/bin/env bash
# 将系统尽量恢复到某次 capture-ubuntu-audio-baseline 采集时的「安装 deb 前」文件状态。
# 典型purge kaisa-hdmi-pipewire-fix → reinstall alsa-ucm-conf → 可选解压备份 tar。
# 用法:./scripts/restore-ubuntu-audio-baseline.sh [基线目录]
# 若不传参数,使用 audio_topology/baseline-stash/ 下最近修改的子目录。
# 需要sudoapt、解压到 /);建议在桌面会话下执行以便重启 PipeWire。
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
resolve_stash() {
if [[ -n "${1:-}" ]]; then
realpath "$1"
return
fi
local latest
latest="$(ls -td "${REPO_ROOT}/audio_topology/baseline-stash"/*/ 2>/dev/null | head -1 || true)"
if [[ -z "$latest" ]]; then
echo "未找到基线目录。请先运行: ${REPO_ROOT}/scripts/capture-ubuntu-audio-baseline.sh" >&2
exit 1
fi
realpath "${latest%/}"
}
STASH="$(resolve_stash "${1:-}")"
if [[ ! -f "$STASH/manifest.txt" ]]; then
echo "不是有效基线目录(缺少 manifest.txt: $STASH" >&2
exit 1
fi
echo "========== 使用基线: $STASH =========="
echo "manifest 创建于:"
head -5 "$STASH/manifest.txt"
echo ""
if ! command -v sudo &>/dev/null; then
echo "需要 sudo 以执行 apt。" >&2
exit 1
fi
if dpkg -s kaisa-hdmi-pipewire-fix &>/dev/null; then
echo ">>> apt purge kaisa-hdmi-pipewire-fix"
sudo apt purge -y kaisa-hdmi-pipewire-fix
else
echo "(未安装 kaisa-hdmi-pipewire-fix跳过 purge)"
fi
echo ">>> apt install --reinstall alsa-ucm-conf"
sudo apt install --reinstall -y alsa-ucm-conf
if [[ -f "$STASH/system-overlay.tar.gz" ]]; then
echo ">>> 解压 system-overlay.tar.gz -> /(覆盖 vendor sof-rt5682.conf与 reinstall 通常等价)"
sudo tar -xzf "$STASH/system-overlay.tar.gz" -C /
else
echo "(无 system-overlay.tar.gz仅依赖 alsa-ucm-conf reinstall)"
fi
if [[ -f "$STASH/user-wireplumber-conf.tar.gz" ]]; then
echo ">>> 解压 user-wireplumber-conf.tar.gz -> ${HOME}/.config/wireplumber/wireplumber.conf.d/"
mkdir -p "${HOME}/.config/wireplumber/wireplumber.conf.d"
tar -xzf "$STASH/user-wireplumber-conf.tar.gz" -C "${HOME}/.config/wireplumber/wireplumber.conf.d"
echo "已恢复用户 WirePlumber 片段。"
else
echo "(无 user-wireplumber-conf.tar.gz跳过用户配置)"
fi
if systemctl --user is-system-running &>/dev/null; then
echo ">>> systemctl --user restart wireplumber pipewire pipewire-pulse"
systemctl --user restart wireplumber pipewire pipewire-pulse 2>/dev/null || {
echo "user 会话重启 pipewire 失败,请手动重登或重启)" >&2
}
else
echo "(无可用 user systemd 会话,请登录图形界面后执行: systemctl --user restart wireplumber pipewire pipewire-pulse"
fi
echo ""
echo "========== 恢复步骤已完成 =========="
echo "若曾启用登录自动 restoreuser systemd恢复前可先禁用 kaisa-hdmi-iec958-pipewire 单元(见 OPERATION §4.3 / §4.5)。"
echo "建议核对: pactl list cards | head -40 ; aplay -l"

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env bash
# 从 WirePlumber 持久状态里删掉 cml_rt5682 声卡那一行。
# 原因default-profile 模块会读取 ~/.local/state/wireplumber/default-profile
# 若其中保存了 output:stereo-fallback+input:stereo-fallback会在每次启动时
# 覆盖 monitor.alsa.rules 里设的 pro-audio表现为「pro-output 出现一下又变回 stereo-fallback」。
#
# 由 apply-kaisa-pro-audio.sh重启栈之前与 kaisa-reapply-pro-audio-session.sh 调用;也可单独执行。
set -euo pipefail
STATE_DIR="${HOME}/.local/state/wireplumber"
F="${STATE_DIR}/default-profile"
[[ -f "$F" ]] || exit 0
if ! grep -q 'cml_rt5682' "$F" 2>/dev/null; then
exit 0
fi
tmp="${F}.tmp.$$"
grep -v 'cml_rt5682' "$F" > "$tmp"
mv -f -- "$tmp" "$F"
echo "strip-kaisa-default-profile-state: 已从 $F 移除含 cml_rt5682 的行(请保持 pro-audio 后由 WirePlumber 再写回正确 profile"

View File

@@ -1,287 +0,0 @@
#!/usr/bin/env bash
# KaisaGoogle-Kaisa / sof-rt5682 / cml_rt5682音频环境一次性全面验证。
# 覆盖PCI、ALSA 枚举、UCM2、已安装 overlay、PipeWire/Pulse、WirePlumber、
# IEC958/Jackamixer、HDMI ELD、近期用户态日志片段。
#
# 用法(在图形会话或 SSH 带 XDG_RUNTIME_DIR 时):
# ./scripts/verify-kaisa-audio-environment.sh
# ./scripts/verify-kaisa-audio-environment.sh --output ~/kaisa-audio-verify.txt
# sudo ./scripts/verify-kaisa-audio-environment.sh # 会经 sudo -u $SUDO_USER 调用 pactl/journalctl勿裸 root 登录)
#
# 注意PipeWire-Pulse 的 pactl 必须「以会话用户 + 其 /run/user/<uid>」连接root 进程不能直接占用普通用户的 XDG_RUNTIME_DIR。
#
# 详见docs/linux-hdmi/OPERATION_PipeWire_Kaisa_ProAudio.md
set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
export REPO_ROOT
OUT_FILE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--output|-o)
OUT_FILE="${2:?}"
shift 2
;;
-h|--help)
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
echo "未知参数: $1 (使用 --help" >&2
exit 1
;;
esac
done
# root + sudopactl / wpctl / journalctl --user 必须代会话用户执行(不能 root 直连用户 PipeWire
PACTL_PREFIX=()
JOURNAL_PREFIX=()
WCONF_HOME="${HOME}"
if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" ]] && command -v sudo &>/dev/null && id -u "$SUDO_USER" &>/dev/null; then
_VU="$(id -u "$SUDO_USER")"
if [[ -d "/run/user/${_VU}" ]]; then
_VH="$(getent passwd "$SUDO_USER" | cut -d: -f6)"
_VH="${_VH:-/home/$SUDO_USER}"
PACTL_PREFIX=(sudo -u "$SUDO_USER" env XDG_RUNTIME_DIR="/run/user/${_VU}" HOME="$_VH")
JOURNAL_PREFIX=(sudo -u "$SUDO_USER" env XDG_RUNTIME_DIR="/run/user/${_VU}")
WCONF_HOME="$_VH"
fi
fi
if [[ -n "$OUT_FILE" ]]; then
exec > >(tee -a "$OUT_FILE")
exec 2>&1
echo "# 报告文件: $OUT_FILE"
fi
hr() { printf '%s\n' "================================================================================"; }
sec() { printf '\n'; hr; echo "### $*"; hr; echo ""; }
run() {
local title="$1"
shift
echo "# $title"
echo "\`\`\`"
if "$@" 2>&1; then
:
else
echo "(命令返回非零: exit $?)"
fi
echo "\`\`\`"
echo ""
}
have() { command -v "$1" &>/dev/null; }
echo "verify-kaisa-audio-environment"
echo "时间: $(date -Iseconds)"
echo "主机: $(hostname)"
echo "用户: ${USER:-?} EUID=$EUID"
echo "XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-<unset>}"
echo "仓库: $REPO_ROOT"
if [[ $EUID -eq 0 ]]; then
if ((${#PACTL_PREFIX[@]})); then
echo "提示: 当前 rootpactl/journalctl/用户 WirePlumber 路径将经 sudo -u ${SUDO_USER}(会话 UID $(id -u "$SUDO_USER"))。"
else
echo "提示: 当前 root 且无法解析 SUDO_USER 或 /run/user/<uid>pactl 与 --user 日志可能失败(建议普通用户执行本脚本,或 sudo -u <登录用户> ./scripts/...)。"
fi
fi
echo ""
sec "1) 系统与软件包"
run "uname -a" uname -a
if have dpkg; then
run "dpkg 相关包版本" bash -c "dpkg -l 2>/dev/null | grep -E '^(ii|rc)\s+(alsa-ucm-conf|alsa-utils|libasound|wireplumber|pipewire|pipewire-pulse|pipewire-bin|pipewire-audio-client-libraries)\s' || true"
fi
for c in pipewire wireplumber pactl wpctl alsaucm aplay amixer; do
if have "$c"; then
echo "# $c: $(command -v "$c")"
else
echo "# $c: (未安装)"
fi
done
echo ""
sec "2) PCI 音频"
if have lspci; then
run "lspci -nn | grep -iE 'audio|multimedia'" bash -c "lspci -nn 2>/dev/null | grep -iE 'audio|multimedia|display' || true"
else
echo "(无 lspci)"
echo ""
fi
sec "3) ALSA 声卡与 PCM"
run "/proc/asound/cards" cat /proc/asound/cards
run "/proc/asound/pcm节选" bash -c "head -120 /proc/asound/pcm 2>/dev/null || true"
if have aplay; then
run "aplay -l" aplay -l
run "aplay -L节选 HDMI/sof/0" bash -c "aplay -L 2>/dev/null | grep -iE 'hdmi|display|sof|card 0|plughw' | head -80 || true"
else
echo "(无 aplay)"
echo ""
fi
sec "4) HDMI ELD有接线时才有内容"
shopt -s nullglob
eld_files=(/proc/asound/card*/eld*)
if ((${#eld_files[@]})); then
for f in "${eld_files[@]}"; do
echo "# $f"
echo "\`\`\`"
cat "$f" 2>/dev/null || echo "(无法读取)"
echo "\`\`\`"
echo ""
done
else
echo "(未找到 /proc/asound/card*/eld*)"
echo ""
fi
sec "5) UCM2alsaucm与系统路径"
run "vendor/overlay UCM 文件是否存在" bash -c '
for p in \
/usr/share/alsa/ucm2/conf.d/sof-rt5682/sof-rt5682.conf \
/usr/share/alsa/ucm2/GoogleKaisa/sof-rt5682/HiFi.conf \
"$REPO_ROOT/reference/ucm2/conf.d/sof-rt5682/sof-rt5682.conf" \
"$REPO_ROOT/reference/ucm2/GoogleKaisa/sof-rt5682/HiFi.conf"
do
if [[ -f "$p" ]]; then echo "OK $p"; else echo "NO $p"; fi
done
'
UCM_NAME=""
if grep -q 'sof-rt5682' /proc/asound/cards 2>/dev/null; then
UCM_NAME="sof-rt5682"
fi
if have alsaucm; then
if [[ -n "$UCM_NAME" ]]; then
run "alsaucm -c ${UCM_NAME} list _verbs" alsaucm -c "$UCM_NAME" list _verbs
else
run "alsaucm未在 /proc/asound/cards 识别 sof-rt5682尝试 sof-rt5682" alsaucm -c sof-rt5682 list _verbs
fi
else
echo "(未安装 alsaucm跳过 UCM 列表)"
echo ""
fi
sec "6) WirePlumber / 桌面侧配置"
run "系统 Lua 60-kaisa-ucm.lua" bash -c '
f=/usr/share/wireplumber/main.lua.d/60-kaisa-ucm.lua
if [[ -f "$f" ]]; then echo "OK $f"; wc -l "$f"; head -25 "$f"; else echo "NO $f"; fi
'
run "用户 ~/.config/wireplumber 中含 kaisa 的片段(主目录: ${WCONF_HOME}" bash -c '
d="'"$WCONF_HOME"'/.config/wireplumber/wireplumber.conf.d"
if [[ -d "$d" ]]; then
find "$d" -maxdepth 1 -type f \( -iname "*kaisa*" -o -iname "50-kaisa*" \) -print 2>/dev/null | while read -r p; do echo "FILE $p"; done
if ! find "$d" -maxdepth 1 -type f \( -iname "*kaisa*" -o -iname "50-kaisa*" \) -print -quit 2>/dev/null | grep -q .; then
echo "(未找到 kaisa 相关片段)"
fi
else
echo "(目录不存在: $d)"
fi
'
sec "7) PipeWire / Pulsepactl"
if have pactl; then
if ((${#PACTL_PREFIX[@]})); then
echo "#(经 ${PACTL_PREFIX[0]} ${PACTL_PREFIX[1]} … 调用 pactl连接用户 PipeWire-Pulse"
echo ""
fi
run "pactl 版本" "${PACTL_PREFIX[@]}" pactl --version
echo "# 默认 sink / source"
echo "\`\`\`"
echo -n "default-sink: "
"${PACTL_PREFIX[@]}" pactl get-default-sink 2>&1 || echo "?"
echo -n "default-source: "
"${PACTL_PREFIX[@]}" pactl get-default-source 2>&1 || echo "?"
echo "\`\`\`"
echo ""
run "pactl list short cards" "${PACTL_PREFIX[@]}" pactl list short cards
run "pactl list short sinks" "${PACTL_PREFIX[@]}" pactl list short sinks
run "pactl list short sources" "${PACTL_PREFIX[@]}" pactl list short sources
run "pactl list cards全文" "${PACTL_PREFIX[@]}" pactl list cards
else
echo "(无 pactl无法检测 PipeWire-Pulse 会话;请登录图形会话或设置 XDG_RUNTIME_DIR)"
echo ""
fi
sec "8) wpctl若可用"
if have wpctl; then
if ((${#PACTL_PREFIX[@]})); then
echo "#(经 sudo -u … 调用 wpctl与 pactl 同一会话 PipeWire"
echo ""
fi
run "wpctl status" "${PACTL_PREFIX[@]}" wpctl status
else
echo "(无 wpctl)"
echo ""
fi
sec "9) amixerIEC958 / Jack卡 0常见为 Kaisa"
if have amixer; then
run "amixer -c0节选" bash -c "amixer -c0 2>/dev/null | grep -iE 'IEC958|Jack|Simple' | head -80 || true"
else
echo "(无 amixer)"
echo ""
fi
sec "10) 内核环缓冲(需 root 时更完整)"
if [[ -r /dev/kmsg ]] || dmesg &>/dev/null; then
run "dmesg | grep -iE 'sof|snd|hda|audio|hdmi|ASoC|rt5682|iDisp' | tail -60" bash -c "dmesg 2>/dev/null | grep -iE 'sof|snd|hda|audio|hdmi|ASoC|rt5682|iDisp' | tail -60 || true"
else
echo "(dmesg 受限;可 sudo 重跑本脚本)"
echo ""
fi
sec "11) 用户态 pipewire / wireplumber 日志(本启动项)"
if have journalctl; then
if ((${#JOURNAL_PREFIX[@]})); then
echo "# journalctl --user -u pipewire -u wireplumber经 sudo -u ${SUDO_USER}| tail -40"
echo "\`\`\`"
"${JOURNAL_PREFIX[@]}" journalctl --user -u pipewire -u wireplumber -b --no-pager 2>/dev/null | tail -40 || echo "(无条目或失败)"
echo "\`\`\`"
echo ""
else
run "journalctl --user -u pipewire -u wireplumber -b --no-pager | tail -40" bash -c "journalctl --user -u pipewire -u wireplumber -b --no-pager 2>/dev/null | tail -40 || true"
fi
else
echo "(journalctl 未安装)"
echo ""
fi
sec "12) 摘要(自动推断,仅供参考)"
KAISA_IN_CARDS=0
grep -q 'sof-rt5682' /proc/asound/cards 2>/dev/null && KAISA_IN_CARDS=1
HIFI_UCM=0
if have alsaucm && [[ "$KAISA_IN_CARDS" -eq 1 ]]; then
alsaucm -c sof-rt5682 list _verbs 2>/dev/null | grep -q HiFi && HIFI_UCM=1 || true
fi
PACTL_HIFI_PROFILE=0
USE_UCM_TRUE=0
PC_TEXT=""
if have pactl; then
PC_TEXT="$("${PACTL_PREFIX[@]}" pactl list cards 2>/dev/null)" || true
if [[ -n "$PC_TEXT" ]]; then
echo "$PC_TEXT" | grep -qiE 'HiFi[[:space:]]*:' && PACTL_HIFI_PROFILE=1 || true
echo "$PC_TEXT" | grep -q 'api.alsa.use-ucm = "true"' && USE_UCM_TRUE=1 || true
fi
fi
LUA_SYS=0
[[ -f /usr/share/wireplumber/main.lua.d/60-kaisa-ucm.lua ]] && LUA_SYS=1
echo "- 内核 /proc/asound/cards 含 sof-rt5682: $([[ "$KAISA_IN_CARDS" -eq 1 ]] && echo OK || echo FAIL)"
echo "- alsaucm 列出 HiFi verb: $([[ "$HIFI_UCM" -eq 1 ]] && echo OK || echo FAIL/WARN)"
echo "- pactl 声卡段出现 HiFi profileHiFi: 行): $([[ "$PACTL_HIFI_PROFILE" -eq 1 ]] && echo OK || echo WARN可与 UCM 不一致,见 OPERATION)"
echo "- pactl api.alsa.use-ucm = true: $([[ "$USE_UCM_TRUE" -eq 1 ]] && echo OK || echo WARN)"
echo "- /usr/share/.../60-kaisa-ucm.lua 存在: $([[ "$LUA_SYS" -eq 1 ]] && echo OK || echo WARN)"
echo ""
echo "说明「alsaucm 有 HiFi」但「pactl 无 HiFi profile」时属 ACP 未注册该 profile"
echo " 不要以 pactl set-card-profile … HiFi 作为唯一验收依据。"
echo ""
hr
echo "完成。"
exit 0

View File

@@ -1,108 +0,0 @@
#!/usr/bin/env bash
# Kaisa pro-audio 基线门禁:检查 WirePlumber 片段、UCM Lua、卡 profile、sinks、IEC958。
# 退出码 0 = 通过1 = 未满足stdout 说明缺项)。
#
# 须在图形/用户会话下执行pactl 连接 PipeWire-Pulse勿裸 root 占用普通用户 XDG_RUNTIME_DIR。
# 若用 sudo 调用本脚本,需带 SUDO_USER脚本会经 sudo -u $SUDO_USER + XDG_RUNTIME_DIR 调用 pactl。
#
# 用法:./scripts/verify-kaisa-pro-audio.sh
set -uo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PACTL_PREFIX=()
WCONF_HOME="${HOME}"
if [[ $EUID -eq 0 && -n "${SUDO_USER:-}" ]] && command -v sudo &>/dev/null && id -u "$SUDO_USER" &>/dev/null; then
_VU="$(id -u "$SUDO_USER")"
if [[ -d "/run/user/${_VU}" ]]; then
_VH="$(getent passwd "$SUDO_USER" | cut -d: -f6)"
_VH="${_VH:-/home/$SUDO_USER}"
PACTL_PREFIX=(sudo -u "$SUDO_USER" env XDG_RUNTIME_DIR="/run/user/${_VU}" HOME="$_VH")
WCONF_HOME="$_VH"
fi
fi
if [[ $EUID -eq 0 && ${#PACTL_PREFIX[@]} -eq 0 ]]; then
echo "verify-kaisa-pro-audio: 当前为 root 且无法解析 SUDO_USER/会话;请用登录用户执行,或: sudo -u <用户> $0" >&2
exit 1
fi
fail() { echo "verify-kaisa-pro-audio: FAIL — $*" >&2; exit 1; }
ok() { echo "verify-kaisa-pro-audio: OK — $*"; }
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'
exit 0
fi
if ! command -v pactl &>/dev/null; then
fail "未找到 pactl建议安装 pulseaudio-utils"
fi
if ! command -v amixer &>/dev/null; then
fail "未找到 amixeralsa-utils"
fi
if ! grep -q 'sof-rt5682' /proc/asound/cards 2>/dev/null; then
fail "/proc/asound/cards 中无 sof-rt5682"
fi
ok "ALSA 卡 sof-rt5682 存在"
if [[ -f /usr/share/wireplumber/main.lua.d/60-kaisa-ucm.lua ]]; then
fail "仍存在可加载的 /usr/share/wireplumber/main.lua.d/60-kaisa-ucm.lua应改为 .disabled 或删除)"
fi
ok "60-kaisa-ucm.lua 未处于激活路径"
conf="${WCONF_HOME}/.config/wireplumber/wireplumber.conf.d/50-kaisa-sof-rt5682-hdmi.conf"
if [[ ! -f "$conf" ]]; then
fail "缺少用户 WirePlumber 片段: $conf"
fi
ok "用户级 50-kaisa-sof-rt5682-hdmi.conf 存在"
wp_state="${WCONF_HOME}/.local/state/wireplumber/default-profile"
if [[ -f "$wp_state" ]] && grep 'cml_rt5682' "$wp_state" 2>/dev/null | grep -qF 'stereo-fallback'; then
fail "WirePlumber 状态文件仍要求 cml_rt5682 使用 stereo-fallback会在重启后顶掉 pro-audio。请执行: ${REPO_ROOT}/scripts/strip-kaisa-default-profile-state.sh 后 systemctl --user restart wireplumber pipewire pipewire-pulse或重新运行 apply-kaisa-pro-audio.sh"
fi
pactl_cards="$("${PACTL_PREFIX[@]}" pactl list cards 2>/dev/null)" || fail "pactl list cards 失败"
if ! grep -qF 'cml_rt5682' <<< "$pactl_cards"; then
fail "pactl list cards 中无 cml_rt5682PCI/卡名是否与仓库 conf 一致?)"
fi
# 在「含 cml_rt5682 的卡」块内取第一条 活动配置 / Active Profile避免匹配到「配置文件」里的 pro-audio 行)
active_line="$(awk '
/^卡 #[0-9]+/ || /^Card #[0-9]+/ { in_c=0 }
/cml_rt5682/ { in_c=1 }
in_c && (/活动配置/ || /Active Profile/) { print; exit }
' <<< "$pactl_cards")"
if [[ -z "$active_line" ]]; then
fail "无法在 cml_rt5682 卡块内解析 活动配置/Active Profile 行"
fi
if [[ "$active_line" != *pro-audio* ]]; then
_al="$(echo "$active_line" | tr -d '\t' | sed 's/^[[:space:]]*//')"
fail "该卡活动配置不是 pro-audio当前: ${_al})。请执行: ${REPO_ROOT}/scripts/apply-kaisa-pro-audio.sh勿加 --verify-only"
fi
ok "pactl 声卡活动配置为 pro-audio"
sinks="$("${PACTL_PREFIX[@]}" pactl list short sinks 2>/dev/null)" || fail "pactl list short sinks 失败"
for po in pro-output-0 pro-output-2 pro-output-3 pro-output-4; do
if ! grep -F 'cml_rt5682' <<< "$sinks" | grep -qF "$po"; then
fail "缺少 sink …${po}pro-audio 下应暴露 Port1 + HDMI1/2/3"
fi
done
ok "pactl short sinks 含 pro-output-0/2/3/4cml_rt5682"
def="$("${PACTL_PREFIX[@]}" pactl get-default-sink 2>/dev/null)" || fail "pactl get-default-sink 失败"
if [[ "$def" != *pro-output-2* ]]; then
fail "默认 sink 应为 …pro-output-2当前: $def"
fi
ok "默认 sink 为 pro-output-2"
for i in 0 1 2; do
out="$(amixer -c0 sget "IEC958",$i 2>/dev/null || true)"
if ! grep -qiE '\[on\]|\[开启\]' <<< "$out"; then
fail "IEC958',$i' 非开启状态(需 amixer -c0 sset 'IEC958',$i on"
fi
done
ok "IEC958',0/1/2 均为 on"
echo "verify-kaisa-pro-audio: 全部检查通过。"
exit 0