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
|
ao_playasync.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
target_link_libraries(ao-play-async PRIVATE ao)
|
||||||
target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY)
|
target_compile_definitions(ao-play-async PRIVATE AOPLAYASYNC_LIBRARY)
|
||||||
|
|||||||
@@ -17,21 +17,44 @@
|
|||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <semaphore.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_LOCK(m) pthread_mutex_lock(&m)
|
||||||
#define MUTEX_UNLOCK(m) pthread_mutex_unlock(&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
|
#endif
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <ao/ao.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PLAY = 1,
|
PLAY = 1,
|
||||||
@@ -39,8 +62,6 @@ typedef enum {
|
|||||||
} Command_t;
|
} Command_t;
|
||||||
|
|
||||||
|
|
||||||
typedef void * ao_device;
|
|
||||||
|
|
||||||
typedef struct _queue_ {
|
typedef struct _queue_ {
|
||||||
Command_t command;
|
Command_t command;
|
||||||
void *buf;
|
void *buf;
|
||||||
@@ -69,42 +90,34 @@ typedef struct {
|
|||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_mutex_t pause_mutex;
|
pthread_mutex_t pause_mutex;
|
||||||
|
pthread_mutex_t clear_mutex;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
sem_t *queue_sem;
|
sem_t queue_sem;
|
||||||
#endif
|
#endif
|
||||||
double at_second;
|
double at_second;
|
||||||
double music_duration;
|
double music_duration;
|
||||||
ao_play_func_t ao_play_f;
|
|
||||||
int buf_size;
|
int buf_size;
|
||||||
} AO_Handle;
|
} AO_Handle;
|
||||||
|
|
||||||
//static int(*ao_play)(void *device, char *samples, uint32_t n) = NULL;
|
|
||||||
|
|
||||||
|
static Queue_t *get(AO_Handle *h, int ms_wait)
|
||||||
static Queue_t *front(AO_Handle *h)
|
|
||||||
{
|
{
|
||||||
assert(h->play_queue != NULL);
|
Queue_t *q = NULL;
|
||||||
return h->play_queue;
|
int r = (ms_wait <= 0) ? SEM_TRYWAIT(h->queue_sem) : SEM_WAIT(h->queue_sem, ms_wait);
|
||||||
}
|
if (r) {
|
||||||
|
MUTEX_LOCK(h->mutex);
|
||||||
static Queue_t *get(AO_Handle *h)
|
if (h->play_queue != NULL) { // Clear could have cleared the play_queue.
|
||||||
{
|
q = h->play_queue;
|
||||||
#ifdef USE_PTHREADS
|
h->play_queue = h->play_queue->next;
|
||||||
sem_wait(h->queue_sem);
|
if (h->play_queue == NULL) {
|
||||||
#endif
|
h->last_frame = NULL;
|
||||||
#ifdef USE_WINDOWS_THREADS
|
} else {
|
||||||
#endif
|
h->play_queue->prev = NULL;
|
||||||
MUTEX_LOCK(h->mutex);
|
}
|
||||||
assert(h->play_queue != NULL);
|
h->buf_size -= q->buflen;
|
||||||
Queue_t *q = h->play_queue;
|
}
|
||||||
h->play_queue = h->play_queue->next;
|
MUTEX_UNLOCK(h->mutex);
|
||||||
if (h->play_queue == NULL) {
|
|
||||||
h->last_frame = NULL;
|
|
||||||
} else {
|
|
||||||
h->play_queue->prev = NULL;
|
|
||||||
}
|
}
|
||||||
h->buf_size -= q->buflen;
|
|
||||||
MUTEX_UNLOCK(h->mutex);
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,11 +136,7 @@ static void add(AO_Handle *h, Queue_t *elem)
|
|||||||
h->last_frame = elem;
|
h->last_frame = elem;
|
||||||
}
|
}
|
||||||
h->buf_size += elem->buflen;
|
h->buf_size += elem->buflen;
|
||||||
#ifdef USE_PTHREADS
|
SEM_POST(h->queue_sem);
|
||||||
sem_post(h->queue_sem);
|
|
||||||
#endif
|
|
||||||
#ifdef USE_WINDOWS_THREADS
|
|
||||||
#endif
|
|
||||||
MUTEX_UNLOCK(h->mutex);
|
MUTEX_UNLOCK(h->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,31 +171,16 @@ static void del_elem(Queue_t *q)
|
|||||||
|
|
||||||
static void clear(AO_Handle *h)
|
static void clear(AO_Handle *h)
|
||||||
{
|
{
|
||||||
/*
|
MUTEX_LOCK(h->clear_mutex);
|
||||||
MUTEX_LOCK(h->mutex);
|
int count = 0;
|
||||||
while (h->play_queue != NULL) {
|
Queue_t *q = get(h, 0);
|
||||||
Queue_t *q = h->play_queue;
|
while (q != NULL) {
|
||||||
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);
|
|
||||||
del_elem(q);
|
del_elem(q);
|
||||||
|
count += 1;
|
||||||
|
q = get(h, 0);
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "%d elements cleared\n", count);
|
||||||
|
MUTEX_UNLOCK(h->clear_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
@@ -197,26 +191,26 @@ static DWORD run(LPVOID arg)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
AO_Handle *handle = (AO_Handle *) arg;
|
AO_Handle *handle = (AO_Handle *) arg;
|
||||||
|
|
||||||
int go_on = (1 == 1);
|
int go_on = (1 == 1);
|
||||||
|
|
||||||
while(go_on) {
|
while(go_on) {
|
||||||
MUTEX_LOCK(handle->pause_mutex);
|
MUTEX_LOCK(handle->pause_mutex);
|
||||||
MUTEX_UNLOCK(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;
|
del_elem(q);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
@@ -232,18 +226,49 @@ int ao_async_version()
|
|||||||
return 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));
|
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->play_queue = NULL;
|
||||||
handle->last_frame = NULL;
|
handle->last_frame = NULL;
|
||||||
handle->at_second = -1;
|
handle->at_second = -1;
|
||||||
|
|
||||||
handle->ao_play_f = (ao_play_func_t) ao_play_f;
|
|
||||||
handle->buf_size = 0;
|
handle->buf_size = 0;
|
||||||
|
|
||||||
handle->paused = (1 == 0);
|
handle->paused = (1 == 0);
|
||||||
@@ -251,11 +276,12 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f)
|
|||||||
#ifdef USE_PTHREADS
|
#ifdef USE_PTHREADS
|
||||||
pthread_mutex_t p = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t p = PTHREAD_MUTEX_INITIALIZER;
|
||||||
handle->pause_mutex = p;
|
handle->pause_mutex = p;
|
||||||
|
pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
handle->clear_mutex = c;
|
||||||
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
|
||||||
handle->mutex = m;
|
handle->mutex = m;
|
||||||
|
sem_init(&handle->queue_sem, 0, 0);
|
||||||
pthread_create(&handle->thread, NULL, run, handle);
|
pthread_create(&handle->thread, NULL, run, handle);
|
||||||
handle->queue_sem = (sem_t *) malloc(sizeof(sem_t));
|
|
||||||
sem_init(handle->queue_sem, 0, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_THREADS
|
#ifdef USE_WINDOWS_THREADS
|
||||||
@@ -270,6 +296,7 @@ void *ao_create_async(void *ao_device_yeah, void *ao_play_f)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MUTEX_UNLOCK(handle->pause_mutex);
|
MUTEX_UNLOCK(handle->pause_mutex);
|
||||||
|
MUTEX_UNLOCK(handle->clear_mutex);
|
||||||
|
|
||||||
return (void *) handle;
|
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)
|
void ao_stop_async(void *ao_handle)
|
||||||
{
|
{
|
||||||
AO_Handle *h = (AO_Handle *) ao_handle;
|
AO_Handle *h = (AO_Handle *) ao_handle;
|
||||||
|
fprintf(stderr, "stopping ao_async\n");
|
||||||
|
|
||||||
clear(h);
|
clear(h);
|
||||||
Queue_t *q = new_elem(STOP, 0.0, 0.0, 0, NULL);
|
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->thread);
|
||||||
CloseHandle(h->mutex);
|
CloseHandle(h->mutex);
|
||||||
#endif
|
#endif
|
||||||
|
ao_close(h->ao_device);
|
||||||
free(h);
|
free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ typedef struct {
|
|||||||
} BufferInfo_t;
|
} BufferInfo_t;
|
||||||
|
|
||||||
AOPLAYASYNC_EXPORT int ao_async_version(void);
|
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_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_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);
|
AOPLAYASYNC_EXPORT void ao_clear_async(void *handle);
|
||||||
|
|||||||
Reference in New Issue
Block a user