summaryrefslogtreecommitdiff
path: root/src/fruits/cmv
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2024-01-06 19:54:21 -0500
committerAndrew Opalach <andrew@akon.city> 2024-01-06 19:54:21 -0500
commite6c1c0afc69ee13465bb68a6bdeb35b6876146d4 (patch)
treeffea140be35691dfc24e9a6ca6c54e2d0247e8a8 /src/fruits/cmv
parent11bbaf5198d15da44731ffb63411558f1c72f97e (diff)
downloadcamu-e6c1c0afc69ee13465bb68a6bdeb35b6876146d4.tar.gz
camu-e6c1c0afc69ee13465bb68a6bdeb35b6876146d4.tar.bz2
camu-e6c1c0afc69ee13465bb68a6bdeb35b6876146d4.zip
Initial synced playback
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'src/fruits/cmv')
-rw-r--r--src/fruits/cmv/cmv2.c363
-rw-r--r--src/fruits/cmv/meson.build10
-rw-r--r--src/fruits/cmv/tui.c165
-rw-r--r--src/fruits/cmv/tui.h28
4 files changed, 0 insertions, 566 deletions
diff --git a/src/fruits/cmv/cmv2.c b/src/fruits/cmv/cmv2.c
deleted file mode 100644
index 89e3427..0000000
--- a/src/fruits/cmv/cmv2.c
+++ /dev/null
@@ -1,363 +0,0 @@
-#define CMV_USE_TUI 0
-#define CMV_USE_SOCKET 0
-
-#include <al/log.h>
-#include <aki/event_loop.h>
-#if CMV_USE_SOCKET
-#include <aki/line_processor.h>
-#endif
-
-#include "../../codec/libav/common.h"
-
-#include "../../mixer/audio_miniaudio.h"
-
-#include "../../screen/screen.h"
-#include "../../render/renderer_libplacebo.h"
-//#include "../../render/renderer_tiger.h"
-
-#include "../../libsink/sink2.h"
-#include "../../tree/common.h"
-
-#include "../../shoki/src/search.h"
-
-#include "../cap/cap.h"
-
-#if CMV_USE_TUI
-#include "tui.h"
-#endif
-
-struct cmv {
- s32 quit;
- struct camu_screen scr;
- struct camu_renderer *renderer;
- struct camu_mixer mixer;
- struct aki_event_loop loop;
- struct camu_sink sink;
- struct cap_runner cap;
-#if CMV_USE_SOCKET
- struct aki_socket socket;
- struct aki_line_processor pro;
-#endif
-#if CMV_USE_TUI
- struct cmv_tui tui;
- struct aki_timer timer;
-#endif
-};
-
-static str *default_list = al_str_c("default");
-
-static u8 sink_callback(void *userdata, u8 op, u8 type, void *opaque)
-{
- struct cmv *c = (struct cmv *)userdata;
- switch (op) {
- case CAMU_SINK_ADD_BUFFER:
- switch (type) {
- case CAMU_SINK_AUDIO: {
- struct camu_audio_buffer *buf = (struct camu_audio_buffer *)opaque;
- camu_mixer_add_buffer(&c->mixer, buf);
- al_log_debug("cmv", "Audio buffer added.");
- break;
- }
- case CAMU_SINK_VIDEO: {
- struct camu_video_buffer *buf = (struct camu_video_buffer *)opaque;
- camu_screen_add_buffer(&c->scr, buf);
- al_log_debug("cmv", "Video buffer added.");
- break;
- }
- }
- break;
- case CAMU_SINK_REMOVE_BUFFER:
- switch (type) {
- case CAMU_SINK_AUDIO: {
- struct camu_audio_buffer *buf = (struct camu_audio_buffer *)opaque;
- camu_mixer_remove_buffer(&c->mixer, buf);
- al_log_debug("cmv", "Audio buffer removed.");
- break;
- }
- case CAMU_SINK_VIDEO: {
- struct camu_video_buffer *buf = (struct camu_video_buffer *)opaque;
- camu_screen_remove_buffer(&c->scr, buf);
- al_log_debug("cmv", "Video buffer removed.");
- break;
- }
- }
- break;
- case CAMU_SINK_SWAP_BUFFER:
- switch (type) {
- case CAMU_SINK_AUDIO: {
- struct camu_audio_buffer *buf = (struct camu_audio_buffer *)opaque;
- camu_mixer_remove_buffer(&c->mixer, buf);
- if (cap_list_set_completed(&c->cap, default_list)) {
- al_log_debug("cmv", "Audio buffers swapped (gapless).");
- return CAMU_SINK_BUFFERS_SWAPPED;
- } else {
- al_log_debug("cmv", "Audio buffer removed.");
- }
- break;
- }
- }
- break;
- case CAMU_SINK_SET_BUFFERED: {
- cap_list_pump(&c->cap, default_list, true);
- break;
- }
- case CAMU_SINK_START:
- switch (type) {
- case CAMU_SINK_AUDIO: {
- camu_mixer_resume(&c->mixer);
- al_log_debug("cmv", "Audio started.");
- break;
- }
- case CAMU_SINK_VIDEO: {
- camu_screen_set_state(&c->scr, CAMU_SCREEN_PLAYING);
- camu_screen_wake(&c->scr);
- al_log_debug("cmv", "Video started.");
- break;
- }
- }
- break;
- case CAMU_SINK_STOP:
- switch (type) {
- case CAMU_SINK_AUDIO: {
- camu_mixer_pause(&c->mixer);
- al_log_debug("cmv", "Audio stopped.");
- break;
- }
- case CAMU_SINK_VIDEO: {
- camu_screen_set_state(&c->scr, CAMU_SCREEN_PAUSED);
- al_log_debug("cmv", "Video stopped.");
- break;
- }
- }
- break;
- case CAMU_SINK_EXIT:
-#if CMV_USE_SOCKET
- aki_line_processor_stop(&c->pro);
- aki_socket_close(&c->socket);
-#endif
- camu_sink_close(&c->sink);
- aki_event_loop_break(&c->loop);
- break;
- }
- return CAMU_SINK_OK;
-}
-
-static void screen_callback(void *userdata, u8 op, f64 float0)
-{
- struct cmv *c = (struct cmv *)userdata;
- switch (op) {
- case CAMU_SCREEN_NEXT:
- cap_list_skip(&c->cap, default_list, 1);
- break;
- case CAMU_SCREEN_PREVIOUS:
- cap_list_skip(&c->cap, default_list, -1);
- break;
- case CAMU_SCREEN_TOGGLE_PAUSE:
- camu_sink_toggle_pause(&c->sink);
- break;
- case CAMU_SCREEN_SEEK:
- camu_sink_seek(&c->sink, float0);
- break;
- case CAMU_SCREEN_CLOSE:
- c->quit = 1;
- break;
- }
-}
-
-/*
-static bool cap_callback(void *userdata, u8 op, str *name, str *unique_id, void *opaque)
-{
- struct cmv *c = (struct cmv *)userdata;
- (void)name;
- switch (op) {
- case CAP_BUFFER:
- return camu_sink_local_buffer(&c->sink, unique_id, (struct cch_entry *)opaque);
- case CAP_SET:
- camu_sink_local_set(&c->sink, unique_id);
- al_log_info("cmv", "Now playing: %.*s.", AL_STR_PRINTF(unique_id));
- break;
- case CAP_SWAP:
- camu_sink_local_swap(&c->sink, unique_id);
- break;
- case CAP_UNLOAD:
- camu_sink_local_unload(&c->sink, unique_id);
- break;
- }
- return true;
-}
-*/
-
-#if CMV_USE_SOCKET
-static u8 line_callback(void *userdata, str *line)
-{
- struct cmv *c = (struct cmv *)userdata;
- if (al_str_eq(line, al_str_c(";NEXT"))) {
- cap_list_skip(&c->cap, default_list, 1);
- } else if (al_str_eq(line, al_str_c(";PREV"))) {
- cap_list_skip(&c->cap, default_list, -1);
- } else if (al_str_eq(line, al_str_c(";SHUFFLE"))) {
- cap_list_shuffle(&c->cap, default_list);
- } else {
- cap_list_add(&c->cap, default_list, line);
- }
- return AKI_LINE_PROCESSOR_CONTINUE;
-}
-#endif
-
-#if CMV_USE_TUI
-static void timer_callback(void *userdata, struct aki_timer *timer)
-{
- struct cmv *c = (struct cmv *)userdata;
- struct camu_sink_entry *entry = camu_sink_get_current(&c->sink);
- if (entry) {
- tui_draw(&c->tui, &((struct camu_sink_local *)entry)->runner, &entry->clock);
- } else {
- tui_draw(&c->tui, NULL, NULL);
- }
- camu_sink_return_current(&c->sink);
- aki_timer_again(timer);
-}
-
-static s32 log_callback(void *userdata, char *s)
-{
- struct cmv *c = (struct cmv *)userdata;
- tui_push_log_msg(&c->tui, s);
- return 0;
-}
-
-#ifdef HAVE_FFMPEG
-static void lav_log_callback(void *userdata, s32 level, const char *fmt, va_list args)
-{
- (void)userdata;
- if (level < AV_LOG_VERBOSE) al_logv("warn", "lav_internal", (char *)fmt, args);
-}
-#endif
-#endif
-
-static aki_thread_result AKI_THREADCALL event_loop_thread(void *userdata)
-{
- struct cmv *c = (struct cmv *)userdata;
- aki_event_loop_run(&c->loop);
- aki_event_loop_destroy(&c->loop);
- return 0;
-}
-
-static struct cmv c = { 0 };
-
-static void sigint_handler(s32 signum)
-{
- (void)signum;
- c.quit = 1;
-}
-
-s32 main(s32 argc, char *argv[])
-{
- if (!aki_common_init()) return EXIT_FAILURE;
-
- signal(SIGINT, sigint_handler);
-
- aki_event_loop_init(&c.loop);
-
-#if CMV_USE_TUI
- if (!tui_init(&c.tui, &c.loop)) {
- goto err;
- };
- al_set_print(log_callback, &c);
-#ifdef HAVE_FFMPEG
- camu_lav_set_log_callback(lav_log_callback);
-#endif
-#endif
-
- c.scr.callback = screen_callback;
- c.scr.userdata = &c;
- if (!camu_screen_init(&c.scr) || !camu_screen_create_window(&c.scr, "cmv")) {
- goto err;
- }
- c.renderer = camu_renderer_lp_create();
- //c.renderer = camu_renderer_tiger_create();
- if (!camu_screen_create_renderer(&c.scr, c.renderer)) {
- goto err;
- }
- c.renderer->render(c.renderer, &c.scr);
-
-#if CAP_USE_PYTHON
- bool py_init = argc == 1 ? sho_python_init() : false;
-#endif
-
- camu_mixer_init(&c.mixer, (struct camu_audio *)&audio_plugin_miniaudio);
- c.mixer.audio->configure_stream(c.mixer.audio, NULL);
-
- camu_sink_init(&c.sink, &c.loop, &c.mixer, c.renderer);
- c.sink.callback = sink_callback;
- c.sink.userdata = &c;
- camu_sink_connect(&c.sink, al_str_c("127.0.0.1"), TREE_PORT);
-
- /*
- cap_init(&c.cap, cap_callback, &c);
- cap_make_list(&c.cap, default_list);
- for (s32 i = 1; i < argc; i++) {
- cap_list_add(&c.cap, default_list, al_str_c(argv[i]));
- }
- */
-
-#if CMV_USE_SOCKET
- c.socket.type = AKI_SOCKET_UNIX;
- aki_socket_init(&c.socket);
- aki_socket_set_blocking(&c.socket, false);
- c.pro.callback = line_callback;
- c.pro.userdata = &c;
- aki_line_processor_init(&c.pro, al_str_c("\n"));
- aki_line_processor_open_socket(&c.pro, &c.socket);
- if (aki_socket_listen(&c.socket, al_str_c("/tmp/cmv_sock"), 0)) {
- aki_line_processor_run(&c.pro, &c.loop);
- }
-#endif
-
-#if CMV_USE_TUI
- aki_timer_init(&c.timer, &c.loop, timer_callback, &c);
- aki_timer_set_repeat(&c.timer, 0.05);
- aki_timer_again(&c.timer);
-#endif
-
- struct aki_thread thread0;
- aki_thread_create(&thread0, event_loop_thread, &c);
-
- c.quit = 0;
-
- while (!c.quit) {
- if (camu_screen_tick(&c.scr)) {
- c.renderer->render(c.renderer, &c.scr);
- }
- }
-
- camu_screen_set_state(&c.scr, CAMU_SCREEN_CLOSED);
-
- camu_sink_stop(&c.sink);
-
- aki_thread_join(&thread0);
-
- camu_mixer_close(&c.mixer);
- c.renderer->free(&c.renderer);
- camu_screen_close(&c.scr);
-
- //cap_close(&c.cap);
-
-#if CAP_USE_PYTHON
- if (py_init) sho_python_close();
-#endif
-
-#if CMV_USE_TUI
- tui_close(&c.tui);
-#endif
-
- aki_common_close();
-
- return EXIT_SUCCESS;
-err:
-#if CMV_USE_TUI
- tui_close(&c.tui);
-#endif
- aki_event_loop_destroy(&c.loop);
- aki_common_close();
- return EXIT_FAILURE;
-}
diff --git a/src/fruits/cmv/meson.build b/src/fruits/cmv/meson.build
deleted file mode 100644
index 1c9ed2d..0000000
--- a/src/fruits/cmv/meson.build
+++ /dev/null
@@ -1,10 +0,0 @@
-cmv_src = ['cmv2.c']
-cmv_deps = [common_deps, buffer, cache, av, screen, render, mixer, bimu, libsink, cap]
-
-use_tui = true
-if use_tui
- cmv_src += ['tui.c']
- cmv_deps += [dependency('notcurses')]
-endif
-
-executable('cmv', cmv_src, dependencies: cmv_deps)
diff --git a/src/fruits/cmv/tui.c b/src/fruits/cmv/tui.c
deleted file mode 100644
index 8315a13..0000000
--- a/src/fruits/cmv/tui.c
+++ /dev/null
@@ -1,165 +0,0 @@
-#include <aki/file.h>
-#include <al/log.h>
-#include <sys/ioctl.h>
-#include <notcurses/direct.h>
-
-#include "tui.h"
-
-static struct cmv_tui *tui_global;
-
-static void update_term_size(struct cmv_tui *tui)
-{
- struct winsize w;
- ioctl(tui->fd, TIOCGWINSZ, &w);
- tui->width = w.ws_col;
- tui->height = w.ws_row;
-}
-
-static void handle_winch(s32 sig)
-{
- (void)sig;
- struct cmv_tui *tui = tui_global;
- aki_mutex_lock(&tui->mutex);
- tui->update_size = true;
- aki_mutex_unlock(&tui->mutex);
-}
-
-static void input_poll_callback(void *userdata, s32 revents)
-{
- struct cmv_tui *tui = (struct cmv_tui *)userdata;
- (void)revents;
- struct ncinput input;
- u32 ret;
- while (1) {
- ret = ncdirect_get_nblock(tui->dir, &input);
- if (ret == (u32)-1 || ret == 0) break;
- if (input.evtype == NCTYPE_PRESS || input.evtype == NCTYPE_UNKNOWN) {
- }
- }
-}
-
-bool tui_init(struct cmv_tui *tui, struct aki_event_loop *loop)
-{
- tui->update_size = true;
- tui->width = 0;
- tui->height = 0;
- tui->prev_lines = 0;
-
- tui->fd = fileno(stdout);
- tui->out = fdopen(tui->fd, "w");
- if (!tui->out) return false;
- tui->buffer = al_malloc(256);
-
- //if (!(tui->dir = ncdirect_init(NULL, tui->out, 0))) {
- // fclose(tui->out);
- // return false;
- //}
-
- //aki_poll_init(&tui->poll, ncdirect_inputready_fd(tui->dir), AKI_POLL_READ, input_poll_callback, tui);
- //aki_poll_start(&tui->poll, loop);
-
- tui_global = tui;
- aki_mutex_init(&tui->mutex);
- signal(SIGWINCH, handle_winch);
-
- // Disable buffer.
- setbuf(tui->out, NULL);
-
- // Disable echo.
- tcgetattr(tui->fd, &tui->term);
- tui->term.c_lflag &= ~ECHO;
- tcsetattr(tui->fd, 0, &tui->term);
-
- al_queue_init(&tui->log_buffer, 256);
-
- return true;
-}
-
-void tui_push_log_msg(struct cmv_tui *tui, char *msg)
-{
- al_queue_push(&tui->log_buffer, msg);
-}
-
-static void draw_now_playing(struct cmv_tui *tui, struct bmu_local *runner, struct camu_clock *clock)
-{
- char *buffer = tui->buffer;
- f64 pts = camu_clock_get_pts(clock);
- f64 duration = bmu_local_get_duration(runner);
- s32 text = 0;
- s64 minute = (s64)(pts / 60L);
- s64 hour = minute / 60L;
- minute -= hour * 60L;
- text += al_sprintf(buffer + text, "[");
- if (hour > 0) text += al_sprintf(buffer + text, "%.2ld:", hour);
- text += al_sprintf(buffer + text, "%.2ld:%.2ld/", minute, (s64)pts % 60L);
- minute = (s64)(duration / 60L);
- hour = minute / 60L;
- minute -= hour * 60L;
- if (hour > 0) text += al_sprintf(buffer + text, "%.2ld:", hour);
- text += al_sprintf(buffer + text, "%.2ld:%.2ld", minute, (s64)duration % 60L);
- text += al_sprintf(buffer + text, "]");
- s32 parts = 0;
- if (pts > 0.0 && duration != 0.0) {
- if (pts > duration) pts = duration;
- f64 percent = pts / duration;
- parts = ((tui->width - text) * percent);
- } else if (duration == 0.0) {
- parts = (tui->width - text);
- }
- al_memset(buffer + text, '-', parts);
- buffer[text + parts] = '\0';
- fprintf(tui->out, "%s", buffer);
-}
-
-void tui_draw(struct cmv_tui *tui, struct bmu_local *runner, struct camu_clock *clock)
-{
- aki_mutex_lock(&tui->mutex);
- if (tui->update_size) {
- update_term_size(tui);
- tui->update_size = false;
- }
- aki_mutex_unlock(&tui->mutex);
-
- // Erase line.
- fprintf(tui->out, "\r\033[K");
- for (u32 i = 0; i < tui->prev_lines; i++) {
- // Up one, erase line.
- fprintf(tui->out, "\033[A\r\033[K");
- }
-
- char *msg;
- while (al_queue_pop(&tui->log_buffer, (void **)&msg)) {
- fprintf(tui->out, "%s\n", msg);
- al_free(msg);
- }
-
- // Simply printing each log message with a newline will leave
- // a one character high space in the bottom of the terminal window.
- // We use that to display a very basic status line (like mpv).
- // Trying to use more than that one line space without a more complete
- // terminal interface gets scuffed very fast.
-
- tui->prev_lines = 0;
-
- if (runner) {
- draw_now_playing(tui, runner, clock);
- }
-}
-
-void tui_close(struct cmv_tui *tui)
-{
- if (!tui->out) return;
- al_free(tui->buffer);
- char *msg;
- while (al_queue_pop(&tui->log_buffer, (void **)&msg)) {
- al_free(msg);
- }
- al_queue_free(&tui->log_buffer);
- aki_mutex_destroy(&tui->mutex);
- fprintf(tui->out, "\n");
- fflush(tui->out);
- tui->term.c_lflag |= ECHO;
- tcsetattr(tui->fd, 0, &tui->term);
- //ncdirect_stop(tui->dir);
- fclose(tui->out);
-}
diff --git a/src/fruits/cmv/tui.h b/src/fruits/cmv/tui.h
deleted file mode 100644
index 6898539..0000000
--- a/src/fruits/cmv/tui.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <al/queue.h>
-#include <aki/event_loop.h>
-#include <termios.h>
-
-#include "../../bimu/local.h"
-#include "../../buffer/video.h"
-
-struct cmv_tui {
- s32 fd;
- FILE *out;
- char *buffer;
- struct ncdirect *dir;
- struct aki_poll poll;
- struct aki_mutex mutex;
- struct termios term;
- bool update_size;
- u32 width;
- u32 height;
- u32 prev_lines;
- queue log_buffer;
-};
-
-bool tui_init(struct cmv_tui *tui, struct aki_event_loop *loop);
-void tui_push_log_msg(struct cmv_tui *tui, char *msg);
-void tui_draw(struct cmv_tui *tui, struct bmu_local *runner, struct camu_clock *clock);
-void tui_close(struct cmv_tui *tui);