docs/scripts(kaisa): add doctor verify mode and HDMI readiness checks
Add a more detailed --verify flow to capture Jack/ELD/subdevices, route per sink, and collect kernel error windows. Improve --fix with readiness gating, retries, and connected-only selection; document single-monitor pcm mapping behavior and ignore local logs/artifacts. Made-with: Cursor
This commit is contained in:
213
scripts/kaisa-hdmi-stability-probe.sh
Executable file
213
scripts/kaisa-hdmi-stability-probe.sh
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env bash
|
||||
# Kaisa (sof-rt5682) HDMI stability probe.
|
||||
# Goal: one script to reproduce/quantify "reboot -> silent -> later OK" and capture
|
||||
# kernel SOF IPC(-5)/ASoC errors with monotonic timestamps.
|
||||
#
|
||||
# What it does (non-destructive, no service stop by default):
|
||||
# - Repeatedly tries playback on HiFi HDMI sinks (pcm=2/3/4 as requested)
|
||||
# - After each attempt, scrapes *new* kernel lines for SOF/ASoC HDMI hw_params failures
|
||||
# - Records ALSA subdevices availability, Jack/ELD states, default sink, and sinks list
|
||||
#
|
||||
# Logs:
|
||||
# ./_logs/kaisa-hdmi-stability-probe_<ts>.log (or $KAISA_LOG_DIR)
|
||||
#
|
||||
# Notes:
|
||||
# - Run as desktop user (no sudo). Needs access to kernel journal for best results.
|
||||
# - If journalctl -k is restricted, the script will still log PipeWire errors and ALSA state.
|
||||
set -euo pipefail
|
||||
|
||||
ts="$(date +%Y%m%d_%H%M%S)"
|
||||
log_dir="${KAISA_LOG_DIR:-./_logs}"
|
||||
out="${log_dir}/kaisa-hdmi-stability-probe_${ts}.log"
|
||||
|
||||
duration_s="${KAISA_PROBE_DURATION_S:-120}"
|
||||
interval_s="${KAISA_PROBE_INTERVAL_S:-2}"
|
||||
pcms="${KAISA_PROBE_PCMS:-2,3}" # comma-separated list: 2,3,4
|
||||
audio_file="${KAISA_PROBE_AUDIO_FILE:-/usr/share/sounds/alsa/Front_Center.wav}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./scripts/kaisa-hdmi-stability-probe.sh [--duration S] [--interval S] [--pcms 2,3,4]
|
||||
|
||||
Env overrides:
|
||||
KAISA_LOG_DIR
|
||||
KAISA_PROBE_DURATION_S
|
||||
KAISA_PROBE_INTERVAL_S
|
||||
KAISA_PROBE_PCMS
|
||||
KAISA_PROBE_AUDIO_FILE
|
||||
|
||||
Example:
|
||||
KAISA_PROBE_DURATION_S=180 KAISA_PROBE_PCMS=2,3 ./scripts/kaisa-hdmi-stability-probe.sh
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help) usage; exit 0 ;;
|
||||
--duration) duration_s="${2:?seconds}"; shift 2 ;;
|
||||
--interval) interval_s="${2:?seconds}"; shift 2 ;;
|
||||
--pcms) pcms="${2:?list}"; shift 2 ;;
|
||||
*) echo "Unknown arg: $1" >&2; usage >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
mkdir -p "$log_dir"
|
||||
exec > >(tee "$out") 2>&1
|
||||
|
||||
hr() { printf '\n%s\n' "================================================================================"; }
|
||||
sec() { hr; printf '%s\n' "$1"; hr; }
|
||||
note() { printf '\n[NOTE] %s\n' "$*"; }
|
||||
warn() { printf '\n[WARN] %s\n' "$*"; }
|
||||
|
||||
kernel_grep_re='sof-audio|sof_ipc3_pcm_hw_params|ipc tx error|STREAM_PCM_PARAMS|ASoC error|HDMI1|HDMI2|HDMI3|pcm2|pcm3|pcm4'
|
||||
pipewire_grep_re='set_hw_params|suspended -> error|Start error|hw_sofrt5682_[234]__sink'
|
||||
|
||||
get_default_sink() {
|
||||
pactl info 2>/dev/null | awk -F': ' '/^默认音频入口:|^Default Sink:/{print $2; exit}'
|
||||
}
|
||||
|
||||
list_sinks_short() {
|
||||
pactl list short sinks 2>/dev/null || true
|
||||
}
|
||||
|
||||
alsa_dump_subdevices() {
|
||||
aplay -l 2>/dev/null | awk '
|
||||
BEGIN { dev=""; }
|
||||
$0 ~ /^card [0-9]+: / { next }
|
||||
$0 ~ /, device [0-9]+: / {
|
||||
match($0, /device [0-9]+:/)
|
||||
dev=substr($0, RSTART+7, RLENGTH-8)
|
||||
gsub(/[^0-9]/,"",dev)
|
||||
print $0
|
||||
next
|
||||
}
|
||||
$0 ~ /(子设备:|Subdevices:)/ {
|
||||
print " " $0
|
||||
next
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
amixer_dump_jack_eld() {
|
||||
# Stable numids for this platform are often: Jack 10/16/22; ELD 15/21/27.
|
||||
# If they differ, doctor script can resolve dynamically; here we best-effort.
|
||||
for n in 10 16 22 15 21 27; do
|
||||
echo
|
||||
echo "\$ amixer -c0 cget numid=$n"
|
||||
amixer -c0 cget "numid=$n" 2>/dev/null || true
|
||||
done
|
||||
}
|
||||
|
||||
kernel_tail_since() {
|
||||
# Print kernel lines since a monotonic timestamp (string like "[ 78.312861]")
|
||||
# We do not rely on exact parse; we simply filter journalctl -k -b -o short-monotonic output
|
||||
# by lexicographic comparison on the bracketed numeric value.
|
||||
local since="${1:-}"
|
||||
if ! journalctl -k -b -o short-monotonic --no-pager &>/dev/null; then
|
||||
note "Cannot read kernel journal (journalctl -k)."
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "$since" ]]; then
|
||||
journalctl -k -b -o short-monotonic --no-pager | grep -E "$kernel_grep_re" | tail -n 80 || true
|
||||
return 0
|
||||
fi
|
||||
journalctl -k -b -o short-monotonic --no-pager | awk -v since="$since" '
|
||||
# since is like "[ 78.312861]"
|
||||
function num(s, x) {
|
||||
x=s
|
||||
gsub(/[\[\]]/,"",x)
|
||||
gsub(/^[[:space:]]+/,"",x)
|
||||
return x+0.0
|
||||
}
|
||||
{
|
||||
tag=""
|
||||
if (match($0, /^\[[^]]+\]/)) {
|
||||
tag=substr($0, RSTART, RLENGTH)
|
||||
}
|
||||
if (tag != "" && num(tag) >= num(since)) print $0
|
||||
}
|
||||
' | grep -E "$kernel_grep_re" | tail -n 120 || true
|
||||
}
|
||||
|
||||
now_monotonic() {
|
||||
# Current kernel journal last monotonic tag, best-effort.
|
||||
# journalctl -o short-monotonic lines start with: "[ 3.588851] ..."
|
||||
# which may tokenize as "[" "3.588851]" ... so we must extract up to the first "]".
|
||||
journalctl -k -b -o short-monotonic --no-pager 2>/dev/null | tail -n 1 | \
|
||||
awk '{ if (match($0, /^\[[^]]+\]/)) print substr($0, RSTART, RLENGTH); }' || true
|
||||
}
|
||||
|
||||
play_on_pcm() {
|
||||
local pcm="${1:?pcm}"
|
||||
local sink="alsa_output.pci-0000_00_1f.3-platform-cml_rt5682_def.HiFi__hw_sofrt5682_${pcm}__sink"
|
||||
echo
|
||||
echo "\$ pactl set-default-sink $sink"
|
||||
pactl set-default-sink "$sink" 2>/dev/null || true
|
||||
echo "\$ pw-play $audio_file"
|
||||
timeout -k 1s 5s pw-play "$audio_file" 2>/dev/null || true
|
||||
}
|
||||
|
||||
sec "Kaisa HDMI stability probe — report: $out"
|
||||
echo "\$ date"; date
|
||||
echo "\$ uname -a"; uname -a
|
||||
echo "\$ id"; id
|
||||
echo
|
||||
note "duration_s=$duration_s interval_s=$interval_s pcms=$pcms audio_file=$audio_file"
|
||||
note "Tip: run right after reboot, before any manual audio tweaks."
|
||||
|
||||
sec "Baseline: ALSA + Jack/ELD + sinks"
|
||||
echo "\$ aplay -l"; aplay -l || true
|
||||
echo
|
||||
echo "\$ aplay -l (subdevices summary)"; alsa_dump_subdevices || true
|
||||
sec "Jack/ELD (best-effort numid dump)"
|
||||
amixer_dump_jack_eld
|
||||
sec "PipeWire sinks"
|
||||
echo "\$ pactl info"; pactl info || true
|
||||
echo "\$ pactl list short sinks"; list_sinks_short
|
||||
|
||||
start_epoch="$(date +%s)"
|
||||
end_epoch="$((start_epoch + duration_s))"
|
||||
iter=0
|
||||
|
||||
last_mon="$(now_monotonic)"
|
||||
note "Kernel monotonic cursor (initial): ${last_mon:-<none>}"
|
||||
|
||||
sec "Loop"
|
||||
while [[ "$(date +%s)" -lt "$end_epoch" ]]; do
|
||||
iter="$((iter+1))"
|
||||
echo
|
||||
hr
|
||||
echo "[ITER $iter] time=$(date) default_sink=$(get_default_sink || true)"
|
||||
|
||||
# Try play on each requested pcm
|
||||
IFS=',' read -r -a pcm_arr <<< "$pcms"
|
||||
for pcm in "${pcm_arr[@]}"; do
|
||||
pcm="$(echo "$pcm" | tr -d '[:space:]')"
|
||||
[[ -n "$pcm" ]] || continue
|
||||
play_on_pcm "$pcm"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "[ITER $iter] sinks:"
|
||||
list_sinks_short
|
||||
|
||||
echo
|
||||
echo "[ITER $iter] new kernel hints since ${last_mon:-<none>}:"
|
||||
new_kernel="$(kernel_tail_since "${last_mon:-}")"
|
||||
if [[ -n "${new_kernel}" ]]; then
|
||||
warn "Kernel SOF/ASoC lines (tail):"
|
||||
printf '%s\n' "${new_kernel}"
|
||||
else
|
||||
echo "(none)"
|
||||
fi
|
||||
|
||||
# Advance cursor
|
||||
last_mon="$(now_monotonic)"
|
||||
|
||||
sleep "$interval_s"
|
||||
done
|
||||
|
||||
sec "Done"
|
||||
note "Saved: $out"
|
||||
note "If you hit failures, also capture: journalctl -k -b -o short-monotonic | grep -nE '$kernel_grep_re' | tail -n 200"
|
||||
Reference in New Issue
Block a user