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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user