#include "precompile.h" #include "audiocache.h" #include "audiocontext.h" #include "audiolog.h" static void process_frame(void *self) { apr_status_t status; audiocache_t *cache = CONTAINING_RECORD(self, audiocache_t, driver_base); if (audiostream_get_direction(&cache->stream_base) & STREAM_DIR_WRITE) { if (cache->pending_write.size != SUGGEST_FRAME_SIZE && cache->pending_write.size > 0) { status = cache->stream_base.vtbl->write_frame(cache->stream_base.downstream, &cache->pending_write); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_DEBUG,"audiostream write_frame failed, status = %d", status); } } } if (audiostream_get_direction(&cache->stream_base) & STREAM_DIR_READ) { cache->pending_read.size = SUGGEST_FRAME_SIZE; status = cache->stream_base.vtbl->read_frame(cache->stream_base.downstream, &cache->pending_read); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_DEBUG,"audiostream read_frame failed"); } } } static apr_status_t read_frame(void *self, audioframe_t *frame) { apr_status_t status; audiocache_t *cache = CONTAINING_RECORD(self, audiocache_t, stream_base); if (audiostream_get_direction(&cache->stream_base) & STREAM_DIR_READ) { status = audioframe_copy(frame, &cache->pending_read); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR, "audiostream_cached_read_frame failed, frm->size little than stream pending frame"); } return status; } return APR_EGENERAL; } static apr_status_t write_frame(void *self, const audioframe_t *frame) { apr_status_t status; audiocache_t *cache = CONTAINING_RECORD(self, audiocache_t, stream_base); if (audiostream_get_direction(&cache->stream_base) & STREAM_DIR_WRITE) { cache->pending_write.size = SUGGEST_FRAME_SIZE; status = audioframe_copy(&cache->pending_write, frame); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR, "audiostream_cached_write_frame failed, frm->size larger than stream pending frame"); return status; } } return APR_EGENERAL; } typedef struct audiostream_read_only { audiostream_t base; audiocache_t *cache; }audiostream_read_only; typedef struct audiostream_write_only { audiostream_t base; audiocache_t *cache; }audiostream_write_only; static apr_status_t istream_read_frame(void *self, audioframe_t *frame) { audiostream_read_only *ro = (audiostream_read_only *)self; audiocache_t *cache = ro->cache; return read_frame(&cache->stream_base, frame); } static apr_status_t ostream_write_frame(void *self, const audioframe_t *frame) { audiostream_write_only *wo = (audiostream_write_only *)self; audiocache_t *cache = wo->cache; return write_frame(&cache->stream_base, frame); } static audiodriver_vtbl_t g_driver_vtbl = { &process_frame, }; static audiostream_vtbl_t g_stream_vtbl = { &read_frame, &write_frame, }; static audiostream_vtbl_t g_istream_vtbl = { &istream_read_frame, NULL, }; static audiostream_vtbl_t g_ostream_vtbl = { NULL, &ostream_write_frame, }; apr_status_t audiocache_create(apr_pool_t *pool, audioengine_t *engine, int istream_cnt, int ostream_cnt, audiocache_t **p_cache) { audiocache_t *cache; int i; cache = apr_palloc(pool, sizeof(audiocache_t)); cache->pending_read.size = SUGGEST_FRAME_SIZE; cache->pending_read.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); cache->pending_read.dtmf = 0; cache->pending_write.size = SUGGEST_FRAME_SIZE; cache->pending_write.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); cache->pending_write.dtmf = 0; audiostream_init(engine, &g_stream_vtbl, &cache->stream_base); audiodriver_init(engine, &g_driver_vtbl, &cache->driver_base); cache->arr_istream = apr_array_make(pool, istream_cnt, sizeof(audiostream_read_only*)); for (i = 0; i < istream_cnt; ++i) { audiostream_read_only *ro = apr_palloc(pool, sizeof(audiostream_read_only)); audiostream_init(engine, &g_istream_vtbl, &ro->base); ro->base.direction = STREAM_DIR_READ; ro->cache = cache; APR_ARRAY_PUSH(cache->arr_istream, audiostream_read_only*) = ro; } cache->arr_ostream = apr_array_make(pool, ostream_cnt, sizeof(audiostream_write_only*)); for (i = 0; i < ostream_cnt; ++i) { audiostream_write_only *wo = apr_palloc(pool, sizeof(audiostream_write_only)); audiostream_init(engine, &g_ostream_vtbl, &wo->base); wo->base.direction = STREAM_DIR_WRITE; APR_ARRAY_PUSH(cache->arr_ostream, audiostream_write_only*) = wo; } *p_cache = cache; return APR_SUCCESS; } void audiocache_destroy(audiocache_t *cache) { } audiostream_t* audiocache_get_istream(audiocache_t *cache, int idx) { audiostream_read_only *ro = APR_ARRAY_IDX(cache->arr_istream, idx, audiostream_read_only *); return &ro->base; } audiostream_t* audiocache_get_ostream(audiocache_t *cache, int idx) { audiostream_write_only *wo = APR_ARRAY_IDX(cache->arr_ostream, idx, audiostream_write_only *); return &wo->base; }