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

This commit is contained in:
2026-04-15 09:39:59 +02:00
parent 373da4aa18
commit 298cde0779
3 changed files with 107 additions and 76 deletions

View File

@@ -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)

View File

@@ -17,21 +17,44 @@
#ifdef USE_PTHREADS
#include <pthread.h>
#include <semaphore.h>
#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 <unistd.h>
#endif
#include <assert.h>
#include <malloc.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <ao/ao.h>
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 <dlfcn.h>
#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);
}

View File

@@ -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);