Files
lgtv_audio_cap/README.md
T
Rene KievitsandClaude Opus 5 3e4d0e17bc Build the service in a container, and fix what the target compiler found
The openlgtv NDK is a Linux toolchain with no macOS or Windows build, so
tools/build.sh could not produce a binary anywhere else. docker-build.sh
bakes the SDK into an image and compiles there; packaging and deploy stay
on the host, where the TV is reachable. The SDK ships aarch64 as well as
x86_64, so the image picks the one matching the daemon and Apple Silicon
builds natively rather than under emulation.

Cross-compiling for real turned up three things the host compiler did
not:

  sink_hyperhdr_viz.c  read p->width and p->height to format the error
                       message after free(p)
  sink_hyperhdr.c      an SDP connection line of 128 bytes cannot hold
                       "IN IP4 " plus a 127-byte host plus "/255", so a
                       long hostname would silently lose its TTL suffix
  common/log.c         the log body was sized to the whole ring line,
                       leaving nothing for the prefix; budget for it so
                       the bound is provable rather than left to
                       snprintf

A clean cross-compile is now warning-free, and readelf confirms the
design rule holds: luna-service2, glib, PmLogLib and libc, with no
libpulse or libasound.

Also: @webosose/ares-cli was pinned to ^3.0.0, which does not exist
(latest is 2.4.0), so npm install failed outright. build.sh now puts
node_modules/.bin on PATH so a local install is enough.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 10:29:09 +02:00

125 lines
5.5 KiB
Markdown

# LG TV Audio Cap
Captures the audio playing on an LG webOS 5 or 6 TV and streams it off the set.
The reason it exists is HyperHDR: ambient lighting that reacts to what the TV is
actually playing, without a microphone in the room or an audio splitter behind
the telly.
It installs through the [Homebrew Channel](https://github.com/webosbrew/webos-homebrew-channel)
and runs as a native background service with a remote-friendly UI in front of
it.
```
┌────────────────────── LG webOS TV ──────────────────────┐
│ PulseAudio / ALSA / a command │
│ │ │
│ capture ─► level + 16-band analysis │
│ │ │
│ ├─► RTP/L16 ──────────────► HyperHDR host │ ← the main path
│ ├─► Flatbuffers images ───► HyperHDR │
│ ├─► raw PCM over UDP │
│ ├─► raw PCM over TCP │
│ └─► WAV over HTTP │
└─────────────────────────────────────────────────────────┘
```
## Why it works this way
HyperHDR has **no network audio input**. Its sound-reactive effects read a
*local* capture device. So the main path here does not try to talk to HyperHDR
at all: it sends the TV's audio to the HyperHDR machine as RTP/L16, and a small
receiver there turns it into a normal sound device that HyperHDR can select.
That is [`host/lgtv-audiocap-receiver.py`](host/lgtv-audiocap-receiver.py), and
[`host/install-loopback.sh`](host/install-loopback.sh) sets up the loopback for
it.
If you would rather not run anything on the HyperHDR machine, there is a second
path: the TV does the frequency analysis itself and sends finished images to
HyperHDR's Flatbuffers port. Fewer moving parts, but the lights react to the
TV's idea of the spectrum rather than to real audio.
See [docs/hyperhdr.md](docs/hyperhdr.md) for both, step by step.
## Requirements
- An LG TV on webOS 5 or 6, rooted, with the Homebrew Channel installed.
- Root for the service. The TV's audio devices are not readable otherwise; the
app has a **Grant root access** button that calls the Homebrew Channel's
`elevate-service` for you.
- For the main HyperHDR path: a Linux machine running HyperHDR with either
`snd-aloop` or PulseAudio/PipeWire available.
## Installing
**From the Homebrew Channel.** Open the Homebrew Channel on the TV, find
*Audio Cap*, install, launch.
**From an ipk.** Copy the ipk to the TV and install it with the Homebrew
Channel's *Install from file*, or from a workstation:
```sh
ares-install --device tv out/org.webosbrew.audiocap_1.0.0_all.ipk
```
**From source.** The NDK is Linux-only, so on macOS or Windows the compile goes
through Docker:
```sh
npm install # ares-cli
./tools/docker-build.sh # or ./tools/build.sh native on Linux
./tools/build.sh package # -> out/*.ipk
```
See [docs/development.md](docs/development.md) for the rest.
## First run
1. Launch **Audio Cap** on the TV.
2. **System → Root access**: press *Grant root access* if it says the service is
not root. It restarts itself.
3. **Capture → Backend**: leave it on *Automatic* to begin with. If nothing is
captured, run [`tools/tv-probe.sh`](tools/tv-probe.sh) on the TV to see what
your firmware actually offers, then pick a backend by hand.
4. **Outputs → HyperHDR audio (RTP/L16)**: turn it on and enter the address of
the machine running HyperHDR.
5. On that machine: `sudo ./host/install-loopback.sh --install-service`, then
point HyperHDR's sound capture at the device it prints.
6. Press **Start** on the TV. The level meter should move.
Nothing captured, no idea why? [docs/troubleshooting.md](docs/troubleshooting.md).
## The other outputs
Each can run at the same time as the others.
| Output | What it is | Use it for |
| --- | --- | --- |
| **HyperHDR audio** | RTP/L16, port 5004 | the main path; also readable by PulseAudio's `module-rtp-recv` with no custom software |
| **HyperHDR visualiser** | Flatbuffers images, port 19400 | HyperHDR with nothing installed on the host |
| **Raw PCM over UDP** | S16LE datagrams, port 4010 | your own scripts; lowest latency |
| **Raw PCM over TCP** | S16LE stream, port 4011 | anything that would rather connect than listen |
| **HTTP WAV** | `http://tv:4012/audio.wav` | opening the TV's audio in VLC |
## Layout
```
native/ the webOS service: capture, DSP, sinks, Luna API (C)
frontend/ the on-TV app (plain HTML/CSS/JS, no framework)
servicefiles/ services.json, package.json and the boot script
host/ the receiver and loopback setup for the HyperHDR machine
tools/ build, packaging, asset generation, on-TV probe
test/ host-side tests: wire formats, the capture pipeline, the UI
docs/ the longer explanations
```
## Documentation
- [docs/hyperhdr.md](docs/hyperhdr.md) — connecting it to HyperHDR, both ways
- [docs/configuration.md](docs/configuration.md) — every setting, and the Luna API
- [docs/development.md](docs/development.md) — building, testing, packaging, publishing
- [docs/troubleshooting.md](docs/troubleshooting.md) — when it does not work
## License
MIT.