From e9cfa67901523228a49c2fa57ed22cd03eeb4bc3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 21 Apr 2025 00:48:45 +0900 Subject: [PATCH] do lock --- engine/gf_audio.c | 92 ++++++++++++++++++++++++++-------- engine/include/gf_audio.h | 24 +++++++-- engine/include/gf_type/audio.h | 12 ++++- 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/engine/gf_audio.c b/engine/gf_audio.c index 972fccd..7e99805 100644 --- a/engine/gf_audio.c +++ b/engine/gf_audio.c @@ -21,18 +21,20 @@ const char* gf_audio_mod_sig[] = {"M!K!", "M.K.", "FLT4", "FLT8", "4CHN", "6CHN", "8CHN", "10CH", "12CH", "14CH", "16CH", "18CH", "20CH", "22CH", "24CH", "26CH", "28CH", "30CH", "32CH"}; void gf_audio_callback(ma_device* dev, void* output, const void* input, ma_uint32 frame) { - int i; - gf_audio_t* audio = dev->pUserData; - ma_int16* out = (ma_int16*)output; - float* tmp = malloc(sizeof(*tmp) * frame * 2); + gf_audio_id_t i; + gf_audio_t* audio = dev->pUserData; + ma_int16* out = (ma_int16*)output; + float* tmp = malloc(sizeof(*tmp) * frame * 2); + int unlocked = 0; for(i = 0; i < frame; i++) { tmp[2 * i + 0] = 0; tmp[2 * i + 1] = 0; } + ma_mutex_lock(audio->mutex); for(i = 0; i < GF_AUDIO_MAX_DECODERS; i++) { - if(audio->decoder[i].used && audio->decoder[i].decoder != NULL) { + if(audio->decoder[i].used == 1 && audio->decoder[i].decoder != NULL) { ma_uint64 readframe; int j; ma_int16* r = malloc(sizeof(*r) * frame * 2); @@ -43,9 +45,11 @@ void gf_audio_callback(ma_device* dev, void* output, const void* input, ma_uint3 } free(r); if(frame > readframe) { + ma_mutex_unlock(audio->mutex); + unlocked = 1; gf_audio_decoder_destroy(&audio->decoder[i]); } - } else if(audio->decoder[i].used && audio->decoder[i].xm != NULL) { + } else if(audio->decoder[i].used == 1 && audio->decoder[i].xm != NULL) { int j; int gotframe; float* r = malloc(sizeof(*r) * frame * 2); @@ -58,9 +62,11 @@ void gf_audio_callback(ma_device* dev, void* output, const void* input, ma_uint3 free(r); audio->decoder[i].samples -= frame; if(audio->decoder[i].samples <= 0) { + ma_mutex_unlock(audio->mutex); + unlocked = 1; gf_audio_decoder_destroy(&audio->decoder[i]); } - } else if(audio->decoder[i].used && audio->decoder[i].mod != NULL) { + } else if(audio->decoder[i].used == 1 && audio->decoder[i].mod != NULL) { int j; int gotframe; ma_int16* r = malloc(sizeof(*r) * frame * 2); @@ -73,10 +79,13 @@ void gf_audio_callback(ma_device* dev, void* output, const void* input, ma_uint3 free(r); audio->decoder[i].samples -= frame; if(audio->decoder[i].samples <= 0) { + ma_mutex_unlock(audio->mutex); + unlocked = 1; gf_audio_decoder_destroy(&audio->decoder[i]); } } } + if(!unlocked) ma_mutex_unlock(audio->mutex); for(i = 0; i < frame; i++) { out[2 * i + 0] = tmp[2 * i + 0] * 32768; @@ -85,8 +94,9 @@ void gf_audio_callback(ma_device* dev, void* output, const void* input, ma_uint3 free(tmp); } -int gf_audio_load(gf_audio_t* audio, const void* data, size_t size) { - int i; +gf_audio_id_t gf_audio_load(gf_audio_t* audio, const void* data, size_t size) { + gf_audio_id_t i; + ma_mutex_lock(audio->mutex); for(i = 0; i < GF_AUDIO_MAX_DECODERS; i++) { if(audio->decoder[i].used == 0) { int xm_cond = size > 37 && memcmp(data, "Extended Module: ", 17) == 0 && ((char*)data)[37] == 0x1a; @@ -104,8 +114,9 @@ int gf_audio_load(gf_audio_t* audio, const void* data, size_t size) { if(xm_cond) { if(jar_xm_create_context_safe(&audio->decoder[i].xm, data, size, audio->device_config.sampleRate) == 0) { audio->decoder[i].samples = jar_xm_get_remaining_samples(audio->decoder[i].xm); - audio->decoder[i].used = 1; - return 0; + audio->decoder[i].used = -1; + ma_mutex_unlock(audio->mutex); + return i; } audio->decoder[i].xm = NULL; } else if(mod_cond) { @@ -114,30 +125,34 @@ int gf_audio_load(gf_audio_t* audio, const void* data, size_t size) { jar_mod_setcfg(audio->decoder[i].mod, audio->device_config.sampleRate, 16, 1, 0, 0); if(jar_mod_load(audio->decoder[i].mod, (void*)data, size)) { audio->decoder[i].samples = jar_mod_max_samples(audio->decoder[i].mod); - audio->decoder[i].used = 1; - return 0; + audio->decoder[i].used = -1; + ma_mutex_unlock(audio->mutex); + return i; } free(audio->decoder[i].mod); audio->decoder[i].mod = NULL; } audio->decoder[i].decoder = malloc(sizeof(*audio->decoder[i].decoder)); if(ma_decoder_init_memory(data, size, &audio->decoder[i].decoder_config, audio->decoder[i].decoder) == MA_SUCCESS) { - audio->decoder[i].used = 1; - return 0; + audio->decoder[i].used = -1; + ma_mutex_unlock(audio->mutex); + return i; } free(audio->decoder[i].decoder); audio->decoder[i].decoder = NULL; + ma_mutex_unlock(audio->mutex); return -1; } } + ma_mutex_unlock(audio->mutex); return -1; } -int gf_audio_load_file(gf_audio_t* audio, const char* path) { +gf_audio_id_t gf_audio_load_file(gf_audio_t* audio, const char* path) { FILE* f = fopen(path, "rb"); size_t sz; unsigned char* data; - int st; + gf_audio_id_t st; if(f == NULL) return -1; fseek(f, 0, SEEK_END); sz = ftell(f); @@ -153,8 +168,9 @@ int gf_audio_load_file(gf_audio_t* audio, const char* path) { } gf_audio_t* gf_audio_create(gf_engine_t* engine) { - gf_audio_t* audio = malloc(sizeof(*audio)); - int i; + gf_audio_t* audio = malloc(sizeof(*audio)); + int i; + gf_audio_id_t id; memset(audio, 0, sizeof(*audio)); audio->engine = engine; @@ -162,20 +178,19 @@ gf_audio_t* gf_audio_create(gf_engine_t* engine) { audio->device_config = ma_device_config_init(ma_device_type_playback); audio->device_config.playback.format = ma_format_s16; audio->device_config.playback.channels = 2; - audio->device_config.sampleRate = 48000; + audio->device_config.sampleRate = 44100; audio->device_config.dataCallback = gf_audio_callback; audio->device_config.pUserData = audio; for(i = 0; i < GF_AUDIO_MAX_DECODERS; i++) { audio->decoder[i].used = 0; + audio->decoder[i].audio = NULL; audio->decoder[i].decoder = NULL; audio->decoder[i].xm = NULL; audio->decoder[i].mod = NULL; audio->decoder[i].decoder_config = ma_decoder_config_init(audio->device_config.playback.format, audio->device_config.playback.channels, audio->device_config.sampleRate); } - gf_audio_load_file(audio, "test.xm"); - audio->device = malloc(sizeof(*audio->device)); if(ma_device_init(NULL, &audio->device_config, audio->device) != MA_SUCCESS) { gf_log_function(engine, "Failed to open playback device", ""); @@ -185,18 +200,34 @@ gf_audio_t* gf_audio_create(gf_engine_t* engine) { return NULL; } + audio->mutex = malloc(sizeof(*audio->mutex)); + if(ma_mutex_init(audio->mutex) != MA_SUCCESS) { + gf_log_function(engine, "Failed to create mutex", ""); + free(audio->mutex); + audio->mutex = NULL; + gf_audio_destroy(audio); + return NULL; + } + if(ma_device_start(audio->device) != MA_SUCCESS) { gf_log_function(engine, "Failed to start playback device", ""); gf_audio_destroy(audio); return NULL; } + for(i = 0; i < GF_AUDIO_MAX_DECODERS; i++) { + audio->decoder[i].audio = audio; + } + gf_log_function(engine, "Audio interface started", ""); + gf_audio_resume(audio, (id = gf_audio_load_file(audio, "test.xm"))); + return audio; } void gf_audio_decoder_destroy(gf_audio_decoder_t* decoder) { + ma_mutex_lock(decoder->audio->mutex); if(decoder->decoder != NULL) { ma_decoder_uninit(decoder->decoder); free(decoder->decoder); @@ -212,6 +243,7 @@ void gf_audio_decoder_destroy(gf_audio_decoder_t* decoder) { decoder->mod = NULL; } decoder->used = 0; + ma_mutex_unlock(decoder->audio->mutex); } void gf_audio_destroy(gf_audio_t* audio) { @@ -220,9 +252,25 @@ void gf_audio_destroy(gf_audio_t* audio) { ma_device_uninit(audio->device); free(audio->device); } + if(audio->mutex != NULL) { + ma_mutex_uninit(audio->mutex); + free(audio->mutex); + } for(i = 0; i < GF_AUDIO_MAX_DECODERS; i++) { gf_audio_decoder_destroy(&audio->decoder[i]); } gf_log_function(audio->engine, "Destroyed audio interface", ""); free(audio); } + +void gf_audio_resume(gf_audio_t* audio, gf_audio_id_t id) { + ma_mutex_lock(audio->mutex); + if(audio->decoder[id].used != 0) audio->decoder[id].used = 1; + ma_mutex_unlock(audio->mutex); +} + +void gf_audio_pause(gf_audio_t* audio, gf_audio_id_t id) { + ma_mutex_lock(audio->mutex); + if(audio->decoder[id].used != 0) audio->decoder[id].used = -1; + ma_mutex_unlock(audio->mutex); +} diff --git a/engine/include/gf_audio.h b/engine/include/gf_audio.h index 05c76bf..84da10d 100644 --- a/engine/include/gf_audio.h +++ b/engine/include/gf_audio.h @@ -46,9 +46,9 @@ GF_EXPORT void gf_audio_decoder_destroy(gf_audio_decoder_t* decoder); * @brief Load and play file * @param audio Audio interface * @param path Path - * @return `0` if successful, otherwise `-1` + * @return ID if successful, otherwise `-1` */ -int gf_audio_load_file(gf_audio_t* audio, const char* path); +GF_EXPORT gf_audio_id_t gf_audio_load_file(gf_audio_t* audio, const char* path); /** * @~english @@ -56,8 +56,24 @@ int gf_audio_load_file(gf_audio_t* audio, const char* path); * @param audio Audio interface * @param data Data * @param size Data size - * @return `0` if successful, otherwise `-1` + * @return ID if successful, otherwise `-1` */ -int gf_audio_load(gf_audio_t* audio, const void* data, size_t size); +GF_EXPORT gf_audio_id_t gf_audio_load(gf_audio_t* audio, const void* data, size_t size); + +/** + * @~english + * @brief Pause audio + * @param audio Audio interface + * @param id Audio ID + */ +GF_EXPORT void gf_audio_pause(gf_audio_t* audio, gf_audio_id_t id); + +/** + * @~english + * @brief Resume audio + * @param audio Audio interface + * @param id Audio ID + */ +GF_EXPORT void gf_audio_resume(gf_audio_t* audio, gf_audio_id_t id); #endif diff --git a/engine/include/gf_type/audio.h b/engine/include/gf_type/audio.h index dfd3edf..f23810c 100644 --- a/engine/include/gf_type/audio.h +++ b/engine/include/gf_type/audio.h @@ -10,6 +10,8 @@ #include #include +typedef int gf_audio_id_t; + #ifdef GF_EXPOSE_AUDIO typedef struct gf_audio_t gf_audio_t; typedef struct gf_audio_decoder_t gf_audio_decoder_t; @@ -35,6 +37,9 @@ typedef struct gf_audio_decoder_t gf_audio_decoder_t; * @~english * @brief Audio decoder * + * @var gf_audio_decoder_t::audio + * @brief Audio interface + * * @var gf_audio_decoder_t::decoder_config * @brief miniaudio decoder config * @@ -51,9 +56,10 @@ typedef struct gf_audio_decoder_t gf_audio_decoder_t; * @brief Remaining samples * * @var gf_audio_decoder_t::used - * @brief `1` if used, otherwise `0` + * @brief `1` if used, `-1` if used but paused, otherwise `0` */ GF_DECLARE_TYPE(audio_decoder, { + gf_audio_t* audio; ma_decoder_config decoder_config; ma_decoder* decoder; jar_xm_context_t* xm; @@ -78,12 +84,16 @@ GF_DECLARE_TYPE(audio_decoder, { * * @var gf_audio_t::decoder * @brief Decoder + * + * @var gf_audio_t::mutex + * @brief Mutex */ GF_DECLARE_TYPE(audio, { gf_engine_t* engine; ma_device_config device_config; ma_device* device; gf_audio_decoder_t decoder[GF_AUDIO_MAX_DECODERS]; + ma_mutex* mutex; }); #else typedef void gf_audio_decoder_t;