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>
137 lines
6.5 KiB
Markdown
137 lines
6.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
|
|
|
|
This app is not in the official Homebrew Channel repository (that needs a
|
|
review submission — see [docs/development.md](docs/development.md)). Two ways
|
|
to get it onto the TV instead, neither needing SSH or Developer Mode:
|
|
|
|
**Add it as a custom repository (recommended).** The Homebrew Channel can
|
|
browse-and-install from any repository URL you give it, not just the official
|
|
one. Build the ipk, publish it plus a generated repo index, then add that URL
|
|
on the TV:
|
|
|
|
```sh
|
|
npm install # ares-cli, only needed for step 2
|
|
./tools/docker-build.sh # cross-compile; Linux: ./tools/build.sh native
|
|
./tools/build.sh package # -> out/*.ipk
|
|
python3 tools/make-manifest.py --base-url <where you'll host the release assets>
|
|
# -> out/repo.json, out/manifest.json
|
|
```
|
|
|
|
Attach the ipk, `frontend/assets/icon.png` and `out/repo.json` to a release at
|
|
that URL, then on the TV: **Homebrew Channel → ⚙ → Add repository** → paste the
|
|
`repo.json` URL → back to Browse → *Audio Cap* → Install. Full walkthrough,
|
|
including why the URLs have to match exactly, in
|
|
[docs/development.md](docs/development.md#publishing-to-the-homebrew-channel).
|
|
|
|
**Install the ipk directly**, if you do have ares-cli talking to the TV (e.g.
|
|
LG Developer Mode's ssh on port 9922, or a root SSH server you've enabled):
|
|
|
|
```sh
|
|
ares-install --device tv out/org.webosbrew.audiocap_1.0.0_all.ipk
|
|
```
|
|
|
|
## 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
|
|
docker/ the receiver, packaged as a container (e.g. for Unraid)
|
|
unraid/ the plugin for the one part a container can't do: the
|
|
ALSA loopback kernel module, persisted across reboots
|
|
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.
|