#include "precompile.h" #include "audioconf.h" #include "audiocontext.h" #include "audiolog.h" static void process_frame(void *self) { int mixbuf[SUGGEST_FRAME_SIZE]; int mixcnt; int mixdtmf; int i; int frame_samples; int frame_size; audioconf_t *conf = CONTAINING_RECORD(self, audioconf_t, base); frame_samples = conf->clock / 1000 * FRAME_TIME; frame_size = frame_samples * 2; mixcnt = 0; mixdtmf = 0; memset(mixbuf, 0, sizeof(mixbuf)); audiocontext_lock(conf->base.ctx); for (i = 0; i < conf->arr_member->nelts; ++i) { audiostream_t *stream = APR_ARRAY_IDX(conf->arr_member, i, audiostream_t*); if (audiostream_get_direction(stream) & STREAM_DIR_READ) { apr_status_t status; audioframe_t *frm = APR_ARRAY_IDX(conf->arr_frame, i, audioframe_t*); frm->size = SUGGEST_FRAME_SIZE; status = stream->vtbl->read_frame(stream, frm); if (status == APR_SUCCESS && frm->size != frame_size) { AUDIO_LOG_DEBUG("audio conf read frame failed, fill with silence frame!"); memset(frm->buffer, 0, frame_size); frm->size = frame_size; } if (status == APR_SUCCESS) { int k; short *p = (short*)&frm->buffer[0]; for (k = 0; k < frame_samples; ++k) mixbuf[k] += p[k]; mixcnt ++; if (frm->dtmf) mixdtmf = frm->dtmf; } } } for (i = 0; i < conf->arr_member->nelts; ++i) { audiostream_t *stream = APR_ARRAY_IDX(conf->arr_member, i, audiostream_t*); short tmp_frm_buf[SUGGEST_FRAME_SIZE]; audioframe_t tmp_frm = {(char*)&tmp_frm_buf[0], frame_samples*2, 0}; int k; if (audiostream_get_direction(stream) & STREAM_DIR_WRITE) { apr_status_t status; if (audiostream_get_direction(stream) & STREAM_DIR_READ) { audioframe_t *frm = APR_ARRAY_IDX(conf->arr_frame, i, audioframe_t*); short *q = (short*)&frm->buffer[0]; for (k = 0; k < frame_samples; ++k) { if (mixcnt == 1) { tmp_frm_buf[k] = (short)((mixbuf[k] - (int)q[k])); } else { tmp_frm_buf[k] = (short)((mixbuf[k] - (int)q[k])/(mixcnt-1)); } } if (frm->dtmf == 0) frm->dtmf = mixdtmf; } else { for (k = 0; k < frame_samples; ++k) { if (mixcnt != 0) { tmp_frm_buf[k] = (short)((mixbuf[k])/(mixcnt)); } else { tmp_frm_buf[k] = (short)mixbuf[k]; } } } status = stream->vtbl->write_frame(stream, &tmp_frm); if (status != APR_SUCCESS) { AUDIO_LOG_ERROR("audio conf write frame failed"); } } } audiocontext_unlock(conf->base.ctx); } static audiodriver_vtbl_t g_driver_vtbl = { &process_frame, }; apr_status_t audioconf_create(apr_pool_t *pool, audioengine_t *engine, int clock, audioconf_t **p_conf) { audioconf_t *conf; conf = apr_palloc(pool, sizeof(audioconf_t)); memset(conf, 0, sizeof(audioconf_t)); conf->clock = clock; conf->arr_member = apr_array_make(pool, 5, sizeof(audiostream_t*)); conf->arr_frame = apr_array_make(pool, 5, sizeof(audioframe_t*)); audiodriver_init(engine, &g_driver_vtbl, &conf->base); *p_conf = conf; return APR_SUCCESS; } void audioconf_destroy(audioconf_t *conf) { //... } apr_status_t audioconf_add_member(apr_pool_t *pool, audioconf_t *conf, audiostream_t *member_stream) { APR_ARRAY_PUSH(conf->arr_member, audiostream_t*) = member_stream; if (conf->arr_frame->nelts < conf->arr_member->nelts) { audioframe_t *frm = apr_palloc(pool, sizeof(audioframe_t)); frm->size = SUGGEST_FRAME_SIZE; frm->buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); frm->dtmf = 0; APR_ARRAY_PUSH(conf->arr_frame, audioframe_t*) = frm; } return APR_SUCCESS; } apr_status_t audioconf_remove_member(audioconf_t *conf, audiostream_t *member_stream) { int i ; for (i = 0; i < conf->arr_member->nelts; ++i) { audiostream_t *t = APR_ARRAY_IDX(conf->arr_member, i, audiostream_t*); if (t == member_stream) { if (i != conf->arr_member->nelts-1) { audiostream_t *tt = APR_ARRAY_IDX(conf->arr_member, i, audiostream_t*); APR_ARRAY_IDX(conf->arr_member, i, audiostream_t*) = APR_ARRAY_IDX(conf->arr_member, conf->arr_member->nelts-1, audiostream_t*); APR_ARRAY_IDX(conf->arr_member, conf->arr_member->nelts-1, audiostream_t*) = tt; } apr_array_pop(conf->arr_member); return APR_SUCCESS; } } return APR_NOTFOUND; }