From 298cde077929060ab36f58abeaefed63d8abbf1d Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Wed, 15 Apr 2026 09:39:59 +0200 Subject: [PATCH] moved ao library access to ao-play-async, because it only provides overhead and no benefits. All playing will be done via ao-play-async --- ao-play-async/CMakeLists.txt | 2 + ao-play-async/ao_playasync.c | 179 ++++++++++++++++++++--------------- ao-play-async/ao_playasync.h | 2 +- 3 files changed, 107 insertions(+), 76 deletions(-) diff --git a/ao-play-async/CMakeLists.txt b/ao-play-async/CMakeLists.txt index e20a189..b6d31e4 100644 --- a/ao-play-async/CMakeLists.txt +++ b/ao-play-async/CMakeLists.txt @@ -10,4 +10,6 @@ add_library(ao-play-async SHARED ao_playasync.h ) + +target_link_libraries(ao-play-async PRIVATE ao) target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY) diff --git a/ao-play-async/ao_playasync.c b/ao-play-async/ao_playasync.c index 93b0a45..5e6d5f0 100644 --- a/ao-play-async/ao_playasync.c +++ b/ao-play-async/ao_playasync.c @@ -17,21 +17,44 @@ #ifdef USE_PTHREADS #include #include + + #define TIME_NS_IN_MSEC 1000000ULL + static void makeSemTimeoutTime(struct timespec *ts, int ms) { + clock_gettime(CLOCK_REALTIME, ts); + ts->tv_sec += ms / 1000; + ts->tv_nsec += (ms % 1000) * TIME_NS_IN_MSEC; + if (ts->tv_nsec >= 1000000000L) { + ts->tv_sec++; + ts->tv_nsec = ts->tv_nsec - 1000000000L; + } + } + + static int _SEM_WAIT(sem_t *sem, int ms) + { + struct timespec ts; + makeSemTimeoutTime(&ts, ms); + int r = sem_timedwait(sem, &ts); + return (r == 0); + } + #define MUTEX_LOCK(m) pthread_mutex_lock(&m) #define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m) + #define SEM_WAIT(sem, ms) _SEM_WAIT(&sem, ms) + #define SEM_TRYWAIT(sem) (sem_trywait(&sem) == 0) + #define SEM_POST(sem) sem_post(&sem) #endif #ifndef WIN32 #include #endif -#include #include #include #include #include #include #include +#include typedef enum { PLAY = 1, @@ -39,8 +62,6 @@ typedef enum { } Command_t; -typedef void * ao_device; - typedef struct _queue_ { Command_t command; void *buf; @@ -69,42 +90,34 @@ typedef struct { #ifdef USE_PTHREADS pthread_mutex_t mutex; pthread_mutex_t pause_mutex; + pthread_mutex_t clear_mutex; pthread_t thread; - sem_t *queue_sem; + sem_t queue_sem; #endif double at_second; double music_duration; - ao_play_func_t ao_play_f; int buf_size; } AO_Handle; -//static int(*ao_play)(void *device, char *samples, uint32_t n) = NULL; - -static Queue_t *front(AO_Handle *h) +static Queue_t *get(AO_Handle *h, int ms_wait) { - assert(h->play_queue != NULL); - return h->play_queue; -} - -static Queue_t *get(AO_Handle *h) -{ -#ifdef USE_PTHREADS - sem_wait(h->queue_sem); -#endif -#ifdef USE_WINDOWS_THREADS -#endif - MUTEX_LOCK(h->mutex); - assert(h->play_queue != NULL); - Queue_t *q = h->play_queue; - h->play_queue = h->play_queue->next; - if (h->play_queue == NULL) { - h->last_frame = NULL; - } else { - h->play_queue->prev = NULL; + Queue_t *q = NULL; + int r = (ms_wait <= 0) ? SEM_TRYWAIT(h->queue_sem) : SEM_WAIT(h->queue_sem, ms_wait); + if (r) { + MUTEX_LOCK(h->mutex); + if (h->play_queue != NULL) { // Clear could have cleared the play_queue. + q = h->play_queue; + h->play_queue = h->play_queue->next; + if (h->play_queue == NULL) { + h->last_frame = NULL; + } else { + h->play_queue->prev = NULL; + } + h->buf_size -= q->buflen; + } + MUTEX_UNLOCK(h->mutex); } - h->buf_size -= q->buflen; - MUTEX_UNLOCK(h->mutex); return q; } @@ -123,11 +136,7 @@ static void add(AO_Handle *h, Queue_t *elem) h->last_frame = elem; } h->buf_size += elem->buflen; -#ifdef USE_PTHREADS - sem_post(h->queue_sem); -#endif -#ifdef USE_WINDOWS_THREADS -#endif + SEM_POST(h->queue_sem); MUTEX_UNLOCK(h->mutex); } @@ -162,31 +171,16 @@ static void del_elem(Queue_t *q) static void clear(AO_Handle *h) { -/* - MUTEX_LOCK(h->mutex); - while (h->play_queue != NULL) { - Queue_t *q = h->play_queue; - h->play_queue = h->play_queue->next; - del_elem(q); - if (h->play_queue == NULL) { - h->last_frame = NULL; - } else { - h->play_queue->prev = NULL; - } - } -#ifdef USE_PTHREADS - sem_destroy(h->queue_sem); - sem_init(h->queue_sem, 0, 0); -#endif - -#ifdef USE_WINDOWS_THREADS -#endif - MUTEX_UNLOCK(h->mutex); -*/ - while (h->play_queue != NULL) { - Queue_t *q = get(h); + MUTEX_LOCK(h->clear_mutex); + int count = 0; + Queue_t *q = get(h, 0); + while (q != NULL) { del_elem(q); + count += 1; + q = get(h, 0); } + fprintf(stderr, "%d elements cleared\n", count); + MUTEX_UNLOCK(h->clear_mutex); } #ifdef USE_PTHREADS @@ -197,26 +191,26 @@ static DWORD run(LPVOID arg) #endif { AO_Handle *handle = (AO_Handle *) arg; - int go_on = (1 == 1); while(go_on) { MUTEX_LOCK(handle->pause_mutex); MUTEX_UNLOCK(handle->pause_mutex); + MUTEX_LOCK(handle->clear_mutex); + Queue_t *q = get(handle, 250); + MUTEX_UNLOCK(handle->clear_mutex); + if (q != NULL) { + handle->at_second = q->at_second; + handle->music_duration = q->music_duration; - Queue_t *q = get(handle); + if (q->command == STOP) { + go_on = (1 == 0); + } else { + ao_play(handle->ao_device, (char *) q->buf, q->buflen); + } - handle->at_second = q->at_second; - handle->music_duration = q->music_duration; - - if (q->command == STOP) { - go_on = (1 == 0); - } else { - //fprintf(stderr, "playing buf at %lf\n", handle->at_second); - handle->ao_play_f(handle->ao_device, (char *) q->buf, q->buflen); + del_elem(q); } - - del_elem(q); } #ifdef USE_PTHREADS @@ -232,18 +226,49 @@ int ao_async_version() return VERSION; } -void *ao_create_async(void *ao_device_yeah, void *ao_play_f) +#ifdef _WIN32 +#else +#include +#endif + +static void at_exit_shutdown_ao() { - //if (ao_play == NULL) { get_ao_play(); } + ao_shutdown(); +} + +static void init_ao() +{ + static int init = 0; + if (!init) { + ao_initialize(); + atexit(at_exit_shutdown_ao); + } +} + +void *ao_create_async(int bits, int rate, int channels, int byte_format) +{ + init_ao(); AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle)); - handle->ao_device = (ao_device *) ao_device_yeah; + ao_sample_format fmt; + fmt.bits = bits; + fmt.rate = rate; + fmt.byte_format = byte_format; + fmt.channels = channels; + fmt.matrix = NULL; + + ao_device *dev = ao_open_live(ao_default_driver_id(), &fmt, NULL); + if (dev == NULL) { + fprintf(stderr, "Cannot open ao-device, error code = %d\n", errno); + return NULL; + } + + handle->ao_device = dev; handle->play_queue = NULL; handle->last_frame = NULL; handle->at_second = -1; - handle->ao_play_f = (ao_play_func_t) ao_play_f; handle->buf_size = 0; handle->paused = (1 == 0); @@ -251,11 +276,12 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f) #ifdef USE_PTHREADS pthread_mutex_t p = PTHREAD_MUTEX_INITIALIZER; handle->pause_mutex = p; + pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER; + handle->clear_mutex = c; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; handle->mutex = m; + sem_init(&handle->queue_sem, 0, 0); pthread_create(&handle->thread, NULL, run, handle); - handle->queue_sem = (sem_t *) malloc(sizeof(sem_t)); - sem_init(handle->queue_sem, 0, 0); #endif #ifdef USE_WINDOWS_THREADS @@ -270,6 +296,7 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f) #endif MUTEX_UNLOCK(handle->pause_mutex); + MUTEX_UNLOCK(handle->clear_mutex); return (void *) handle; } @@ -277,6 +304,7 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f) void ao_stop_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; + fprintf(stderr, "stopping ao_async\n"); clear(h); Queue_t *q = new_elem(STOP, 0.0, 0.0, 0, NULL); @@ -291,6 +319,7 @@ void ao_stop_async(void *ao_handle) CloseHandle(h->thread); CloseHandle(h->mutex); #endif + ao_close(h->ao_device); free(h); } diff --git a/ao-play-async/ao_playasync.h b/ao-play-async/ao_playasync.h index 872b7a6..6a04ff1 100644 --- a/ao-play-async/ao_playasync.h +++ b/ao-play-async/ao_playasync.h @@ -29,7 +29,7 @@ typedef struct { } BufferInfo_t; AOPLAYASYNC_EXPORT int ao_async_version(void); -AOPLAYASYNC_EXPORT void *ao_create_async(void *ao_handle, void *ao_play_f); +AOPLAYASYNC_EXPORT void *ao_create_async(int bits, int rate, int channels, int byte_format); AOPLAYASYNC_EXPORT void ao_stop_async(void *handle); AOPLAYASYNC_EXPORT void ao_play_async(void *handle, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info); AOPLAYASYNC_EXPORT void ao_clear_async(void *handle);