diff options
Diffstat (limited to 'src/libsink')
| -rw-r--r-- | src/libsink/desktop.c | 265 | ||||
| -rw-r--r-- | src/libsink/desktop.h | 26 | ||||
| -rw-r--r-- | src/libsink/input_simulator.c | 68 | ||||
| -rw-r--r-- | src/libsink/input_simulator.h | 10 | ||||
| -rw-r--r-- | src/libsink/meson.build | 5 |
5 files changed, 374 insertions, 0 deletions
diff --git a/src/libsink/desktop.c b/src/libsink/desktop.c new file mode 100644 index 0000000..2bbe906 --- /dev/null +++ b/src/libsink/desktop.c @@ -0,0 +1,265 @@ +#define AL_LOG_SECTION "desktop" +#include <al/log.h> + +//#define DESKTOP_NULL_AUDIO + +#ifdef DESKTOP_NULL_AUDIO +#include "../mixer/audio_null.h" +#else +#include "../mixer/audio_miniaudio.h" +#endif +#if defined CAMU_RENDERER_TIGER +#include "../render/renderer_tiger.h" +#elif defined CAMU_RENDERER_LIBPLACEBO +#include "../render/renderer_libplacebo.h" +#endif +#include "../util/print_time.h" + +#include "desktop.h" +#ifdef CAMU_SCREEN_DEBUG_KEY +#include "input_simulator.h" +#endif + +static u8 sink_callback(void *userdata, u8 op, u8 type, void *opaque) +{ + struct camu_desktop *c = (struct camu_desktop *)userdata; + struct camu_mixer *mixer = &c->mixer; + struct camu_screen *scr = &c->scr; + 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(mixer, buf); + log_debug("Audio buffer added."); + break; + } + case CAMU_SINK_VIDEO: { + struct camu_video_buffer *buf = (struct camu_video_buffer *)opaque; + camu_screen_add_buffer(scr, buf); + log_debug("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(mixer, buf); + log_debug("Audio buffer removed."); + break; + } + case CAMU_SINK_VIDEO: { + struct camu_video_buffer *buf = (struct camu_video_buffer *)opaque; + camu_screen_remove_buffer(scr, buf); + log_debug("Video buffer removed."); + break; + } + } + break; + case CAMU_SINK_START: + switch (type) { + case CAMU_SINK_AUDIO: + camu_mixer_resume(mixer); + log_info("Audio started."); + break; + case CAMU_SINK_VIDEO: + camu_screen_set_state(scr, CAMU_SCREEN_PLAYING); + camu_screen_wake(scr); + log_info("Video started."); + break; + } + break; + case CAMU_SINK_STOP: + switch (type) { + case CAMU_SINK_AUDIO: + camu_mixer_pause(mixer); + log_info("Audio stopped."); + break; + case CAMU_SINK_VIDEO: + camu_screen_set_state(scr, CAMU_SCREEN_PAUSED); + log_info("Video stopped."); + break; + } + break; + case CAMU_SINK_REFRESH_VIDEO: + camu_screen_force_refresh(scr); + break; + case CAMU_SINK_CLEAR: + switch (type) { + case CAMU_SINK_AUDIO: + camu_mixer_clear(mixer); + break; + case CAMU_SINK_VIDEO: + camu_screen_clear(scr); + break; + } + break; + case CAMU_SINK_MOCK_CLOSE: + c->should_quit = 1; + camu_screen_wake(&c->scr); + break; + case CAMU_SINK_EXIT: + camu_sink_close(&c->sink); + if (c->exit_callback) { + c->exit_callback(c->userdata, c); + } + break; + } + return CAMU_SINK_OK; +} + +static char status[64]; +static void log_playback_pos(struct camu_sink *sink) +{ + struct camu_sink_entry *current = camu_sink_get_current(sink); + if (!current) { + camu_sink_return_current(sink); + goto notplaying; + } + + u64 pts = camu_clock_get_last_pts(¤t->clock) * 1000000u; + u64 duration = current->client.duration; + pts = MIN(duration, pts); + bool paused = current->paused; + + camu_sink_return_current(sink); + + u64 remaining = duration - pts; + if (remaining == 0) { + goto notplaying; + } + + bool show_hour = duration > 60u * 60u * 1000000u; + s32 offset = al_snprintf(status, sizeof(status), paused ? "⏸ " : "⏵ "); + offset += al_snprintf(status + offset, sizeof(status) - offset, "["); + offset += camu_print_time(status + offset, sizeof(status) - offset, pts, show_hour, 2); + offset += al_snprintf(status + offset, sizeof(status) - offset, "/"); + offset += camu_print_time(status + offset, sizeof(status) - offset, duration, show_hour, 2); + offset += al_snprintf(status + offset, sizeof(status) - offset, "]"); + status[offset] = '\0'; + + log_info("%s", status); + return; +notplaying: + log_info("Not playing."); +} + +static void screen_callback(void *userdata, u8 op, void *opaque) +{ + struct camu_desktop *c = (struct camu_desktop *)userdata; + switch (op) { + case CAMU_SCREEN_SET_VOLUME: + camu_mixer_set_volume(&c->mixer, *(f32 *)opaque); + break; + case CAMU_SCREEN_OFFSET_VOLUME: + camu_mixer_offset_volume(&c->mixer, *(f32 *)opaque); + break; + case CAMU_SCREEN_SKIP: + camu_sink_skip(&c->sink, *(s32 *)opaque); + break; + case CAMU_SCREEN_TOGGLE_PAUSE: + camu_sink_toggle_pause(&c->sink); + break; + case CAMU_SCREEN_PERCENT_SEEK: + camu_sink_seek(&c->sink, opaque, CAMU_SEEK_PERCENT); + break; + case CAMU_SCREEN_RELATIVE_SEEK: + camu_sink_seek(&c->sink, opaque, CAMU_SEEK_RELATIVE); + break; + case CAMU_SCREEN_RESEEK: + camu_sink_reseek(&c->sink); + break; + case CAMU_SCREEN_SHUFFLE: + camu_sink_shuffle(&c->sink); + break; + case CAMU_SCREEN_STATUS: + log_playback_pos(&c->sink); + break; +#ifdef CAMU_SCREEN_DEBUG_KEY + case CAMU_SCREEN_DEBUG: + if (camu_input_simulator_running()) { + camu_input_simulator_stop(); + } else { + camu_input_simulator_run(&c->sink); + } + break; +#endif + case CAMU_SCREEN_CLOSE: + c->should_quit = 1; + break; + } +} + +bool camu_desktop_open(struct camu_desktop *c, const char *window_name) +{ + c->scr.callback = screen_callback; + c->scr.userdata = c; + if (!camu_screen_init(&c->scr) || !camu_screen_create_window(&c->scr, window_name)) { + return false; + } +#if defined CAMU_RENDERER_TIGER + c->renderer = camu_renderer_tiger_create(); +#elif defined CAMU_RENDERER_LIBPLACEBO + c->renderer = camu_renderer_lp_create(); +#endif + if (!camu_screen_create_renderer(&c->scr, c->renderer)) { + return false; + } + c->renderer->render(c->renderer, &c->scr, true); +#ifdef DESKTOP_NULL_AUDIO + if (!camu_mixer_init(&c->mixer, (struct camu_audio *)&audio_plugin_null)) { +#else + if (!camu_mixer_init(&c->mixer, camu_audio_miniaudio_create())) { +#endif + return false; + } + if (!c->mixer.audio->configure_stream(c->mixer.audio, NULL)) { + return false; + } + camu_mixer_pick_format(&c->mixer, &c->mixer.fmt); + c->should_quit = 0; + c->exit_callback = NULL; + c->userdata = NULL; + return true; +} + +bool camu_desktop_connect(struct camu_desktop *c, str *name, struct nn_event_loop *loop, u8 type, str *addr, u16 port) +{ + c->loop = loop; + camu_sink_init(&c->sink, c->loop, &c->mixer, c->renderer); + al_str_from(&c->sink.default_list, "default"); + c->sink.callback = sink_callback; + c->sink.userdata = c; + return camu_sink_connect(&c->sink, name, type, addr, port); +} + +bool camu_desktop_tick(struct camu_desktop *c) +{ + bool force; + if (!c->should_quit && camu_screen_tick(&c->scr, &force)) { + c->renderer->render(c->renderer, &c->scr, force); + } + return !c->should_quit; +} + +void camu_desktop_stop(struct camu_desktop *c) +{ +#ifdef CAMU_SCREEN_DEBUG_KEY + if (camu_input_simulator_running()) { + camu_input_simulator_stop(); + } +#endif + // We have already stopped ticking the screen at this point. + camu_screen_clear(&c->scr); + camu_sink_stop(&c->sink); +} + +void camu_desktop_free(struct camu_desktop *c) +{ + camu_sink_free(&c->sink); + camu_mixer_close(&c->mixer); + c->renderer->free(&c->renderer); + camu_screen_close(&c->scr); +} diff --git a/src/libsink/desktop.h b/src/libsink/desktop.h new file mode 100644 index 0000000..279fd7b --- /dev/null +++ b/src/libsink/desktop.h @@ -0,0 +1,26 @@ +#pragma once + +#include <al/types.h> +#include <al/str.h> +#include <nnwt/event_loop.h> + +#include "../libsink/sink.h" + +#include "../screen/screen.h" + +struct camu_desktop { + struct nn_event_loop *loop; + s32 should_quit; + struct camu_screen scr; + struct camu_renderer *renderer; + struct camu_mixer mixer; + struct camu_sink sink; + void (*exit_callback)(void *, struct camu_desktop *); + void *userdata; +}; + +bool camu_desktop_open(struct camu_desktop *c, const char *window_name); +bool camu_desktop_connect(struct camu_desktop *c, str *name, struct nn_event_loop *loop, u8 type, str *addr, u16 port); +bool camu_desktop_tick(struct camu_desktop *c); +void camu_desktop_stop(struct camu_desktop *c); +void camu_desktop_free(struct camu_desktop *c); diff --git a/src/libsink/input_simulator.c b/src/libsink/input_simulator.c new file mode 100644 index 0000000..80fde02 --- /dev/null +++ b/src/libsink/input_simulator.c @@ -0,0 +1,68 @@ +#include "../screen/screen.h" +#ifdef CAMU_SCREEN_DEBUG_KEY +#include <nnwt/thread.h> +#include <al/random.h> + +#include "input_simulator.h" + +// This is ignoring all thread-safety. +static s32 quit = 1; +static struct nn_thread thread; + +enum { + SEEK, + SKIP, + BACKSKIP, + TOGGLE_PAUSE, + SHUFFLE, + MARK, // count +}; + +static nn_thread_result NNWT_THREADCALL input_simulation_thread(void *userdata) +{ + struct camu_sink *sink = (struct camu_sink *)userdata; + while (!quit) { + nn_thread_sleep(NNWT_TS_FROM_USEC(30000)); + switch (al_rand() % MARK) { + case SKIP: + camu_sink_skip(sink, (al_rand() % 5)); + break; + case BACKSKIP: + camu_sink_skip(sink, -(al_rand() % 5)); + break; + case SHUFFLE: + camu_sink_shuffle(sink); + break; + case TOGGLE_PAUSE: + camu_sink_toggle_pause(sink); + break; + case SEEK: { + f64 pos = al_rand() / (f64)AL_RAND_MAX; + if (pos < 0.005) pos = 0.0; + if (pos > 0.995) pos = 1.0; + else if (pos > 0.99) pos = .9999; + camu_sink_seek(sink, &pos, CAMU_SEEK_PERCENT); + break; + } + } + } + return 0; +} + +void camu_input_simulator_run(struct camu_sink *sink) +{ + quit = 0; + nn_thread_create(&thread, input_simulation_thread, sink); +} + +bool camu_input_simulator_running(void) +{ + return quit == 0; +} + +void camu_input_simulator_stop(void) +{ + quit = 1; + nn_thread_join(&thread); +} +#endif diff --git a/src/libsink/input_simulator.h b/src/libsink/input_simulator.h new file mode 100644 index 0000000..e05b03e --- /dev/null +++ b/src/libsink/input_simulator.h @@ -0,0 +1,10 @@ +#pragma once + +#include "../screen/screen.h" +#ifdef CAMU_SCREEN_DEBUG_KEY +#include "../libsink/sink.h" + +void camu_input_simulator_run(struct camu_sink *sink); +bool camu_input_simulator_running(void); +void camu_input_simulator_stop(void); +#endif diff --git a/src/libsink/meson.build b/src/libsink/meson.build index a0805af..153e371 100644 --- a/src/libsink/meson.build +++ b/src/libsink/meson.build @@ -9,3 +9,8 @@ else endif libsink = declare_dependency(sources: libsink_src, dependencies: libsink_deps, compile_args: libsink_args) + +desktop_src = ['desktop.c', 'input_simulator.c'] +desktop_deps = [libsink] +desktop_args = ['-DCAMU_MIXER_THREADED', '-DCAMU_SCREEN_THREADED'] +desktop = declare_dependency(sources: desktop_src, dependencies: desktop_deps, compile_args: desktop_args) |