#include "precompile.h" #include "audiomixer.h" #include "audioengine.h" static apr_status_t read_frame(void *self, audioframe_t *frame) { audiomixer_t *mixer = CONTAINING_RECORD(self, audiomixer_t, base); apr_status_t status; if (mixer->base.downstream == NULL) return APR_EGENERAL; status = mixer->base.downstream->vtbl->read_frame(mixer->base.downstream, frame); if (status == APR_SUCCESS && frame->size) { int mixbuf[SUGGEST_FRAME_SIZE]; int mixcnt; int mixdtmf; int frame_samples; int frame_size; int i; int kk; if (mixer->arr_stream->nelts == 0) return status; frame_samples = frame->size >> 1; frame_size = frame->size; mixcnt = 0; mixdtmf = 0; memset(mixbuf, 0, sizeof(mixbuf)); for (i = 0; i < mixer->arr_stream->nelts; ++i) { audiostream_t *stream = APR_ARRAY_IDX(mixer->arr_stream, i, audiostream_t*); if (audiostream_get_direction(stream) & STREAM_DIR_READ) { short frm_buf[SUGGEST_FRAME_SIZE]; audioframe_t frm = {(char*)&frm_buf[0], SUGGEST_FRAME_SIZE}; status = stream->vtbl->read_frame(stream, &frm); if (status == APR_SUCCESS && frm.size == frame->size) { for (kk = 0; kk < frame_samples; ++kk) mixbuf[kk] += frm_buf[kk]; if (mixdtmf == 0 && frm.dtmf) mixdtmf = frm.dtmf; mixcnt ++; } } } if (mixcnt > 0) { short *dst = (short*)frame->buffer; for (kk = 0; kk < frame_samples; ++kk) { int t = mixbuf[kk] + dst[kk]; if (t > 32767) t = 32767; if (t < -32767) t = -32767; dst[kk] = (short)t; } if (frame->dtmf == 0) frame->dtmf = mixdtmf; } } else { return status; } return APR_SUCCESS; } static apr_status_t write_frame(void *self, const audioframe_t *frame) { audiomixer_t *mixer = CONTAINING_RECORD(self, audiomixer_t, base); if (mixer->base.downstream) { return mixer->base.downstream->vtbl->write_frame(mixer->base.downstream, frame); } else { return APR_EGENERAL; } } static audiostream_vtbl_t g_stream_vtbl = { &read_frame, &write_frame, }; apr_status_t audiomixer_create(apr_pool_t *pool, audioengine_t *engine, audiomixer_t **p_mixer) { audiomixer_t *mixer; mixer = apr_palloc(pool, sizeof(audiomixer_t)); memset(mixer, 0, sizeof(audiomixer_t)); mixer->arr_stream = apr_array_make(pool, 3, sizeof(audiostream_t*)); audiostream_init(engine, &g_stream_vtbl, &mixer->base); *p_mixer = mixer; return APR_SUCCESS; } void audiomixer_destroy(audiomixer_t *mixer) { } apr_status_t audiomixer_add_stream(audiomixer_t *mixer, audiostream_t *stream) { if (!mixer || !stream) return APR_EINVAL; APR_ARRAY_PUSH(mixer->arr_stream, audiostream_t*) = stream; return APR_SUCCESS; } apr_status_t audiomixer_remove_stream(audiomixer_t *mixer, audiostream_t *stream) { int i; if (!mixer || !stream) return APR_EINVAL; for (i = 0; i < mixer->arr_stream->nelts; ++i) { audiostream_t *t = APR_ARRAY_IDX(mixer->arr_stream, i, audiostream_t*); if (t == stream) { if (i != mixer->arr_stream->nelts-1) APR_ARRAY_IDX(mixer->arr_stream, i, audiostream_t*) = APR_ARRAY_IDX(mixer->arr_stream, mixer->arr_stream->nelts-1, audiostream_t*); apr_array_pop(mixer->arr_stream); return APR_SUCCESS; } } return APR_NOTFOUND; }