Confirmed the brightness command applies globally, not per-LED
(serverinfo showed exactly one adjustment object, "id": "default",
covering the whole string), so no LED-count configuration is needed
for this at all -- that question resolved itself once the mechanism
was actually inspected instead of assumed.
For "only react while Spotify is running": only one app can be in the
foreground on webOS at a time, so a "capture the current app" button
in this app's own UI can never work -- pressing it means this app is
foreground, not Spotify. The only workable UI is picking a target from
every *installed* app by name, regardless of what's currently running.
That needed a new native capability this service never had: calling
OUT to another Luna service, not just being called. Two additions:
foreground_app.c subscribes once, at startup, to
com.webos.applicationManager/getForegroundAppInfo
and keeps a thread-safe cache the audio thread can
read without a blocking Luna call
service.c new listApps method, bridging to
com.webos.applicationManager/listApps so the
frontend never has to call another service
directly -- same rule as everywhere else here
Until the subscription has delivered at least one reply, a restricted
sink treats the target app as inactive, not active -- reacting to
audio when the user explicitly restricted it to one app would be the
wrong failure mode. Verified end to end on the host: engine_smoke.c
opens the sink with a restriction set, confirms it reports itself
correctly inactive against the stub Luna bus (which always "fails" to
call out, exactly like a real host with no bus).
Needed real, linkable stub bodies for LSCall/LSCallOneReply/
LSCallCancel/LSMessageGetPayload/LSErrorInit/LSErrorFree
(test/stubs/luna-service2/lunaservice_stub.c) since foreground_app.c
is the first source file here that's actually linked into a host test
binary rather than only syntax-checked -- service.c/main.c's existing
stub declarations were never called, only compiled against. Confirmed
those really are the correct symbol names by cross-compiling clean
against the real webOS SDK's actual libluna-service2, not just the
stub.
Bumped to 1.0.5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
108 lines
3.4 KiB
Bash
Executable File
108 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Host-side tests. These build the parts of the service that are not tied to
|
|
# webOS with the system compiler and run them, so the risky code (FlatBuffers
|
|
# encoding, the capture pipeline, socket framing) is verified before anything
|
|
# is ever copied to a TV.
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
CC="${CC:-cc}"
|
|
# verify_rtp.py imports the host receiver by path; without this it would leave a
|
|
# __pycache__ next to it.
|
|
export PYTHONDONTWRITEBYTECODE=1
|
|
OUT=$(mktemp -d)
|
|
trap 'rm -rf "$OUT"' EXIT
|
|
|
|
CFLAGS=(-std=c11 -Wall -Wextra -Wno-unused-parameter -D_GNU_SOURCE -Inative/src -Itest/stubs -O1 -g)
|
|
|
|
SOURCES=(
|
|
native/src/engine.c
|
|
native/src/config.c
|
|
native/src/dsp.c
|
|
native/src/foreground_app.c
|
|
test/stubs/luna-service2/lunaservice_stub.c
|
|
native/src/common/log.c
|
|
native/src/common/json.c
|
|
native/src/common/ringbuf.c
|
|
native/src/capture/capture.c
|
|
native/src/capture/cap_pulse.c
|
|
native/src/capture/cap_alsa.c
|
|
native/src/capture/cap_exec.c
|
|
native/src/capture/cap_tone.c
|
|
native/src/net/flatbuf.c
|
|
native/src/net/hyperion.c
|
|
native/src/net/streamserv.c
|
|
native/src/sinks/sink.c
|
|
native/src/sinks/sink_hyperhdr.c
|
|
native/src/sinks/sink_hyperhdr_viz.c
|
|
native/src/sinks/sink_hyperhdr_adjust.c
|
|
native/src/sinks/sink_udp.c
|
|
native/src/sinks/sink_tcp.c
|
|
native/src/sinks/sink_http.c
|
|
)
|
|
|
|
echo "== Syntax-checking the webOS-only sources against stub headers"
|
|
for f in native/src/service.c native/src/main.c; do
|
|
"$CC" "${CFLAGS[@]}" -fsyntax-only "$f"
|
|
echo " ok $f"
|
|
done
|
|
|
|
echo
|
|
echo "== FlatBuffers wire format"
|
|
if python3 -c "import flatbuffers" 2>/dev/null; then
|
|
python3 test/verify_flatbuf.py
|
|
else
|
|
echo " SKIP: the 'flatbuffers' Python package is not installed"
|
|
echo " python3 -m venv /tmp/fbvenv && /tmp/fbvenv/bin/pip install flatbuffers"
|
|
echo " CC=$CC /tmp/fbvenv/bin/python test/verify_flatbuf.py"
|
|
fi
|
|
|
|
echo
|
|
echo "== RTP wire format, against the host receiver"
|
|
"$CC" "${CFLAGS[@]}" -o "$OUT/rtp_send" test/rtp_send.c "${SOURCES[@]}" -lpthread -lm
|
|
python3 test/verify_rtp.py "$OUT/rtp_send"
|
|
|
|
echo
|
|
echo "== Capture pipeline end to end"
|
|
"$CC" "${CFLAGS[@]}" -o "$OUT/engine_smoke" test/engine_smoke.c "${SOURCES[@]}" -lpthread -lm
|
|
"$OUT/engine_smoke"
|
|
|
|
echo
|
|
echo "== Unraid plugin"
|
|
python3 test/verify_unraid_plugin.py
|
|
|
|
echo
|
|
echo "== Receiver container"
|
|
if command -v docker >/dev/null 2>&1; then
|
|
docker build -f docker/Dockerfile -t lgtv-audiocap-receiver:test-run . >/dev/null 2>&1
|
|
docker run --rm lgtv-audiocap-receiver:test-run --help >/dev/null
|
|
echo " ok image builds and forwards --help"
|
|
docker rmi lgtv-audiocap-receiver:test-run >/dev/null 2>&1
|
|
else
|
|
echo " SKIP: docker is not installed"
|
|
fi
|
|
|
|
echo
|
|
echo "== Frontend"
|
|
if command -v node >/dev/null 2>&1; then
|
|
for f in frontend/js/*.js; do
|
|
node --check "$f"
|
|
echo " ok $f"
|
|
done
|
|
|
|
# jsdom is a test-only dependency; the app itself has none. `npm install`
|
|
# puts it in node_modules, or point JSDOM_PATH at an install elsewhere.
|
|
if [ -z "${JSDOM_PATH:-}" ] && [ -d node_modules/jsdom ]; then
|
|
JSDOM_PATH="$PWD/node_modules"
|
|
fi
|
|
JSDOM_PATH="${JSDOM_PATH:-/tmp/audiocap-domtest/node_modules}"
|
|
if NODE_PATH="$JSDOM_PATH" node -e "require('jsdom')" 2>/dev/null; then
|
|
NODE_PATH="$JSDOM_PATH" node test/ui_smoke.js
|
|
else
|
|
echo " SKIP: jsdom is not installed, so the page was not run"
|
|
echo " mkdir -p /tmp/audiocap-domtest && cd /tmp/audiocap-domtest && npm i jsdom"
|
|
fi
|
|
else
|
|
echo " SKIP: node is not installed"
|
|
fi
|