Audio capture and streaming app for webOS 5/6

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>
This commit is contained in:
Rene Kievits
2026-08-26 10:21:00 +02:00
co-authored by Claude Opus 5
commit 7529a60650
73 changed files with 12826 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
// Minimal luna-service2 stand-in for host-side syntax checks. Mirrors the
// signatures this project calls, so a typo or a wrong argument count is caught
// without a webOS SDK. See ../glib.h.
#pragma once
#include <glib.h>
#include <stdbool.h>
typedef struct LSHandle LSHandle;
typedef struct LSMessage LSMessage;
typedef struct {
int error_code;
char* message;
const char* file;
int line;
const char* func;
void* padding;
unsigned long magic;
} LSError;
typedef bool (*LSMethodFunction)(LSHandle* sh, LSMessage* msg, void* category_context);
typedef enum {
LUNA_METHOD_FLAGS_NONE = 0,
} LSMethodFlags;
typedef struct {
const char* name;
LSMethodFunction function;
LSMethodFlags flags;
} LSMethod;
typedef struct {
const char* name;
void* function;
unsigned int flags;
} LSSignal;
typedef struct {
const char* name;
void* function;
unsigned int flags;
} LSProperty;
void LSErrorInit(LSError* error);
void LSErrorFree(LSError* error);
bool LSRegister(const char* name, LSHandle** handle, LSError* error);
bool LSUnregister(LSHandle* handle, LSError* error);
bool LSRegisterCategory(LSHandle* handle, const char* category, LSMethod* methods,
LSSignal* signals, LSProperty* properties, LSError* error);
bool LSCategorySetData(LSHandle* handle, const char* category, void* user_data, LSError* error);
bool LSGmainAttach(LSHandle* handle, GMainLoop* loop, LSError* error);
const char* LSMessageGetPayload(LSMessage* message);
bool LSMessageIsSubscription(LSMessage* message);
bool LSMessageReply(LSHandle* sh, LSMessage* message, const char* reply, LSError* error);
bool LSSubscriptionAdd(LSHandle* sh, const char* key, LSMessage* message, LSError* error);
bool LSSubscriptionReply(LSHandle* sh, const char* key, const char* payload, LSError* error);