diff --git a/docs/impl/reports/HEADLESS.md b/docs/impl/reports/HEADLESS.md new file mode 100644 index 0000000..813884f --- /dev/null +++ b/docs/impl/reports/HEADLESS.md @@ -0,0 +1,68 @@ +--- +type: report +date: 2026-10-09 +--- +# Headless: No Desktop, No Sound Server + +## Why + +The car unit has no display of its own; the display is the tablet app. Anything graphical on the Orin +uses unified memory, which the voice stack (GPT-SoVITS TTS, Whisper ASR) needs more. + +## Result + +| Item | State | +|------|-------| +| Default target | `multi-user.target` (was `graphical.target`): GDM, Xorg and GNOME no longer start | +| Local console | `getty@tty1` enabled, so a text login appears on a directly attached monitor/keyboard | +| Sound servers | PulseAudio and PipeWire disabled for all users. **ALSA kept**: devices are still there for mic capture | +| Camera | `nvargus-daemon` kept (used by `camera-webui` and the later vision service) | +| Memory | "used" went from 1206 MB to 1005 MB (~200 MB) on an idle system (GDM greeter only, nobody logged in graphically) | + +Per-process RSS for the desktop added up to ~550 MB, but that counts shared pages once per process. The `free` difference is the real saving. + +## Commands + +``` +sudo systemctl set-default multi-user.target +sudo systemctl enable getty@tty1 +sudo systemctl --global disable pulseaudio.socket pulseaudio.service \ + pipewire.socket pipewire.service pipewire-media-session.service +sudo systemctl isolate multi-user.target # apply now, without a reboot +``` + +`disable` rather than `mask`: nothing is removed, and each step reverses cleanly. + +``` +sudo systemctl set-default graphical.target +sudo systemctl --global enable pulseaudio.socket pulseaudio.service \ + pipewire.socket pipewire.service pipewire-media-session.service +``` + +To start the desktop once without changing the default: `sudo systemctl start gdm`. + +## Audio + +Project Yukart's plan keeps the **microphone on the Orin** (Whisper) and sends **TTS to the tablet** as chunked +utterances. Neither needs a desktop sound server: + +- capture: read the ALSA device directly (`arecord -l` lists it; a USB mic adds its own card); +- playback on the Orin itself isn't needed (only HDMI is present: `card 0: HDA`). + +If a service later needs PipeWire anyway, run it for that service's user with `loginctl enable-linger `, +so it starts at boot without a login session. Don't re-enable it globally. + +## Side effects seen when switching live + +`systemctl isolate` re-ran two NVIDIA oneshot units, which then failed because their setup was already done: + +- `nvzramconfig`: `mkswap: /dev/zram5 is mounted`. All six zram swap devices are active, so nothing is missing. +- `nv_nvsciipc_init`: exits 1 on re-run. + +Both run only once on a normal boot. **To check at the next boot:** `systemctl --failed` should list neither. + +## Unrelated, pre-existing + +`logrotate.service` fails every night: `stat of /data/logging-volume/*.log failed: Permission denied`. +`/etc/logrotate.d/jetson-logging` (package `nvidia-jetson-services`) rotates as user `logging`, but `/data` is `drwx------ root`. +Harmless because nothing logs there. Left as is, since it's a package-owned file.