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>
5.2 KiB
When it does not work
Work down the chain: does the service run, does it capture, does the audio leave the TV, does it arrive, does HyperHDR see it.
The app says "No service"
The service did not start. Reinstall the app, then check from a shell on the TV:
luna-send -n 1 -f luna://org.webosbrew.audiocap.service/isRunning '{}'
ls -l /media/developer/apps/usr/palm/services/org.webosbrew.audiocap.service/
The binary must be there and executable. If luna-send reports
Service does not exist, the service failed to register on the bus — usually a
missing services.json or a binary built for the wrong architecture. Check with
file audiocap-service: it should say ARM, EABI5.
"The service is running as uid …" instead of as root
It has not been elevated. Press System → Grant root access, or run:
/media/developer/apps/usr/palm/services/org.webosbrew.hbchannel.service/elevate-service \
org.webosbrew.audiocap.service
Then restart the service (quit on the bus, or just relaunch the app).
Without root the audio devices are unreadable and the settings file falls back
to /tmp.
Nothing is captured
Capture → Backend on Automatic and the meter stays flat.
-
System → Run diagnostics. Look at
librariesandpulseSockets. Iflibpulse.so.0andlibasound.so.2are bothnull, no backend can work as built and you need theexecbackend with whatever binary the TV does have. -
Run the probe for the fuller picture:
ssh -p 9922 root@TV-IP 'sh -s' < tools/tv-probe.sh -
Prove the rest of the chain first. Set the backend to Test tone and start. If the tone reaches HyperHDR, the problem is only the capture end.
Common outcomes by firmware:
| What the probe shows | What to do |
|---|---|
a PulseAudio socket and pactl lists a .monitor source |
backend pulse, device = that source name (or blank) |
/proc/asound with a capture PCM |
backend alsa, device hw:X,Y from arecord -l |
only arecord or gst-launch-1.0 |
backend exec, e.g. arecord -D hw:0,0 -f S16_LE -r 48000 -c 2 -t raw |
| nothing at all | the audio path is inside the closed audio daemon; only the test tone will run |
The meter moves but the lights do not
Audio is being captured, so it is the transport or HyperHDR.
Is it leaving the TV? Enable the HTTP output and open
http://TV-IP:4012/audio.wav in VLC. If you hear the TV, the TV's side is
fine.
Is it arriving? On the HyperHDR machine:
./host/lgtv-audiocap-receiver.py --port 5004 --output - | \
aplay -f S16_LE -r 48000 -c 2 -
Nothing? Check the firewall (sudo ufw allow 5004/udp) and that the receiver
address on the TV is right. Watch the sink's own counters in
Status → Outputs: sendErrors climbing means the TV cannot even send.
Is HyperHDR listening to the right device? The loopback has two ends and
they are easy to swap. The receiver plays into hw:Loopback,0,0; HyperHDR must
capture hw:Loopback,1,0.
Is something else holding the loopback? PulseAudio grabs cards it finds.
install-loopback.sh writes a udev rule to keep it away; if you set the card up
by hand, add it yourself:
/etc/udev/rules.d/89-lgtv-audiocap-loopback.rules
ATTRS{id}=="Loopback", ENV{PULSE_IGNORE}="1", ENV{ACP_IGNORE}="1"
The audio crackles or drops out
The receiver prints loss statistics every 30 seconds. Read those first.
| Symptom | Cause | Fix |
|---|---|---|
| steady loss on Wi-Fi | the TV's radio | Ethernet, or the visualiser output instead |
| loss in bursts | buffer too small for the jitter | --latency-ms 150 --prebuffer-ms 120 |
| clicks with no reported loss | the loopback and the stream disagree about the rate | make the TV's rate, the receiver's --rate and HyperHDR's device all 48000 |
| audio slowly drifts out of sync | free-running clocks, unavoidable in a one-way stream | it is a few ms per hour; restart the receiver if it ever matters |
The lights react to the wrong thing
HyperHDR is showing another source at a higher priority. The visualiser sink sends at priority 150 by default; a screen grabber usually sits at 240 and a static colour at 100. Lower numbers win. Set the visualiser's priority below whatever is currently on screen.
Settings do not survive a reboot
System → Settings file says Temporary (/tmp). The service is not root, so it
cannot write /var/lib/webosbrew/audiocap/. Grant root access; the next save
lands in the persistent path.
It does not start with the TV
System → Start on boot installs a symlink in /var/lib/webosbrew/init.d/,
which the Homebrew Channel runs at boot. Check it:
ls -l /var/lib/webosbrew/init.d/audiocapautostart
If it is missing, the Homebrew Channel's exec refused the call — its
"root access" toggle has to be on. If it is there and nothing happens at boot,
check that autoStart is also on: the script only wakes the service, and the
service decides for itself whether to start capturing.
Reading the log
luna-send -n 1 -f luna://org.webosbrew.audiocap.service/getLogs '{}'
or System → Show log in the app. Set Log level to Debug first if you are chasing something specific — it is the last 200 lines only, and at Debug they go by quickly.