#include "precompile.h" #include "audiobridge.h" #include "audiocontext.h" #include "audiolog.h" static apr_status_t read_and_write(audiostream_t *src, audiostream_t *dst, audioframe_t *frm) { apr_status_t status = APR_EGENERAL; if (src && (audiostream_get_direction(src) & STREAM_DIR_READ)) { status = src->vtbl->read_frame(src, frm); if (status == APR_SUCCESS) { if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { status = dst->vtbl->write_frame(dst, frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } else { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, read frame failed"); if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { frm->size = 0; // silence frm status = dst->vtbl->write_frame(dst, frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } } else { if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { frm->size = 0; // silence frm status = dst->vtbl->write_frame(dst, frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } return status; } static void mix_frame(audioframe_t *x, audioframe_t *y, audioframe_t *out) { if (x->size == 0) { memcpy(out->buffer, y->buffer, y->size); out->size = y->size; } else if (y->size == 0) { memcpy(out->buffer, x->buffer, x->size); out->size = x->size; } else { int i; int frame_samples = x->size >> 1; short *xx = (short*)&x->buffer[0]; short *yy = (short*)&y->buffer[0]; short *zz = (short*)&out->buffer[0]; for (i = 0; i < frame_samples; ++i) { //int t = (((int)*xx + (int)*yy) * 3) >> 2; int t = (*xx + *yy) - (((*xx) * (*yy)) >> 0x10); if (t > 32767) t = 32767; if (t < -32767) t = -32767; *zz = (short)t; xx++; yy++; zz++; } out->size = x->size; } } static void process_frame(void *self) { audiobridge_t *bridge = CONTAINING_RECORD(self, audiobridge_t, base); char left_buf[SUGGEST_FRAME_SIZE]; char right_buf[SUGGEST_FRAME_SIZE]; audioframe_t left_frm = {&left_buf[0], SUGGEST_FRAME_SIZE, 0}; audioframe_t right_frm = {&right_buf[0], SUGGEST_FRAME_SIZE, 0}; apr_status_t left_status, right_status; left_status = read_and_write(bridge->leg_stream[AUDIO_BRIDGE_LEG_LEFT], bridge->leg_stream[AUDIO_BRIDGE_LEG_RIGHT], &left_frm); right_status = read_and_write(bridge->leg_stream[AUDIO_BRIDGE_LEG_RIGHT], bridge->leg_stream[AUDIO_BRIDGE_LEG_LEFT], &right_frm); if (bridge->rec_stream && (audiostream_get_direction(bridge->rec_stream)&STREAM_DIR_WRITE)) { apr_status_t status = APR_EGENERAL; if (left_status == APR_SUCCESS && right_status != APR_SUCCESS) { status = bridge->rec_stream->vtbl->write_frame(bridge->rec_stream, &left_frm); } else if (left_status != APR_SUCCESS && right_status == APR_SUCCESS) { status = bridge->rec_stream->vtbl->write_frame(bridge->rec_stream, &right_frm); } else if (left_status == APR_SUCCESS && right_status == APR_SUCCESS) { char rec_buf[SUGGEST_FRAME_SIZE]; audioframe_t rec_frm = {&rec_buf[0], SUGGEST_FRAME_SIZE, 0}; mix_frame(&left_frm, &right_frm, &rec_frm); status = bridge->rec_stream->vtbl->write_frame(bridge->rec_stream, &rec_frm); } if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame to recorder stream failed"); } } } static void process_frame1(void *self) { int i; audiobridge_t *bridge = CONTAINING_RECORD(self, audiobridge_t, base); for (i = 0; i < 2; ++i) { char buf[SUGGEST_FRAME_SIZE]; audiostream_t *src; audiostream_t *dst; apr_status_t status; audioframe_t frm = {&buf[0], SUGGEST_FRAME_SIZE, 0}; src = bridge->leg_stream[i]; dst = bridge->leg_stream[1-i]; if (src && (audiostream_get_direction(src) & STREAM_DIR_READ)) { status = src->vtbl->read_frame(src, &frm); if (status == APR_SUCCESS) { if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { status = dst->vtbl->write_frame(dst, &frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } else { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, read frame failed"); if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { frm.size = 0; // silence frm status = dst->vtbl->write_frame(dst, &frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } } else { if (dst && (audiostream_get_direction(dst)&STREAM_DIR_WRITE)) { frm.size = 0; // silence frm status = dst->vtbl->write_frame(dst, &frm); if (status != APR_SUCCESS) { audio_log_v(AUDIO_LOG_LEVEL_ERROR,"audio bridge process_frame, write frame failed"); } } } } } static audiodriver_vtbl_t g_driver_vtbl = { &process_frame, }; apr_status_t audiobridge_create(apr_pool_t *pool, audioengine_t *engine, audiobridge_t **p_bridge) { audiobridge_t *bridge = apr_palloc(pool, sizeof(audiobridge_t)); if (NULL == bridge){ return APR_ENOPOOL; } memset(bridge, 0, sizeof(audiobridge_t)); bridge->leg_stream[0] = NULL; bridge->leg_stream[1] = NULL; bridge->rec_stream = NULL; audiodriver_init(engine, &g_driver_vtbl, &bridge->base); *p_bridge = bridge; return APR_SUCCESS; } void audiobridge_destroy(audiobridge_t *bridge) { //... } void audiobridge_set_leg(audiobridge_t *bridge, int leg, audiostream_t *stream) { bridge->leg_stream[leg] = stream; } audiostream_t* audiobridge_get_leg(audiobridge_t *bridge, int leg) { return bridge->leg_stream[leg]; } void audiobridge_set_recorder(audiobridge_t *bridge, audiostream_t *stream) { bridge->rec_stream = stream; } audiostream_t* audiobridge_get_recorder(audiobridge_t *bridge) { return bridge->rec_stream; }