Files
orin-nano-env-setup/docs/impl/reports/HEADLESS.md
T
mikkeli fc0836aec7 Go headless: multi-user target, tty1 console, no sound servers
The car unit has no display of its own (the tablet app is the display),
and unified memory is better spent on the voice stack. GDM/GNOME no
longer start, a text login stays on tty1, and PulseAudio/PipeWire are
disabled for all users while ALSA stays for mic capture. Saves ~200 MB
idle; every step is a reversible disable, not a removal.

Also notes the pre-existing nightly logrotate failure from the NVIDIA
jetson-logging config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:01:51 +09:00

69 lines
2.9 KiB
Markdown

---
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 <user>`,
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.