#include "precompile.h" #include "audiocontext.h" #include "audiostream.h" #include "audiodriver.h" #include "audiolog.h" #ifdef _WIN32 #else #include #include #endif typedef struct event_handler_entry { APR_RING_ENTRY(event_handler_entry) link; int priority; audiocontext_event_handler event_handler; void *user_data; }event_handler_entry; typedef struct event_entry { APR_RING_ENTRY(event_entry) link; void *stream_or_driver; int bstream; int evt; int param1; int param2; }event_entry; struct audiocontext_t { audioengine_t *engine; apr_array_header_t *arr_drv; APR_RING_HEAD(event_entry_head, event_entry) event_list, event_list_free; int event_list_cnt, event_list_free_cnt; APR_RING_HEAD(event_handler_entry_head, event_handler_entry) event_handler_list, event_handler_list_free; int event_handler_list_cnt, event_handler_list_free_cnt; apr_thread_mutex_t *mtx; apr_thread_t *thread_handle; volatile int bstop; #ifdef _WIN32 HANDLE sem; #else sem_t* sem; #endif // _WIN32 }; static void *APR_THREAD_FUNC audiocontext_run(apr_thread_t *thread_handle, void *data) { audiocontext_t *ctx = (audiocontext_t *)data; //SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); for (;;) { #ifdef _WIN32 WaitForSingleObject(ctx->sem, INFINITE); #else sem_wait(ctx->sem); #endif // _WIN32 if (!ctx->bstop) { int i; apr_thread_mutex_lock(ctx->mtx); for (i = 0; i < ctx->arr_drv->nelts; ++i) { audiodriver_t *drv = APR_ARRAY_IDX(ctx->arr_drv, i, audiodriver_t*); //暂时屏蔽rtp流发送功能 drv->vtbl->process_frame(drv); } while (ctx->event_list_cnt > 0) { event_entry *e = APR_RING_FIRST(&ctx->event_list); event_handler_entry *ep1, *ep2; APR_RING_REMOVE(e, link); ctx->event_list_cnt--; APR_RING_FOREACH_SAFE(ep1, ep2, &ctx->event_handler_list, event_handler_entry, link) { if ((*ep1->event_handler)(ctx, ep1->user_data, e->bstream, e->stream_or_driver, e->evt, e->param1, e->param2) == TRUE) { break; } } APR_RING_INSERT_TAIL(&ctx->event_list_free, e, event_entry, link); ctx->event_list_free_cnt++; } apr_thread_mutex_unlock(ctx->mtx); } else { break; } } apr_thread_exit(thread_handle, APR_SUCCESS); return NULL; } audioengine_t *audiocontext_get_engine(audiocontext_t *ctx) { return ctx ? ctx->engine : 0; } apr_status_t audiocontext_create(apr_pool_t *pool, audioengine_t *e, audiocontext_t **p_ctx) { apr_status_t status; audiocontext_t *ctx; ctx = apr_palloc(pool, sizeof(audiocontext_t)); memset(ctx, 0, sizeof(audiocontext_t)); status = apr_thread_mutex_create(&ctx->mtx, APR_THREAD_MUTEX_NESTED, pool); if (status != APR_SUCCESS) { return status; } #ifdef _WIN32 ctx->sem = CreateSemaphoreA(NULL, 0, 0x7fffffff, NULL); #else ctx->sem = apr_palloc(pool, sizeof(sem_t)); sem_init(ctx->sem, 0, 0); if (ctx->sem){ int ivalue = -1; sem_getvalue(ctx->sem, &ivalue); } #endif // _WIN32 if (!ctx->sem) { apr_thread_mutex_destroy(ctx->mtx); return apr_get_os_error(); } ctx->arr_drv = apr_array_make(pool, 1024, sizeof(audiodriver_t*)); APR_RING_INIT(&ctx->event_list, event_entry, link); APR_RING_INIT(&ctx->event_list_free, event_entry, link); APR_RING_INIT(&ctx->event_handler_list, event_handler_entry, link); APR_RING_INIT(&ctx->event_handler_list_free, event_handler_entry, link); ctx->event_list_cnt = ctx->event_list_free_cnt = 0; ctx->event_handler_list_cnt = ctx->event_handler_list_free_cnt = 0; ctx->engine = e; status = apr_thread_create(&ctx->thread_handle, NULL, &audiocontext_run, ctx, pool); if (status != APR_SUCCESS) { #ifdef _WIN32 CloseHandle(ctx->sem); #else sem_destroy(ctx->sem); #endif // _WIN32 apr_thread_mutex_destroy(ctx->mtx); return status; } *p_ctx = ctx; return APR_SUCCESS; } void audiocontext_destroy(audiocontext_t *ctx) { if (ctx && ctx->thread_handle) { apr_status_t s; ctx->bstop = 1; #ifdef _WIN32 ReleaseSemaphore(ctx->sem, 2, NULL); #else sem_post(ctx->sem); #endif // _WIN32 apr_thread_join(&s, ctx->thread_handle); ctx->thread_handle = 0; #ifdef _WIN32 CloseHandle(ctx->sem); #else sem_destroy(ctx->sem); #endif // _WIN32 { event_handler_entry *ep1, *ep2; APR_RING_FOREACH_SAFE(ep1, ep2, &ctx->event_handler_list, event_handler_entry, link) { APR_RING_REMOVE(ep1, link); free(ep1); } APR_RING_FOREACH_SAFE(ep1, ep2, &ctx->event_handler_list_free, event_handler_entry, link) { APR_RING_REMOVE(ep1, link); free(ep1); } } { event_entry *ep1, *ep2; APR_RING_FOREACH_SAFE(ep1, ep2, &ctx->event_list, event_entry, link) { APR_RING_REMOVE(ep1, link); free(ep1); } APR_RING_FOREACH_SAFE(ep1, ep2, &ctx->event_list_free, event_entry, link) { APR_RING_REMOVE(ep1, link); free(ep1); } } apr_thread_mutex_destroy(ctx->mtx); } } void audiocontext_signal(audiocontext_t *ctx) { #ifdef _WIN32 ReleaseSemaphore(ctx->sem, 1, NULL); #else sem_post(ctx->sem); #endif // _WIN32 } apr_status_t audiocontext_add_driver(audiocontext_t *ctx, audiodriver_t *drv) { if (!ctx || !drv) return APR_BADARG; apr_thread_mutex_lock(ctx->mtx); drv->ctx = ctx; APR_ARRAY_PUSH(ctx->arr_drv, audiodriver_t*) = drv; apr_thread_mutex_unlock(ctx->mtx); return APR_SUCCESS; } apr_status_t audiocontext_remove_driver(audiocontext_t *ctx, audiodriver_t *drv) { if (!ctx || !drv) return APR_BADARG; apr_thread_mutex_lock(ctx->mtx); { int i; for (i = 0; i < ctx->arr_drv->nelts; ++i) { audiodriver_t *d = APR_ARRAY_IDX(ctx->arr_drv, i, audiodriver_t*); if (d == drv) { drv->ctx = NULL; if (i < ctx->arr_drv->nelts-1) { audiodriver_t *tmp = APR_ARRAY_IDX(ctx->arr_drv, i, audiodriver_t*); APR_ARRAY_IDX(ctx->arr_drv, i, audiodriver_t*) = APR_ARRAY_IDX(ctx->arr_drv, ctx->arr_drv->nelts-1, audiodriver_t*); APR_ARRAY_IDX(ctx->arr_drv, ctx->arr_drv->nelts-1, audiodriver_t*) = tmp; } apr_array_pop(ctx->arr_drv); apr_thread_mutex_unlock(ctx->mtx); return APR_SUCCESS; } } } apr_thread_mutex_unlock(ctx->mtx); return APR_EGENERAL; } apr_status_t audiocontext_add_stream(audiocontext_t *ctx, audiostream_t *stream) { stream->ctx = ctx; return APR_SUCCESS; } apr_status_t audiocontext_remove_stream(audiocontext_t *ctx, audiostream_t *stream) { stream->ctx = NULL; return APR_SUCCESS; } apr_status_t audiocontext_lock(audiocontext_t *ctx) { return ctx ? apr_thread_mutex_lock(ctx->mtx) : APR_BADARG; } apr_status_t audiocontext_unlock(audiocontext_t *ctx) { return ctx ? apr_thread_mutex_unlock(ctx->mtx) : APR_BADARG; } static apr_status_t audiocontext_put_event(audiocontext_t *ctx, int bstream, void *stream_or_driver, int evt, int param1, int param2) { event_entry *e; if (!ctx || !stream_or_driver) return APR_EINVAL; apr_thread_mutex_lock(ctx->mtx); if (ctx->event_list_free_cnt == 0) { int i; for (i = 0; i < 10; ++i) { e = malloc(sizeof(event_entry)); APR_RING_INSERT_TAIL(&ctx->event_list_free, e, event_entry, link); ctx->event_list_free_cnt ++; } } e = APR_RING_FIRST(&ctx->event_list_free); APR_RING_REMOVE(e, link); ctx->event_list_free_cnt --; e->stream_or_driver = stream_or_driver; e->evt = evt; e->bstream = bstream; e->param1 = param1; e->param2 = param2; APR_RING_INSERT_TAIL(&ctx->event_list, e, event_entry, link); ctx->event_list_cnt++; apr_thread_mutex_unlock(ctx->mtx); return APR_SUCCESS; } apr_status_t audiocontext_put_stream_event(audiocontext_t *ctx, audiostream_t *stream, int evt, int param1, int param2) { return audiocontext_put_event(ctx, TRUE, stream, evt, param1, param2); } apr_status_t audiocontext_put_driver_event(audiocontext_t *ctx, audiodriver_t *driver, int evt, int param1, int param2) { return audiocontext_put_event(ctx, FALSE, driver, evt, param1, param2); } apr_status_t audiocontext_add_event_handler(audiocontext_t *ctx, int priority, audiocontext_event_handler handler, void *user_data) { event_handler_entry *e, *ep; if (!ctx || !handler) return APR_EINVAL; apr_thread_mutex_lock(ctx->mtx); if (ctx->event_handler_list_free_cnt == 0) { int i; for (i = 0; i < 10; ++i) { e = malloc(sizeof(event_handler_entry)); APR_RING_INSERT_TAIL(&ctx->event_handler_list_free, e, event_handler_entry, link); ctx->event_handler_list_free_cnt ++; } } e = APR_RING_FIRST(&ctx->event_handler_list_free); APR_RING_REMOVE(e, link); ctx->event_handler_list_free_cnt --; e->priority = priority; e->event_handler = handler; e->user_data = user_data; APR_RING_FOREACH(ep, &ctx->event_handler_list, event_handler_entry, link) { if (priority < ep->priority) { break; } } APR_RING_INSERT_BEFORE(ep, e, link); ctx->event_handler_list_cnt ++; apr_thread_mutex_unlock(ctx->mtx); return APR_SUCCESS; } apr_status_t audiocontext_remove_event_handler(audiocontext_t *ctx, audiocontext_event_handler handler) { event_handler_entry *ep; apr_thread_mutex_lock(ctx->mtx); APR_RING_FOREACH(ep, &ctx->event_handler_list, event_handler_entry, link) { if (ep->event_handler == handler) { APR_RING_REMOVE(ep, link); ctx->event_handler_list_cnt --; APR_RING_INSERT_TAIL(&ctx->event_handler_list_free, ep, event_handler_entry, link); ctx->event_handler_list_free_cnt ++; apr_thread_mutex_unlock(ctx->mtx); return APR_SUCCESS; } } apr_thread_mutex_unlock(ctx->mtx); return APR_NOTFOUND; }