Bug hunting ao_playasync

This commit is contained in:
2026-05-07 08:32:41 +02:00
parent a358a8593d
commit 977eb5a456
5 changed files with 206 additions and 75 deletions
+206 -75
View File
@@ -1,17 +1,23 @@
#include "ao_playasync.h" #include "ao_playasync.h"
#include "../ffi_version.h" #include "../ffi_version.h"
#ifdef WIN32 #define TRUE (1==1)
#define FALSE (1==0)
#if defined(_WIN32) || defined(WIN32)
#define AO_ASYNC_WINDOWS
#include <windows.h> #include <windows.h>
#define USE_WINDOWS_THREADS #define USE_WINDOWS_THREADS
#define sleep_ms(ms) Sleep(ms) #define sleep_ms(ms) Sleep(ms)
#else #else
#ifdef __APPLE__ #ifdef __APPLE__
#define AO_ASYNC_APPLE
#define USE_DISPATCH #define USE_DISPATCH
#include <time.h> #include <time.h>
#define sleep_ms(ms) msleep(ms) #define sleep_ms(ms) msleep(ms)
#else #else
#define USE_PTHREADS #define USE_PTHREADS
#include <time.h>
#include <sched.h> #include <sched.h>
#define sleep_ms(ms) usleep(ms * 1000) #define sleep_ms(ms) usleep(ms * 1000)
#endif #endif
@@ -61,6 +67,7 @@
#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_WAIT(sem, ms) _SEM_WAIT(sem, ms)
#define SEM_TRYWAIT(sem) (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0) #define SEM_TRYWAIT(sem) (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0)
#define SEM_WAIT_INFINITE(sem) (dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER) == 0)
#define SEM_POST(sem) dispatch_semaphore_signal(sem) #define SEM_POST(sem) dispatch_semaphore_signal(sem)
#define YIELD() sleep_ms(5) #define YIELD() sleep_ms(5)
#endif #endif
@@ -70,6 +77,7 @@
#define MUTEX_UNLOCK(m) ReleaseMutex(m) #define MUTEX_UNLOCK(m) ReleaseMutex(m)
#define SEM_WAIT(sem, ms) (WaitForSingleObject(sem, ms) == WAIT_OBJECT_0) #define SEM_WAIT(sem, ms) (WaitForSingleObject(sem, ms) == WAIT_OBJECT_0)
#define SEM_TRYWAIT(sem) (WaitForSingleObject(sem, 0) == WAIT_OBJECT_0) #define SEM_TRYWAIT(sem) (WaitForSingleObject(sem, 0) == WAIT_OBJECT_0)
#define SEM_WAIT_INFINITE(sem) (WaitForSingleObject(sem, INFINITE) == WAIT_OBJECT_0)
#define SEM_POST(sem) ReleaseSemaphore(sem, 1, NULL) #define SEM_POST(sem) ReleaseSemaphore(sem, 1, NULL)
#define YIELD() sleep_ms(5) #define YIELD() sleep_ms(5)
#endif #endif
@@ -100,24 +108,25 @@
#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_WAIT(sem, ms) _SEM_WAIT(&sem, ms)
#define SEM_WAIT_INFINITE(sem) (sem_wait(&sem) == 0)
#define SEM_TRYWAIT(sem) (sem_trywait(&sem) == 0) #define SEM_TRYWAIT(sem) (sem_trywait(&sem) == 0)
#define SEM_POST(sem) sem_post(&sem) #define SEM_POST(sem) sem_post(&sem)
#define YIELD() yield() #define YIELD() yield()
#endif #endif
#ifndef WIN32 #ifndef AO_ASYNC_WINDOWS
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifndef __APPLE__ #ifndef AO_ASYNC_APPLE
#include <malloc.h> #include <malloc.h>
#endif #endif
#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 <ao/ao.h> #include <ao/ao.h>
#include <errno.h>
typedef enum { typedef enum {
PLAY = 1, PLAY = 1,
@@ -143,6 +152,7 @@ typedef struct {
Queue_t *last_frame; Queue_t *last_frame;
int paused; int paused;
int stopped;
ao_device *ao_device; ao_device *ao_device;
int requested_bits_per_sample; int requested_bits_per_sample;
@@ -153,31 +163,41 @@ typedef struct {
#ifdef USE_WINDOWS_THREADS #ifdef USE_WINDOWS_THREADS
HANDLE mutex; HANDLE mutex;
HANDLE pause_mutex;
HANDLE clear_mutex; HANDLE clear_mutex;
HANDLE thread; HANDLE thread;
DWORD thread_id; DWORD thread_id;
HANDLE queue_sem; HANDLE queue_sem;
HANDLE pause_sem;
#endif #endif
#if defined(USE_PTHREADS) || defined(USE_DISPATCH) #if defined(USE_PTHREADS) || defined(USE_DISPATCH)
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_mutex_t pause_mutex;
pthread_mutex_t clear_mutex; pthread_mutex_t clear_mutex;
pthread_t thread; pthread_t thread;
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
sem_t queue_sem; sem_t queue_sem;
sem_t pause_sem;
#endif #endif
#ifdef USE_DISPATCH #ifdef USE_DISPATCH
dispatch_semaphore_t queue_sem; dispatch_semaphore_t queue_sem;
dispatch_semaphore_t pause_sem;
#endif #endif
#endif #endif
double at_second; double at_second;
double music_duration; double music_duration;
int at_music_id; int at_music_id;
int buf_size; int buf_size;
int volume_in_10000; // volume in 100000 steps, i.e. 100000 equals 100% int volume_in_10000; // volume in 10000 steps, i.e. 10000 equals 100%
} AO_Handle; } AO_Handle;
static inline int stopped(AO_Handle *h, int lock_mutex)
{
if (lock_mutex) MUTEX_LOCK(h->mutex);
int stopped = h->stopped;
if (lock_mutex) MUTEX_UNLOCK(h->mutex);
return stopped;
}
static void del_elem(Queue_t *q);
static Queue_t *get(AO_Handle *h, int ms_wait) static Queue_t *get(AO_Handle *h, int ms_wait)
{ {
@@ -205,9 +225,20 @@ static Queue_t *get(AO_Handle *h, int ms_wait)
return q; return q;
} }
static void add(AO_Handle *h, Queue_t *elem) static void add(AO_Handle *h, Queue_t *elem, int in_clear)
{ {
if (!in_clear) {
MUTEX_LOCK(h->clear_mutex);
}
MUTEX_LOCK(h->mutex); MUTEX_LOCK(h->mutex);
if (!in_clear && stopped(h, FALSE)) {
MUTEX_UNLOCK(h->mutex);
MUTEX_UNLOCK(h->clear_mutex);
del_elem(elem);
return;
}
if (h->last_frame == NULL) { if (h->last_frame == NULL) {
h->play_queue = elem; h->play_queue = elem;
elem->next = NULL; elem->next = NULL;
@@ -221,17 +252,34 @@ static void add(AO_Handle *h, Queue_t *elem)
} }
h->buf_size += elem->buflen; h->buf_size += elem->buflen;
SEM_POST(h->queue_sem); SEM_POST(h->queue_sem);
MUTEX_UNLOCK(h->mutex); MUTEX_UNLOCK(h->mutex);
if (!in_clear) {
MUTEX_UNLOCK(h->clear_mutex);
}
} }
static Queue_t *new_elem(int command, int music_id, double at_second, double music_duration, int buf_len, void *buf) static Queue_t *new_elem(int command, int music_id, double at_second, double music_duration, int buf_len, void *buf)
{ {
Queue_t *q = (Queue_t *) malloc(sizeof(Queue_t)); Queue_t *q = (Queue_t *) malloc(sizeof(Queue_t));
if (q == NULL) {
fprintf(stderr, "new_elem: Cannot allocate Queue Element!\n");
return NULL;
}
void *new_buf; void *new_buf;
if (buf_len != 0) { if (buf_len > 0) {
new_buf = (void *) malloc(buf_len); new_buf = (void *) malloc(buf_len);
if (new_buf != NULL) {
memcpy(new_buf, buf, buf_len); memcpy(new_buf, buf, buf_len);
} else {
fprintf(stderr, "new_elem: Cannot allocate memory of size %d\n", buf_len);
buf_len = 0;
free(q);
return NULL;
}
} else { } else {
new_buf = NULL; new_buf = NULL;
} }
@@ -254,7 +302,7 @@ static void del_elem(Queue_t *q)
free(q); free(q);
} }
static void clear(AO_Handle *h) static void clear(AO_Handle *h, int do_stop)
{ {
//fprintf(stderr, "Wait for clear mutex\n"); //fprintf(stderr, "Wait for clear mutex\n");
MUTEX_LOCK(h->clear_mutex); MUTEX_LOCK(h->clear_mutex);
@@ -267,6 +315,16 @@ static void clear(AO_Handle *h)
q = get(h, 0); q = get(h, 0);
} }
fprintf(stderr, "%d elements cleared\n", count); fprintf(stderr, "%d elements cleared\n", count);
if (do_stop) {
Queue_t *q = new_elem(STOP, 0, 0.0, 0.0, 0, NULL);
if (q == NULL) {
fprintf(stderr, "Unexpected! Cannot allocate STOP element, aborting\n");
abort();
}
add(h, q, TRUE);
}
MUTEX_UNLOCK(h->clear_mutex); MUTEX_UNLOCK(h->clear_mutex);
} }
@@ -276,6 +334,7 @@ static int inline littleEndian()
return (*(char *)&n) == 1; return (*(char *)&n) == 1;
} }
/*
static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int volume_in_10000) static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int volume_in_10000)
{ {
int bytes_per_sample = (handle->dev_bits_per_sample >> 3); int bytes_per_sample = (handle->dev_bits_per_sample >> 3);
@@ -318,6 +377,59 @@ static void inline adjustVolume(AO_Handle *handle, char *_buf, int buf_size, int
} }
} }
} }
*/
static inline int32_t read_sample(unsigned char *mem, int req_bytes, int little_endian)
{
uint32_t v = 0;
for (int i = 0; i < req_bytes; i++) {
int idx = little_endian ? i : (req_bytes - i - 1);
v |= ((uint32_t) mem[idx]) << (8 * i);
}
if (req_bytes < 4) {
int bits = req_bytes * 8;
uint32_t sign = 1u << (bits - 1);
v = (v ^ sign) - sign;
}
return (int32_t) v;
}
static inline void store_sample(unsigned char *dst, int32_t in_sample, int out_bytes, int is_little_endian)
{
uint32_t sample = (uint32_t) in_sample;
for (int i = 0; i < out_bytes; i++) {
int idx = is_little_endian ? i : (out_bytes - i - 1);
dst[idx] = sample & 0xff;
sample >>= 8;
}
}
static inline void adjustVolume(AO_Handle *handle,
char *_buf,
int buf_size,
int volume_in_10000)
{
int bytes_per_sample = handle->dev_bits_per_sample >> 3;
int endianess = handle->dev_endianess;
int little_endian = (endianess == AO_FMT_LITTLE);
if (!little_endian && endianess == AO_FMT_NATIVE) {
little_endian = littleEndian();
}
unsigned char *buf = (unsigned char *) _buf;
for (int i = 0; i + bytes_per_sample <= buf_size; i += bytes_per_sample) {
int32_t sample = read_sample(buf + i, bytes_per_sample, little_endian);
int64_t scaled = ((int64_t) sample * volume_in_10000) / 10000;
store_sample(buf + i, (int32_t) scaled, bytes_per_sample, little_endian);
}
}
#if defined(USE_PTHREADS) || defined(USE_DISPATCH) #if defined(USE_PTHREADS) || defined(USE_DISPATCH)
static void *run(void *arg) static void *run(void *arg)
@@ -330,25 +442,36 @@ static DWORD run(LPVOID arg)
int go_on = (1 == 1); int go_on = (1 == 1);
while(go_on) { while(go_on) {
MUTEX_LOCK(handle->pause_mutex); SEM_WAIT_INFINITE(handle->pause_sem);
MUTEX_UNLOCK(handle->pause_mutex); SEM_POST(handle->pause_sem);
MUTEX_LOCK(handle->clear_mutex); MUTEX_LOCK(handle->clear_mutex);
Queue_t *q = get(handle, 250); Queue_t *q = get(handle, 250);
MUTEX_UNLOCK(handle->clear_mutex); MUTEX_UNLOCK(handle->clear_mutex);
if (q != NULL) { if (q != NULL) {
MUTEX_LOCK(handle->mutex);
handle->at_second = q->at_second; handle->at_second = q->at_second;
handle->music_duration = q->music_duration; handle->music_duration = q->music_duration;
handle->at_music_id = q->music_id; handle->at_music_id = q->music_id;
int volume = handle->volume_in_10000;
MUTEX_UNLOCK(handle->mutex);
if (handle->volume_in_10000 != 10000) { if (volume != 10000 && q->command == PLAY) {
// adjust volume // adjust volume
adjustVolume(handle, q->buf, q->buflen, handle->volume_in_10000); adjustVolume(handle, q->buf, q->buflen, volume);
} }
if (q->command == STOP) { if (q->command == STOP) {
go_on = (1 == 0); go_on = FALSE;
} else { } else {
ao_play(handle->ao_device, (char *) q->buf, q->buflen); if (!ao_play(handle->ao_device, (char *) q->buf, q->buflen)) {
fprintf(stderr, "Unexpected, ao_play returns 0 --> ao device must be closed\n");
fprintf(stderr, "Stopping play loop\n");
go_on = FALSE;
MUTEX_LOCK(handle->mutex);
handle->stopped = TRUE;
MUTEX_UNLOCK(handle->mutex);
}
} }
del_elem(q); del_elem(q);
@@ -370,12 +493,12 @@ int ao_async_version()
return ffi_version(); return ffi_version();
} }
#ifdef _WIN32 #ifdef AO_ASYNC_WINDOWS
#else #else
#include <dlfcn.h> #include <dlfcn.h>
#endif #endif
#ifdef _WIN32 #ifdef AO_ASYNC_WINDOWS
static void at_exit_shutdown_ao(void) static void at_exit_shutdown_ao(void)
#else #else
static void at_exit_shutdown_ao() static void at_exit_shutdown_ao()
@@ -434,6 +557,7 @@ static ao_device *try_open_device(int bits, int rate, int channels, int byte_for
} }
/*
static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits) static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits)
{ {
if (req_bits > out_bits) { if (req_bits > out_bits) {
@@ -443,41 +567,36 @@ static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits)
} }
return sample; return sample;
} }
*/
static inline int32_t read_sample(unsigned char *mem, int req_bytes, int little_endian) static inline int32_t convert_bits(int32_t sample, int req_bits, int out_bits)
{ {
uint32_t v = 0; if (req_bits == out_bits) return sample;
for (int i = 0; i < req_bytes; i++) { int shift = req_bits > out_bits
int idx = little_endian ? i : (req_bytes - i - 1); ? req_bits - out_bits
v |= ((uint32_t) mem[idx]) << (8 * i); : out_bits - req_bits;
if (req_bits > out_bits) {
return sample / (1 << shift);
} else {
return (int32_t)((int64_t)sample * ((int64_t)1 << shift));
}
} }
if (req_bytes < 4) {
int bits = req_bytes * 8;
uint32_t sign = 1u << (bits - 1);
v = (v ^ sign) - sign;
}
return (int32_t) v;
}
static inline void store_sample(unsigned char *dst, int32_t sample, int out_bytes, int is_little_endian)
{
for (int i = 0; i < out_bytes; i++) {
int idx = is_little_endian ? i : (out_bytes - i - 1);
dst[idx] = sample & 0xff;
sample >>= 8;
}
}
static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferInfo_t *info, int *out_size) static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferInfo_t *info, int *out_size)
{ {
if (mem_size <= 0) {
*out_size = 0;
return NULL;
}
int endianess = h->dev_endianess; int endianess = h->dev_endianess;
int little_endian = (endianess == AO_FMT_LITTLE); int little_endian = (endianess == AO_FMT_LITTLE);
if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian(); if (!little_endian && endianess == AO_FMT_NATIVE) little_endian = littleEndian();
int requested_bits = h->requested_bits_per_sample; int requested_bits = info->sample_bits; // h->requested_bits_per_sample;
int output_bits = h->dev_bits_per_sample; int output_bits = h->dev_bits_per_sample;
int req_bytes = (requested_bits / 8); int req_bytes = (requested_bits / 8);
@@ -485,7 +604,7 @@ static void *convert_req_to_real(AO_Handle *h, void *mem, int mem_size, BufferIn
int samples = (mem_size / req_bytes); int samples = (mem_size / req_bytes);
unsigned char *buf_out = (unsigned char *) malloc(samples * out_bytes); unsigned char *buf_out = (unsigned char *) malloc((samples + 1) * out_bytes);
if (buf_out == NULL) { if (buf_out == NULL) {
fprintf(stderr, "Allocation of output buffer of %d samples of %d bits gives NULL", samples, output_bits); fprintf(stderr, "Allocation of output buffer of %d samples of %d bits gives NULL", samples, output_bits);
*out_size = 0; *out_size = 0;
@@ -520,13 +639,10 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format, const c
init_ao(); init_ao();
AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle)); AO_Handle *handle = (AO_Handle *) malloc(sizeof(AO_Handle));
if (handle == NULL) {
ao_sample_format fmt; fprintf(stderr, "Cannot allocate ao_handle!\n");
fmt.bits = bits; return NULL;
fmt.rate = rate; }
fmt.byte_format = byte_format;
fmt.channels = channels;
fmt.matrix = NULL;
int opened_bits = 0; int opened_bits = 0;
ao_device *dev = try_open_device(bits, rate, channels, byte_format, wav_file_output, &opened_bits); ao_device *dev = try_open_device(bits, rate, channels, byte_format, wav_file_output, &opened_bits);
@@ -549,23 +665,23 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format, const c
handle->last_frame = NULL; handle->last_frame = NULL;
handle->at_second = -1; handle->at_second = -1;
handle->at_music_id = -1; handle->at_music_id = -1;
handle->music_duration = 0;
handle->buf_size = 0; handle->buf_size = 0;
handle->paused = (1 == 0); handle->paused = FALSE;
handle->stopped = FALSE;
#if defined(USE_PTHREADS) || defined(USE_DISPATCH) #if defined(USE_PTHREADS) || defined(USE_DISPATCH)
pthread_mutex_t p = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init(&handle->clear_mutex, NULL);
handle->pause_mutex = p; pthread_mutex_init(&handle->mutex, NULL);
pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER;
handle->clear_mutex = c;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
handle->mutex = m;
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
sem_init(&handle->queue_sem, 0, 0); sem_init(&handle->queue_sem, 0, 0);
sem_init(&handle->pause_sem, 0, 1);
#endif #endif
#ifdef USE_DISPATCH #ifdef USE_DISPATCH
handle->queue_sem = dispatch_semaphore_create(0); handle->queue_sem = dispatch_semaphore_create(0);
handle->pause_sem = dispatch_semaphore_create(1);
#endif #endif
pthread_create(&handle->thread, NULL, run, handle); pthread_create(&handle->thread, NULL, run, handle);
#endif #endif
@@ -575,19 +691,14 @@ void *ao_create_async(int bits, int rate, int channels, int byte_format, const c
handle->mutex = CreateMutex(NULL, // default security attributes handle->mutex = CreateMutex(NULL, // default security attributes
FALSE, // initially not owned FALSE, // initially not owned
NULL); NULL);
handle->pause_mutex = CreateMutex(NULL, // default security attributes
FALSE, // initially not owned
NULL);
handle->clear_mutex = CreateMutex(NULL, handle->clear_mutex = CreateMutex(NULL,
FALSE, FALSE,
NULL); NULL);
handle->queue_sem = CreateSemaphore(NULL, 0, 1000000, NULL); handle->queue_sem = CreateSemaphore(NULL, 0, 1000000, NULL);
handle->pause_sem = CreateSemaphore(NULL, 1, 1000000, NULL);
handle->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) run, handle, 0, &handle->thread_id); handle->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) run, handle, 0, &handle->thread_id);
#endif #endif
MUTEX_UNLOCK(handle->pause_mutex);
MUTEX_UNLOCK(handle->clear_mutex);
return (void *) handle; return (void *) handle;
} }
@@ -596,15 +707,19 @@ 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, calling clear\n"); fprintf(stderr, "stopping ao_async, calling clear\n");
clear(h); MUTEX_LOCK(h->mutex);
h->stopped = TRUE;
MUTEX_UNLOCK(h->mutex);
clear(h, TRUE);
fprintf(stderr, "queue cleared\n"); fprintf(stderr, "queue cleared\n");
MUTEX_LOCK(h->mutex);
if (h->paused) { if (h->paused) {
MUTEX_UNLOCK(h->pause_mutex); SEM_POST(h->pause_sem);
} }
Queue_t *q = new_elem(STOP, 0, 0.0, 0.0, 0, NULL); MUTEX_UNLOCK(h->mutex);
add(h, q);
fprintf(stderr, "stop command queued\n"); fprintf(stderr, "stop command queued\n");
@@ -614,9 +729,14 @@ void ao_stop_async(void *ao_handle)
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
sem_destroy(&h->queue_sem); sem_destroy(&h->queue_sem);
sem_destroy(&h->pause_sem);
#endif
#ifdef USE_DISPATCH
dispatch_release(h->queue_sem);
dispatch_release(h->pause_sem);
#endif #endif
pthread_mutex_destroy(&h->pause_mutex);
pthread_mutex_destroy(&h->clear_mutex); pthread_mutex_destroy(&h->clear_mutex);
pthread_mutex_destroy(&h->mutex); pthread_mutex_destroy(&h->mutex);
#endif #endif
@@ -625,6 +745,9 @@ void ao_stop_async(void *ao_handle)
WaitForSingleObject(h->thread, INFINITE); WaitForSingleObject(h->thread, INFINITE);
CloseHandle(h->thread); CloseHandle(h->thread);
CloseHandle(h->mutex); CloseHandle(h->mutex);
CloseHandle(h->pause_sem);
CloseHandle(h->queue_sem);
CloseHandle(h->clear_mutex);
#endif #endif
ao_close(h->ao_device); ao_close(h->ao_device);
@@ -635,10 +758,7 @@ void ao_stop_async(void *ao_handle)
fprintf(stderr, "async handle freed\n"); fprintf(stderr, "async handle freed\n");
} }
#define AO_FMT_LITTLE 1 /*
#define AO_FMT_BIG 2
#define AO_FMT_NATIVE 4
static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int big_endian, unsigned char b[4]) static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int big_endian, unsigned char b[4])
{ {
int i; int i;
@@ -657,27 +777,38 @@ static inline void make_sample_bytes(int32_t sample, int bytes_per_sample, int b
} }
} }
} }
*/
void ao_play_async(void *ao_handle, int music_id, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info) void ao_play_async(void *ao_handle, int music_id, double at_second, double music_duration, int buf_size, void *mem, BufferInfo_t info)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
if (stopped(h, TRUE)) { return; }
Queue_t *q = NULL; Queue_t *q = NULL;
int ao_size = 0; int ao_size = 0;
void *ao_mem = convert_req_to_real(ao_handle, mem, buf_size, &info, &ao_size); void *ao_mem = convert_req_to_real(ao_handle, mem, buf_size, &info, &ao_size);
if (ao_mem == NULL || ao_size <= 0) {
if (ao_mem != NULL) { free(ao_mem); }
return;
}
q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem); q = new_elem(PLAY, music_id, at_second, music_duration, ao_size, ao_mem);
free(ao_mem); free(ao_mem);
add(h, q); if (q != NULL && q->buf != NULL) { // memory error has already been given.
add(h, q, FALSE);
}
} }
void ao_clear_async(void *ao_handle) void ao_clear_async(void *ao_handle)
{ {
AO_Handle *h = (AO_Handle *) ao_handle; AO_Handle *h = (AO_Handle *) ao_handle;
clear(h); if (stopped(h, TRUE)) { return; }
clear(h, FALSE);
} }
double ao_is_at_second_async(void *ao_handle) double ao_is_at_second_async(void *ao_handle)
@@ -746,12 +877,12 @@ void ao_pause_async(void *ao_handle, int paused)
if (h->paused) { if (h->paused) {
if (!paused) { if (!paused) {
h->paused = paused; h->paused = paused;
MUTEX_UNLOCK(h->pause_mutex); SEM_POST(h->pause_sem);
} }
} else { } else {
if (paused) { if (paused) {
h->paused = paused; h->paused = paused;
MUTEX_LOCK(h->pause_mutex); SEM_WAIT_INFINITE(h->pause_sem);
} }
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.