The device-source parser assumed pactl list short sources is strictly
tab-separated, true for stock PulseAudio but not guaranteed for a
TV's own heavily customized audio stack (this one names sources
tpcm_output/tpmedia/tptts/... — clearly not vanilla). A different
separator would have silently produced zero parsed sources with no
error, and the picker's own `when` guard would then just hide the row
entirely rather than show anything broken. Split on any whitespace
run instead of a literal tab; source names never contain embedded
whitespace, so this is strictly more permissive with no new failure
mode. Confirmed end to end on real hardware: tptts.monitor lit up
during the accessibility voice guide and reached HyperHDR.
Also: the System panel now shows the app's actual running version,
read from a <meta> tag substituted at package time (tools/build.sh
stage()) from frontend/appinfo.json — not hand-maintained, so it can't
drift from what was actually built. Requested after a version bump
alone wasn't enough to tell whether a reinstall had truly picked up
new files versus served something cached along the way; this settles
that question by inspection instead of by inference. Bumped to 1.0.2.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every rebuild since 1.0.0 kept the same version, so the ipk filename
and repo.json content never changed even though the contents did --
indistinguishable from a stale cache to both Homebrew Channel's
update check and any HTTP cache sitting between the release and the
TV. Bumping the version changes the ipk's filename outright, which
sidesteps that ambiguity regardless of what's caching what.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diagnosing capture on a real TV meant reading pactlSources off the
screen and typing an exact PulseAudio source name back in through the
same remote-driven text field — no way to copy-paste, easy to
mistype, and the one piece of information (which source, if any, is
actually RUNNING) was buried in a JSON dump.
Added two choice() pickers bound to the same capture.device setting:
one built from pactlSources (pulse/auto backends), one built from
alsaCapturePcms (alsa backend), both parsed from diagnostics the
service already collects — no new Luna method needed. Diagnostics
already run once at boot, so the picker is populated immediately,
before the user ever presses "Run diagnostics" by hand.
Picking a value writes straight into capture.device, and the plain
text field stays as the fallback for anything the parser misses.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Captures the TV's audio and sends it out over several transports. The
primary one is HyperHDR: RTP/L16 to a host-side loopback device, since
HyperHDR has no network audio input of its own. A second route renders
the spectrum on the TV and sends FlatBuffers images to port 19400
instead, for setups where touching the host's sound config is not an
option.
native/ the service: capture backends (PulseAudio, ALSA, exec,
test tone, all dlopen-based), DSP, and one file per sink
frontend/ D-pad driven UI at a fixed 1920x1080
servicefiles/ native service manifest plus the boot script
host/ RTP receiver and the loopback installer for the HyperHDR
machine
tools/ build/package, asset generation, Homebrew Channel
manifest, on-TV probe
test/ host-side suites: FlatBuffers and RTP verified against
real decoders, the engine end to end, the page in jsdom
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>