summaryrefslogtreecommitdiff
path: root/src/fruits/cmv
diff options
context:
space:
mode:
Diffstat (limited to 'src/fruits/cmv')
-rw-r--r--src/fruits/cmv/cmv.c151
-rw-r--r--src/fruits/cmv/meson.build25
2 files changed, 176 insertions, 0 deletions
diff --git a/src/fruits/cmv/cmv.c b/src/fruits/cmv/cmv.c
new file mode 100644
index 0000000..8eaa8b7
--- /dev/null
+++ b/src/fruits/cmv/cmv.c
@@ -0,0 +1,151 @@
+#include <al/log.h>
+#include <aki/event_loop.h>
+#include <aki/thread.h>
+
+#include "../../sink/desktop.h"
+#include "../../server/common.h"
+#include "../../codec/ffmpeg/common.h"
+#ifndef CAMU_SINK_ONLY
+#include "../../server/server.h"
+#include "../../server/list.h"
+#else
+#include "../../server/common.c"
+#endif
+
+struct cmv {
+ struct aki_event_loop loop;
+ struct camu_desktop desktop;
+#ifndef CAMU_SINK_ONLY
+ struct camu_server server;
+#endif
+};
+
+#ifndef CAMU_SINK_ONLY
+static void meta_callback(void *userdata, u8 op, struct lia_list_entry *entry)
+{
+ struct cmv *c = (struct cmv *)userdata;
+ (void)c;
+ switch (op) {
+ case LIANA_META_PLAYING: {
+ struct camu_server_resource *resource = (struct camu_server_resource *)entry->opaque;
+ al_log_info("server", "now playing: %.*s.", AL_STR_PRINTF(&resource->unique_id));
+ break;
+ }
+ }
+}
+
+static void exit_callback(void *userdata, struct camu_desktop *desktop)
+{
+ struct cmv *c = (struct cmv *)userdata;
+ (void)desktop;
+ camu_server_close(&c->server);
+}
+#endif
+
+static aki_thread_result AKI_THREADCALL event_loop_thread(void *userdata)
+{
+ struct cmv *c = (struct cmv *)userdata;
+ aki_event_loop_run(&c->loop);
+ return 0;
+}
+
+static struct cmv c = { 0 };
+
+static void sigint_handler(int signum)
+{
+ (void)signum;
+ c.desktop.should_quit = 1;
+}
+
+#define failure() do { \
+ goto out; \
+} while (0)
+
+#ifndef _WIN32
+s32 main(s32 argc, char *argv[])
+#else
+s32 wmain(s32 argc, wchar_t **argv)
+#endif
+{
+ if (!aki_common_init() || !stl_global_init(false)) {
+ return EXIT_FAILURE;
+ }
+
+ s32 ret = EXIT_FAILURE;
+
+ signal(SIGINT, sigint_handler);
+
+ camu_ff_set_default_log_callback();
+
+ aki_event_loop_init(&c.loop);
+
+ u8 type;
+ str *addr;
+#ifndef CAMU_SINK_ONLY
+ bool local = argc > 1;
+ if (local) {
+ type = AKI_SOCKET_UNIX; addr = CAMU_UNIX_LOCAL;
+ if (!camu_server_init(&c.server, type, &c.loop)) failure();
+ if (!camu_server_listen(&c.server, addr, CAMU_PORT)) failure();
+ struct camu_list *list = al_array_at(c.server.lists, 0);
+ list->impl.callback = meta_callback;
+ list->impl.userdata = &c;
+ } else {
+ type = CAMU_LOCAL_TYPE;
+ addr = CAMU_LOCAL_ADDR;
+ }
+#else
+ type = AKI_SOCKET_TCP; addr = CAMU_SERVER_IP;
+#endif
+
+#ifndef CAMU_SINK_ONLY
+ if (local) {
+ for (s32 i = 1; i < argc; i++) {
+#ifndef _WIN32
+ str arg = *al_str_cr(argv[i]);
+#else
+ str arg;
+ al_wstr_to_str(al_wstr_cr(argv[i]), &arg);
+#endif
+ struct aki_packet *packet = aki_packet_create();
+ aki_packet_write_str(packet, &arg);
+ camu_server_local_add(&c.server, packet);
+ }
+ }
+#else
+ (void)argc;
+ (void)argv;
+#endif
+
+ if (!camu_desktop_init(&c.desktop, "cmv")) failure();
+#ifndef CAMU_SINK_ONLY
+ if (local) {
+ c.desktop.exit_callback = exit_callback;
+ c.desktop.userdata = &c;
+ }
+#endif
+ if (!camu_desktop_connect(&c.desktop, type, &c.loop, addr, CAMU_PORT)) failure();
+
+ struct aki_thread thread0;
+ aki_thread_create(&thread0, event_loop_thread, &c);
+
+ while (camu_desktop_tick(&c.desktop)) {}
+
+ camu_desktop_stop(&c.desktop);
+ aki_thread_join(&thread0);
+ camu_desktop_free(&c.desktop);
+#ifndef CAMU_SINK_ONLY
+ camu_server_free(&c.server);
+#endif
+
+ ret = EXIT_SUCCESS;
+out:
+ aki_event_loop_destroy(&c.loop);
+
+ camu_ff_free_default_log_callback();
+
+ stl_global_close();
+ aki_common_close();
+
+ return ret;
+}
diff --git a/src/fruits/cmv/meson.build b/src/fruits/cmv/meson.build
new file mode 100644
index 0000000..ba571c3
--- /dev/null
+++ b/src/fruits/cmv/meson.build
@@ -0,0 +1,25 @@
+cmv_src = ['cmv.c']
+cmv_deps = [desktop]
+cmv_args = []
+if get_option('sink-only')
+ cmv_args += ['-DCAMU_SINK_ONLY']
+else
+ cmv_deps += [server]
+endif
+
+if get_option('portal').enabled()
+ cmv_deps += [portal]
+endif
+
+use_tui = false
+if use_tui
+ cmv_src += []
+ cmv_deps += [dependency('notcurses')]
+endif
+
+cmv_link_args = []
+if is_windows and meson.is_cross_build()
+ cmv_link_args += ['-static', '-static-libgcc', '-static-libstdc++', '-municode', '-mwindows']
+endif
+
+executable('cmv', cmv_src, dependencies: cmv_deps, c_args: cmv_args, link_args: cmv_link_args)