#include "ao_playasync.h" #include #include #include #include #include //#include #include #include #include typedef enum { PLAY = 1, STOP = 2 } Command_t; typedef void * ao_device; typedef struct _queue_ { Command_t command; void *buf; int buflen; double at_second; struct _queue_ *next; struct _queue_ *prev; } Queue_t; typedef struct { Queue_t *play_queue; Queue_t *last_frame; ao_device *ao_device; pthread_mutex_t mutex; pthread_t thread; double at_second; 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) { assert(h->play_queue != NULL); return h->play_queue; } static Queue_t *get(AO_Handle *h) { 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; } h->buf_size -= q->buflen; return q; } static void add(AO_Handle *h, Queue_t *elem) { if (h->last_frame == NULL) { h->play_queue = elem; elem->next = NULL; elem->prev = NULL; h->last_frame = h->play_queue; } else { h->last_frame->next = elem; elem->prev = h->last_frame; elem->next = NULL; h->last_frame = elem; } h->buf_size += elem->buflen; } static Queue_t *new_elem(int command, double at_second, int buf_len, void *buf) { Queue_t *q = (Queue_t *) malloc(sizeof(Queue_t)); void *new_buf; if (buf_len != 0) { new_buf = (void *) malloc(buf_len); memcpy(new_buf, buf, buf_len); } else { new_buf = NULL; } q->at_second = at_second; q->buf = new_buf; q->buflen = buf_len; q->command = command; q->next = NULL; q->prev = NULL; return q; } static void del_elem(Queue_t *q) { if (q->buflen != 0) { free(q->buf); } free(q); } static void clear(AO_Handle *h) { while (h->play_queue != NULL) { Queue_t *q = get(h); del_elem(q); } } static void *run(void *arg) { AO_Handle *handle = (AO_Handle *) arg; int go_on = (1 == 1); while(go_on) { pthread_mutex_lock(&handle->mutex); int has_frames = (handle->play_queue != NULL); if (has_frames) { Queue_t *q = get(handle); handle->at_second = q->at_second; pthread_mutex_unlock(&handle->mutex); if (q->command == STOP) { go_on = (1 == 0); } else { handle->ao_play_f(handle->ao_device, q->buf, q->buflen); } del_elem(q); } else { pthread_mutex_unlock(&handle->mutex); usleep(5000); // sleep for 5ms } } return NULL; } /* static void get_ao_play(void) { char *lib = "libao.so"; void *handle = dlopen(lib, RTLD_LAZY); if (!handle) { fprintf(stderr, "Cannot open library %s: %s\n", lib, dlerror()); exit(EXIT_FAILURE); } ao_play = dlsym(handle, "ao_play"); char *err; err = dlerror(); if (err != NULL) { fprintf(stderr, "Cannot get function ao_play: %s\n", err); exit(EXIT_FAILURE); } } */ void *ao_create_async(void *ao_device_yeah, void *ao_play_f) { //if (ao_play == NULL) { get_ao_play(); } AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle)); handle->ao_device = (ao_device *) ao_device_yeah; handle->play_queue = NULL; handle->last_frame = NULL; handle->at_second = -1; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; handle->mutex = m; handle->ao_play_f = ao_play_f; handle->buf_size = 0; pthread_create(&handle->thread, NULL, run, handle); return (void *) handle; } void ao_stop_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; pthread_mutex_lock(&h->mutex); clear(h); Queue_t *q = new_elem(STOP, 0.0, 0, NULL); add(h, q); pthread_mutex_unlock(&h->mutex); void *retval; pthread_join(h->thread, &retval); free(h); } void ao_play_async(void *ao_handle, double at_second, int buf_size, void *mem) { AO_Handle *h = (AO_Handle *) ao_handle; Queue_t *q = new_elem(PLAY, at_second, buf_size, mem); pthread_mutex_lock(&h->mutex); add(h, q); pthread_mutex_unlock(&h->mutex); } double ao_is_at_second_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; pthread_mutex_lock(&h->mutex); double s = h->at_second; pthread_mutex_unlock(&h->mutex); return s; } int ao_bufsize_async(void *ao_handle) { AO_Handle *h = (AO_Handle *) ao_handle; pthread_mutex_lock(&h->mutex); int s = h->buf_size; pthread_mutex_unlock(&h->mutex); return s; }