Files
chromebox_10th_audio_driver/audio_topology/collect_linux_audio_topology.sh
jack bda6b60c15 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
2026-04-08 15:22:45 +08:00

286 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#
# Chromebox 10 代 - Linux 音频硬件拓扑收集脚本
# 用于 C1a 任务:在 Linux 下收集硬件拓扑信息
#
# 用法: ./collect_linux_audio_topology.sh [输出文件]
# 默认输出到: audio_topology/collected/audio_topology_linux_$(hostname)_$(date).txt
#
# 建议: 用 sudo 运行以获取 dmesg/journalctlpactl/wpctl 需图形会话,
# 若用 sudo 会尝试以 SUDO_USER 身份调用,否则可在桌面终端直接运行
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/collected"
mkdir -p "$OUTPUT_DIR"
OUTPUT="${1:-${OUTPUT_DIR}/audio_topology_linux_$(hostname)_$(date +%Y%m%d_%H%M%S).txt}"
TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT
log() {
echo "[$(date +%H:%M:%S)] $*"
}
section() {
echo "" >> "$OUTPUT"
echo "========================================" >> "$OUTPUT"
echo "### $1" >> "$OUTPUT"
echo "========================================" >> "$OUTPUT"
echo "" >> "$OUTPUT"
}
run_cmd() {
local desc="$1"
shift
echo "# $desc" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
if "$@" >> "$OUTPUT" 2>&1; then
true
else
echo "(命令返回非零,可能部分信息缺失)" >> "$OUTPUT"
fi
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
}
log "开始收集 Linux 音频硬件拓扑..."
log "输出文件: $OUTPUT"
: > "$OUTPUT"
echo "# Chromebox 10 代 - Linux 音频硬件拓扑" >> "$OUTPUT"
echo "# 收集时间: $(date -Iseconds)" >> "$OUTPUT"
echo "# 主机: $(hostname)" >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- 系统信息 ---
section "系统信息"
run_cmd "uname -a" uname -a
run_cmd "内核版本" uname -r
run_cmd "/proc/version" cat /proc/version
if command -v alsactl &>/dev/null; then
run_cmd "ALSA 版本" alsactl --version 2>/dev/null || echo "alsactl 无版本信息"
fi
# --- PCI 音频设备 ---
section "PCI 音频相关设备"
if command -v lspci &>/dev/null; then
run_cmd "lspci -nn | grep -i audio (含设备 ID便于查驱动/quirks)" bash -c "lspci -nn | grep -i audio || echo '(无匹配)'"
run_cmd "lspci | grep -i audio" bash -c "lspci | grep -i audio || echo '(无匹配)'"
run_cmd "lspci -v | grep -A 15 -i audio" bash -c "lspci -v 2>/dev/null | grep -A 15 -i audio || echo '(无匹配)'"
fi
# --- 播放/录音设备列表 ---
section "ALSA 设备列表"
if command -v aplay &>/dev/null; then
run_cmd "aplay -l (播放设备)" aplay -l
run_cmd "aplay -L (ALSA 设备描述)" aplay -L 2>/dev/null || true
else
echo "# aplay 未安装" >> "$OUTPUT"
fi
if command -v arecord &>/dev/null; then
run_cmd "arecord -l (录音设备)" arecord -l
fi
run_cmd "cat /proc/asound/cards" cat /proc/asound/cards
run_cmd "cat /proc/asound/pcm (PCM 设备明细)" cat /proc/asound/pcm
# --- /proc/asound 目录结构 ---
section "/proc/asound 目录结构"
run_cmd "ls -la /proc/asound" ls -la /proc/asound
for card_dir in /proc/asound/card[0-9]*; do
if [ -d "$card_dir" ]; then
card=$(basename "$card_dir")
echo "# $card 目录内容:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls -la "$card_dir" 2>/dev/null >> "$OUTPUT" || true
echo "\`\`\`" >> "$OUTPUT"
fi
done
# --- Codec 信息 (HDA) ---
section "HDA Codec 信息"
for codec in /proc/asound/card*/codec*; do
if [ -f "$codec" ]; then
echo "# $codec" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat "$codec" >> "$OUTPUT" 2>/dev/null || echo "(无法读取)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
if ! ls /proc/asound/card*/codec* &>/dev/null; then
echo "(未找到 codec 文件)" >> "$OUTPUT"
fi
# --- ELD 内容 (HDMI 显示器音频能力,对 HDMI 无声排查很重要) ---
section "HDMI ELD 内容"
for eld in /proc/asound/card*/eld*; do
if [ -f "$eld" ]; then
echo "# $eld" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat "$eld" >> "$OUTPUT" 2>/dev/null || echo "(无法读取,或 ELD 为空/未连接)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
# --- /sys/class/sound 拓扑 ---
section "/sys/class/sound 设备"
if [ -d /sys/class/sound ]; then
run_cmd "ls -la /sys/class/sound" ls -la /sys/class/sound
for card in /sys/class/sound/card[0-9]*; do
if [ -d "$card" ]; then
name=$(basename "$card")
echo "# $name 设备属性:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for f in id number; do
if [ -f "$card/$f" ]; then
echo "$f: $(cat "$card/$f" 2>/dev/null)" >> "$OUTPUT"
fi
done
echo "\`\`\`" >> "$OUTPUT"
fi
done
fi
# --- 内核日志中的音频相关信息 ---
section "内核日志 (dmesg) 音频相关"
echo "# dmesg | grep -iE 'snd|hda|audio|codec|hdmi'" >> "$OUTPUT"
echo "# 提示: 若此处显示「需要 root」请用 sudo 重新运行本脚本以获取完整日志" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
dmesg 2>/dev/null | grep -iE 'snd|hda|audio|codec|hdmi' >> "$OUTPUT" || echo "(需要 root 或 dmesg 不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- Kaisa HDMI / SOF IPC 基线(辅助采集;用户态排障见 docs/linux-hdmi/OPERATION_PipeWire_Kaisa_UCM_HiFi.md---
section "SOF / HDMI / IPC 基线 (dmesg)"
echo "# dmesg | grep -iE 'sof|STREAM_PCM|ipc failed|ipc tx|pcm[0-9]|ASoC|iDisp|hdmi' | tail -120" >> "$OUTPUT"
echo "# 用于对照 SOF/IPC 与 dmesg建议 sudo 运行本脚本以读全量 dmesg" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
dmesg 2>/dev/null | grep -iE 'sof|STREAM_PCM|ipc failed|ipc tx|pcm[0-9]|ASoC|iDisp|hdmi' | tail -120 >> "$OUTPUT" || echo "(需要 root 或 dmesg 不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
section "HDMI 试听命令提示(人工执行)"
{
echo "# 在 aplay -L 中查找 HDMI / DisplayPort 设备后,对每个候选 plughw 试播Ctrl+C 结束):"
echo "# speaker-test -D plughw:卡号,设备号 -c 2 -l 1"
echo "# 若 dmesg 已出现 SOF IPC / PARAMS 类错误,用户态换 sink 通常无法单独修复。"
} >> "$OUTPUT"
echo "" >> "$OUTPUT"
# --- 可选: journalctl 内核日志 (补充 dmesg含启动后日志) ---
section "journalctl 内核日志 (SOF/音频,可选补充)"
if command -v journalctl &>/dev/null; then
echo "# journalctl -b -k --no-pager | grep -iE 'sof|snd|hda|audio|hdmi' | tail -80" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
journalctl -b -k --no-pager 2>/dev/null | grep -iE 'sof|snd|hda|audio|hdmi' | tail -80 >> "$OUTPUT" || echo "(journalctl 需 root 或不可用)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
else
echo "(journalctl 未安装)" >> "$OUTPUT"
fi
# --- 可选: ACPI NHLT 表 (Coreboot 下常缺失,影响 SOF) ---
section "ACPI NHLT 表"
if [ -d /sys/firmware/acpi/tables ]; then
echo "# ls /sys/firmware/acpi/tables/ | grep -i nhlt" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls /sys/firmware/acpi/tables/ 2>/dev/null | grep -i nhlt >> "$OUTPUT" || echo "(未找到 NHLT 表Coreboot 下常见)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
else
echo "(/sys/firmware/acpi/tables 不可用)" >> "$OUTPUT"
fi
# --- 可选: sof-logger (若已安装,可查看 SOF 固件 trace) ---
section "sof-logger (可选)"
# sudo 下同时检查 SUDO_USER 的 ~/.local/bin用户可能安装于此
if [ -n "${SUDO_USER:-}" ]; then
USER_HOME=$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6)
[ -n "$USER_HOME" ] && [ -d "$USER_HOME/.local/bin" ] && export PATH="$USER_HOME/.local/bin:$PATH"
fi
if command -v sof-logger &>/dev/null; then
echo "# sof-logger -t 2>/dev/null | tail -30 (DMA trace无需 ldc 文件)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
SOF_LOG=$(timeout 3 sof-logger -t 2>/dev/null | tail -30) || true
if [ -z "$SOF_LOG" ]; then
echo "(sof-logger 执行超时或需 root/debugfs)" >> "$OUTPUT"
elif echo "$SOF_LOG" | grep -q "Usage sof-logger"; then
echo "(sof-logger 输出 Usage通常表示 debugfs 未挂载或需 root 权限读取 /sys/kernel/debug/sof/)" >> "$OUTPUT"
else
echo "$SOF_LOG" >> "$OUTPUT"
fi
echo "\`\`\`" >> "$OUTPUT"
else
echo "(sof-logger 未安装,可从 thesofproject/sof-bin 或发行版 firmware-sof 相关包安装)" >> "$OUTPUT"
fi
# --- 音频服务/会话 ---
section "音频服务 (PulseAudio / PipeWire)"
echo "# 提示: sudo 下会以原用户身份调用 pactl/pw-cli需设置 XDG_RUNTIME_DIR 以连接用户会话" >> "$OUTPUT"
RUN_PACTL() {
if [ -n "${SUDO_USER:-}" ] && [ -d "/run/user/$(id -u "$SUDO_USER" 2>/dev/null)" ]; then
runuser -u "$SUDO_USER" -- env XDG_RUNTIME_DIR="/run/user/$(id -u "$SUDO_USER")" "$@"
else
"$@"
fi
}
if command -v pactl &>/dev/null; then
run_cmd "pactl info" RUN_PACTL pactl info 2>/dev/null || run_cmd "pactl info (直接调用)" pactl info 2>/dev/null || true
run_cmd "pactl list cards (含 HDMI/3.5mm 等 profile)" RUN_PACTL pactl list cards 2>/dev/null || true
run_cmd "pactl list sinks short" RUN_PACTL pactl list sinks short 2>/dev/null || true
fi
if command -v pw-cli &>/dev/null; then
run_cmd "pw-cli list-objects Device" RUN_PACTL pw-cli list-objects Device 2>/dev/null || true
fi
if command -v wpctl &>/dev/null; then
run_cmd "wpctl status (WirePlumber)" RUN_PACTL wpctl status 2>/dev/null || true
fi
# --- 已加载的音频相关内核模块 ---
section "音频相关内核模块"
run_cmd "lsmod | grep -iE 'snd|hda|sound'" bash -c "lsmod | grep -iE 'snd|hda|sound' || echo '(无匹配)'"
# --- 混音器状态 ---
section "ALSA 混音器状态"
if command -v amixer &>/dev/null; then
run_cmd "amixer -c 0 contents (或 -c default)" amixer -c 0 contents 2>/dev/null || amixer contents 2>/dev/null || echo "(amixer 执行失败)" >> "$OUTPUT"
fi
# --- SOF 固件与拓扑 ---
section "SOF 固件 (Intel Sound Open Firmware)"
if [ -f /sys/kernel/debug/sof/fw_version ]; then
echo "# /sys/kernel/debug/sof/fw_version (需 root)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
cat /sys/kernel/debug/sof/fw_version 2>/dev/null >> "$OUTPUT" || echo "(无法读取)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
echo "" >> "$OUTPUT"
fi
if [ -d /lib/firmware/intel ]; then
echo "# ls -la /lib/firmware/intel/ (sof 相关)" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
ls -la /lib/firmware/intel/ 2>/dev/null | grep -E 'sof|avs' >> "$OUTPUT" || ls -la /lib/firmware/intel/ >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for tplg_dir in /lib/firmware/intel/sof /lib/firmware/intel/sof-tplg; do
if [ -d "$tplg_dir" ]; then
echo "# SOF 拓扑: $tplg_dir" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
find "$tplg_dir" -type f -name '*tplg*' 2>/dev/null | head -30 >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
fi
done
else
echo "(未找到 /lib/firmware/intel)" >> "$OUTPUT"
fi
# --- 机器/主板识别 (ACPI) ---
section "机器识别 (主板/机型)"
if [ -f /sys/class/dmi/id/board_name ]; then
echo "# DMI 主板信息:" >> "$OUTPUT"
echo "\`\`\`" >> "$OUTPUT"
for f in /sys/class/dmi/id/board_name /sys/class/dmi/id/product_name /sys/class/dmi/id/sys_vendor; do
[ -f "$f" ] && echo "$(basename $f): $(cat "$f" 2>/dev/null)" >> "$OUTPUT"
done
echo "\`\`\`" >> "$OUTPUT"
fi
log "收集完成,结果已保存到: $OUTPUT"