#include "precompile.h" #include "audioaec.h" #include "audioengine.h" #include static apr_status_t read_frame(void *self, audioframe_t *frame) { audioaec_t *aec = CONTAINING_RECORD(self, audioaec_t, base); apr_status_t status = APR_SUCCESS; if (aec->opt & AUDIO_AEC_OPT_READ_AS_CAPTURE) { aec->tmp_capture_frame.size = SUGGEST_FRAME_SIZE; status = aec->base.downstream->vtbl->read_frame(aec->base.downstream, &aec->tmp_capture_frame); if (status == 0) { if (aec->tmp_capture_frame.size == 0) { memset(aec->tmp_capture_frame.buffer, 0, aec->psize); } frame->dtmf = aec->tmp_capture_frame.dtmf; frame->size = aec->psize; speex_echo_capture(aec->state, (short*)aec->tmp_capture_frame.buffer, (short*)frame->buffer); } } else { status = aec->base.downstream->vtbl->read_frame(aec->base.downstream, frame); if (status != 0 || frame->size == 0) { memset(frame->buffer, 0, aec->psize); frame->size = aec->psize; } speex_echo_playback(aec->state, (short*)frame->buffer); } return status; } static apr_status_t write_frame(void *self, const audioframe_t *frame) { audioaec_t *aec = CONTAINING_RECORD(self, audioaec_t, base); apr_status_t status = APR_SUCCESS; if (aec->opt & AUDIO_AEC_OPT_READ_AS_CAPTURE) { aec->tmp_capture_frame.dtmf = frame->dtmf; if (frame->size == 0) { aec->tmp_capture_frame.size = aec->psize; memset(aec->tmp_capture_frame.buffer, 0, aec->psize); speex_echo_playback(aec->state, (short*)aec->tmp_capture_frame.buffer); status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, &aec->tmp_capture_frame); } else { speex_echo_playback(aec->state, (short*)frame->buffer); status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, frame); } } else { if (frame->size == 0) { memset((void*)frame->buffer, 0, aec->psize); // because size is zero, so buffer can be use } aec->tmp_capture_frame.dtmf = frame->dtmf; aec->tmp_capture_frame.size = aec->psize; speex_echo_capture(aec->state, (short*)frame->buffer, (short*)aec->tmp_capture_frame.buffer); status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, &aec->tmp_capture_frame); } return status; } static audiostream_vtbl_t g_stream_vtbl = { &read_frame, &write_frame, }; apr_status_t audioaec_create(apr_pool_t *pool, audioengine_t *engine, int clock, int ptime, int opt, int latency, audioaec_t **p_aec) { audioaec_t *aec; if (latency == 0) latency = 300; aec = apr_palloc(pool, sizeof(audioaec_t)); memset(aec, 0, sizeof(audioaec_t)); audiostream_init(engine, &g_stream_vtbl, &aec->base); aec->opt = opt; aec->clock = clock; aec->ptime = ptime; aec->psize = ptime * clock / 1000 * 2; aec->tmp_capture_frame.size = SUGGEST_FRAME_SIZE; aec->tmp_capture_frame.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE); aec->tmp_capture_frame.dtmf = 0; /* Set EC latency to 3/4 of output latency to reduce the * possibility of missing/late reference frame. */ { //unsigned uLlatency = 440 * 3/4; int uLlatency = latency * 3 / 4; aec->state = speex_echo_state_init(ptime * clock /1000,clock * uLlatency / 1000); } *p_aec = aec; return APR_SUCCESS; } void audioaec_destroy(audioaec_t *aec) { speex_echo_state_destroy(aec->state); }