Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

native: speaker-first PCM selection + per-PCM name diagnostic

Follow-up to the SOF buffer-sizing fix. Amp toggles dropped from 10,686
to 4 per boot (big win) but speakers still silent. Suspicion: ac-native
opens hw:0,0 blindly, but on SOF JSL topologies card0 exposes multiple
playback PCMs and the Chromebook convention isn't universal — pcm0 may
be Headset (RT5682) while Speakers (MAX98360A) sits on pcm1, or vice
versa. Opening the wrong one means no audio ever reaches the amp,
regardless of whether DAPM + SD_MODE are correct.

Fix: before the legacy hw:0,0 → hw:1,0 → … fallback chain, scan
/proc/asound/cardN/pcmMp/info for name/id strings. Skip HDMI (monitor
audio, not speaker). Prefer "Speaker" match; accept "HiFi" / "Jack"
(SOF combined front-end name) as fallback. If neither exists we drop
through to the original hardcoded list so nothing regresses on boards
without /proc/asound.

Also dump each PCM's id + name in pre-launch.log so the next boot tells
us which PCM is actually the speaker device, end to end.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+53
+11
fedac/native/initramfs/init
··· 250 250 fi 251 251 echo "Sound class:" >> $LOG 252 252 ls /sys/class/sound/ 2>/dev/null >> $LOG 253 + # Per-PCM names — SOF topologies name PCMs like "Headset (*)", "Speakers (*)", 254 + # "HDMI1 (*)" in /proc/asound/card0/pcmNp/info. If ac-native is opening the 255 + # wrong PCM (speaker vs headphone), this answers it in one glance. 256 + echo "Card 0 PCM names:" >> $LOG 257 + for p in /proc/asound/card0/pcm*p/info; do 258 + [ -r "$p" ] || continue 259 + dev=$(dirname "$p" | sed 's|.*/||') 260 + name=$(grep -E '^name:' "$p" 2>/dev/null | head -1) 261 + id=$(grep -E '^id:' "$p" 2>/dev/null | head -1) 262 + echo " $dev: $id / $name" >> $LOG 263 + done 253 264 echo "ASoC debugfs:" >> $LOG 254 265 mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null 255 266 ls /sys/kernel/debug/asoc/ 2>/dev/null >> $LOG
+42
fedac/native/src/audio.c
··· 1756 1756 int err = -1; 1757 1757 int card_idx = 0; 1758 1758 1759 + // Smart PCM selection — on SOF topologies (Chromebooks), card0 typically 1760 + // exposes multiple playback PCMs with distinct names: "Headset (*)", 1761 + // "Speakers (*)", "HDMI1 (*)"… hw:0,0 blindly is fine on HDA-direct 1762 + // codecs but opens the wrong endpoint on SOF. Scan /proc/asound and 1763 + // prefer the PCM whose name contains "Speaker" (fall back to anything 1764 + // containing "HiFi" which is the common SOF FE name for both-path). 1765 + // HDMI PCMs are explicitly skipped — they'd play on monitor, not speakers. 1766 + for (int c = 0; c < 4 && err < 0; c++) { 1767 + for (int d = 0; d < 8 && err < 0; d++) { 1768 + char info_path[64]; 1769 + snprintf(info_path, sizeof(info_path), "/proc/asound/card%d/pcm%dp/info", c, d); 1770 + FILE *ip = fopen(info_path, "r"); 1771 + if (!ip) continue; 1772 + char line[256], id_str[96] = "", name_str[96] = ""; 1773 + while (fgets(line, sizeof(line), ip)) { 1774 + if (!strncmp(line, "id: ", 4)) snprintf(id_str, sizeof(id_str), "%s", line + 4); 1775 + if (!strncmp(line, "name: ", 6)) snprintf(name_str, sizeof(name_str), "%s", line + 6); 1776 + } 1777 + fclose(ip); 1778 + // Skip HDMI — those route to monitor audio, not internal speaker. 1779 + if (strstr(id_str, "HDMI") || strstr(name_str, "HDMI")) continue; 1780 + // Prefer Speaker name; accept HiFi (SOF combined FE) as fallback. 1781 + int is_speaker = (strstr(id_str, "Speaker") || strstr(name_str, "Speaker")); 1782 + int is_combined = (strstr(id_str, "HiFi") || strstr(name_str, "HiFi") || 1783 + strstr(id_str, "Jack") || strstr(name_str, "Jack")); 1784 + if (!is_speaker && !is_combined) continue; 1785 + char dev_str[16]; 1786 + snprintf(dev_str, sizeof(dev_str), "hw:%d,%d", c, d); 1787 + err = snd_pcm_open(&pcm, dev_str, SND_PCM_STREAM_PLAYBACK, 0); 1788 + if (err >= 0) { 1789 + fprintf(stderr, "[audio] SOF PCM match: %s (id=%.*s)\n", 1790 + dev_str, (int)strcspn(id_str, "\n"), id_str); 1791 + snprintf(audio->audio_device, sizeof(audio->audio_device), "%s", dev_str); 1792 + card_idx = c; 1793 + // Prefer speaker name over combined — if we found a Speaker, 1794 + // stop here; otherwise keep scanning in case a later PCM is 1795 + // the speaker (cheap sort: Speaker beats HiFi by continuing). 1796 + if (is_speaker) break; 1797 + } 1798 + } 1799 + } 1800 + 1759 1801 // AC_AUDIO_DEVICE override — try the env var device before the hardcoded list. 1760 1802 const char *env_dev = getenv("AC_AUDIO_DEVICE"); 1761 1803 if (env_dev && env_dev[0]) {