Mercurial > repos > blastem
changeset 2640:c30e5548154f
Get sync to audio working in emscripten
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 26 Feb 2025 22:55:42 -0800 |
parents | 0046305e3fa8 |
children | 8d016949c29b |
files | blastem.c render.h render_sdl.c |
diffstat | 3 files changed, 115 insertions(+), 61 deletions(-) [+] |
line wrap: on
line diff
--- a/blastem.c Wed Feb 26 20:46:00 2025 -0800 +++ b/blastem.c Wed Feb 26 22:55:42 2025 -0800 @@ -32,6 +32,7 @@ #endif #ifdef __EMSCRIPTEN__ #include <emscripten.h> +#include "render_audio.h" #endif #include "version.inc" @@ -142,8 +143,90 @@ } } +static uint8_t menu; +static uint8_t use_nuklear; +#ifdef __EMSCRIPTEN__ +void handle_frame_presented(void) +{ + if (current_system) { + current_system->request_exit(current_system); + } +} + +void browser_main_loop(void) +{ + static uint8_t system_started; +#ifndef DISABLE_NUKLEAR + static uint8_t was_menu; + if (use_nuklear) { + if (menu && !was_menu) { + ui_enter(); + } else if (!menu && was_menu) { + ui_exit(); + } + if (menu) { + render_update_display(); + } + } +#endif + if (!current_system && game_system) { + current_system = game_system; + menu = 0; +#ifndef DISABLE_NUKLEAR + was_menu = 0; + ui_exit(); +#endif + } + if (current_system) { + if (system_started && render_is_audio_sync()) { + if (all_sources_ready()) { + return; + } + } + if (current_system->next_rom) { + char *next_rom = current_system->next_rom; + current_system->next_rom = NULL; + init_system_with_media(next_rom, 0); + system_started = 0; + menu = 0; + current_system = game_system; + } else if (!menu) { + if (system_started) { + current_system->resume_context(current_system); + } else { + system_started = 1; + current_system->start_context(current_system, NULL); + } + if (current_system->force_release) { + menu = 1; + } + } + } + +} + +void setup_main_loop(void) +{ + //can't use render_is_audio_sync since we haven't called render_init/render_config_updated yet + char *sync = tern_find_path_default(config, "system\0sync_source\0", (tern_val){.ptrval = "audio"}, TVAL_PTR).ptrval; + emscripten_cancel_main_loop(); + if (!strcmp("video", sync)) { + render_set_audio_full_fun(NULL); + render_set_frame_presented_fun(handle_frame_presented); + emscripten_set_main_loop(browser_main_loop, 0, 0); + } else { + render_set_frame_presented_fun(NULL); + render_set_audio_full_fun(handle_frame_presented); + emscripten_set_main_loop(browser_main_loop, 1, 0); //dummy fps value, will be overridden by a call to emscripten_set_main_loop_timing + } +} +#endif + void apply_updated_config(void) { +#ifdef __EMSCRIPTEN__ + setup_main_loop(); +#endif render_config_updated(); set_bindings(); update_pad_bindings(); @@ -274,64 +357,6 @@ update_title(game_system->info.name); } -static uint8_t menu; -static uint8_t use_nuklear; -#ifdef __EMSCRIPTEN__ -void handle_frame_presented(void) -{ - if (current_system) { - current_system->request_exit(current_system); - } -} - -void browser_main_loop(void) -{ - static uint8_t system_started; -#ifndef DISABLE_NUKLEAR - static uint8_t was_menu; - if (use_nuklear) { - if (menu && !was_menu) { - ui_enter(); - } else if (!menu && was_menu) { - ui_exit(); - } - if (menu) { - render_update_display(); - } - } -#endif - if (!current_system && game_system) { - current_system = game_system; - menu = 0; -#ifndef DISABLE_NUKLEAR - was_menu = 0; - ui_exit(); -#endif - } - if (current_system) { - if (current_system->next_rom) { - char *next_rom = current_system->next_rom; - current_system->next_rom = NULL; - init_system_with_media(next_rom, 0); - system_started = 0; - menu = 0; - current_system = game_system; - } else if (!menu) { - if (system_started) { - current_system->resume_context(current_system); - } else { - system_started = 1; - current_system->start_context(current_system, NULL); - } - if (current_system->force_release) { - menu = 1; - } - } - } - -} -#endif - char *parse_addr_port(char *arg) { while (*arg && *arg != ':') { @@ -550,10 +575,8 @@ fullscreen = !fullscreen; } #ifdef __EMSCRIPTEN__ - config = tern_insert_path(config, "system\0sync_source\0", (tern_val){.ptrval = strdup("video")}, TVAL_PTR); config = tern_insert_path(config, "ui\0initial_path\0", (tern_val){.ptrval = strdup("/roms")}, TVAL_PTR); - render_set_frame_presented_fun(handle_frame_presented); - emscripten_set_main_loop(browser_main_loop, 0, 0); + setup_main_loop(); #endif if (!headless) { if (reader_addr) {
--- a/render.h Wed Feb 26 20:46:00 2025 -0800 +++ b/render.h Wed Feb 26 22:55:42 2025 -0800 @@ -143,6 +143,7 @@ void render_set_ui_render_fun(ui_render_fun); void render_set_ui_fb_resize_handler(ui_render_fun resize); void render_set_frame_presented_fun(ui_render_fun); +void render_set_audio_full_fun(ui_render_fun); void render_video_loop(void); uint8_t render_should_release_on_exit(void); void render_set_external_sync(uint8_t ext_sync_on);
--- a/render_sdl.c Wed Feb 26 20:46:00 2025 -0800 +++ b/render_sdl.c Wed Feb 26 22:55:42 2025 -0800 @@ -26,6 +26,9 @@ #include <GL/glew.h> #endif #endif +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif #define MAX_EVENT_POLL_PER_FRAME 2 @@ -123,12 +126,20 @@ { SDL_LockMutex(audio_mutex); uint8_t all_ready; +#ifdef __EMSCRIPTEN__ + if (!all_sources_ready()) { + memset(byte_stream, 0, len); + SDL_UnlockMutex(audio_mutex); + return; + } +#else do { all_ready = all_sources_ready(); if (!quitting && !all_ready) { SDL_CondWait(audio_ready, audio_mutex); } } while(!quitting && !all_ready); +#endif if (!quitting) { mix_and_convert(byte_stream, len, NULL); } @@ -255,6 +266,12 @@ uint8_t audio_deadlock_hack(void); +static ui_render_fun audio_full_cb; +void render_set_audio_full_fun(ui_render_fun cb) +{ + audio_full_cb = cb; +} + void render_do_audio_ready(audio_source *src) { if (sync_src == SYNC_AUDIO_THREAD) { @@ -268,7 +285,9 @@ system_request_exit(current_system, 0); } } else if (sync_src == SYNC_AUDIO) { + uint8_t all_ready = 0; SDL_LockMutex(audio_mutex); +#ifndef __EMSCRIPTEN__ if (src->front_populated) { if (audio_deadlock_hack()) { SDL_CondSignal(audio_ready); @@ -277,13 +296,18 @@ while (src->front_populated) { SDL_CondWait(src->opaque, audio_mutex); } +#endif int16_t *tmp = src->front; src->front = src->back; src->back = tmp; src->front_populated = 1; src->buffer_pos = 0; + all_ready = all_sources_ready(); SDL_CondSignal(audio_ready); SDL_UnlockMutex(audio_mutex); + if (all_ready && audio_full_cb) { + audio_full_cb(); + } } else { uint32_t num_buffered; SDL_LockAudio(); @@ -1070,6 +1094,12 @@ debug_message("unsupported format %X\n", actual.format); warning("Unsupported audio sample format: %X\n", actual.format); } +#ifdef __EMSCRIPTEN__ + if (sync_src == SYNC_AUDIO) { + printf("emscripten_set_main_loop_timing %d\n", actual.samples * 500 / actual.freq); + emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, actual.samples * 500 / actual.freq); + } +#endif render_audio_initialized(format, actual.freq, actual.channels, actual.samples, SDL_AUDIO_BITSIZE(actual.format) / 8); }