// Entry point for the native Luna service. // // Nothing interesting happens here: register on the bus, hand control to the // glib main loop, and make sure a SIGTERM from the service launcher shuts the // capture down cleanly so sinks get to say goodbye (HyperHDR in particular // needs its Clear, or the LEDs freeze on the last frame we sent). #include "common/log.h" #include "service.h" #include #include #include #include #include #include #include #include #define SERVICE_NAME "org.webosbrew.audiocap.service" // webOS 3.5 and earlier need the service registered on the public bus too. // Declared weak so the same binary keeps loading on newer firmware where the // symbol was removed. extern bool LSRegisterPubPriv(const char* name, LSHandle** handle, bool public_bus, LSError* error) __attribute__((weak)); static gboolean on_signal(gpointer user) { GMainLoop* loop = user; INFO("Signal received, shutting down"); g_main_loop_quit(loop); return G_SOURCE_REMOVE; } static void log_environment(void) { uid_t uid = getuid(); INFO("lgtv-audio-cap service starting (uid=%d%s)", (int)uid, uid == 0 ? ", root" : ", unprivileged"); if (uid != 0) { // Without root the PulseAudio socket and the ALSA devices are usually // out of reach, so say this once rather than leaving the user to // decode a permission error later. WARN("Not running as root: audio devices are likely inaccessible."); WARN("Install the Homebrew Channel 'elevate-service' patch and restart the service."); } } int main(int argc, char** argv) { bool debug = false; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0) debug = true; } log_init(debug ? LOG_DEBUG : LOG_INFO); log_environment(); // A client that hangs up mid-stream must not kill the service. Every send // path already asks for MSG_NOSIGNAL; this covers the rest. signal(SIGPIPE, SIG_IGN); GMainLoop* loop = g_main_loop_new(NULL, false); LSError lserror; LSErrorInit(&lserror); LSHandle* handle = NULL; bool registered = LSRegisterPubPriv ? LSRegisterPubPriv(SERVICE_NAME, &handle, true, &lserror) : LSRegister(SERVICE_NAME, &handle, &lserror); if (!registered) { ERR("Cannot register %s on the Luna bus: %s", SERVICE_NAME, lserror.message); LSErrorFree(&lserror); g_main_loop_unref(loop); return 1; } if (!LSGmainAttach(handle, loop, &lserror)) { ERR("Cannot attach to the main loop: %s", lserror.message); LSErrorFree(&lserror); LSUnregister(handle, &lserror); g_main_loop_unref(loop); return 1; } service_t* service = service_create(handle, loop); if (!service) { ERR("Cannot create the service"); LSUnregister(handle, &lserror); g_main_loop_unref(loop); return 1; } char err[256] = { 0 }; if (!service_register(service, err, sizeof(err))) { ERR("%s", err); service_destroy(service); LSUnregister(handle, &lserror); g_main_loop_unref(loop); return 1; } g_unix_signal_add(SIGTERM, on_signal, loop); g_unix_signal_add(SIGINT, on_signal, loop); INFO("Registered as %s", SERVICE_NAME); service_autostart(service); g_main_loop_run(loop); INFO("Shutting down"); service_destroy(service); if (!LSUnregister(handle, &lserror)) { ERR("Unregister failed: %s", lserror.message); LSErrorFree(&lserror); } g_main_loop_unref(loop); return 0; }