splitcomb.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 641 行 · 第 1/2 页

C
641
字号
/* $Id: splitcomb.c 974 2007-02-19 01:13:53Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjmedia/splitcomb.h>#include <pjmedia/errno.h>#include <pj/assert.h>#include <pj/log.h>#include <pj/pool.h>#define SIGNATURE	    PJMEDIA_PORT_SIGNATURE('S', 'p', 'C', 'b')#define SIGNATURE_PORT	    PJMEDIA_PORT_SIGNATURE('S', 'p', 'C', 'P')#define THIS_FILE	    "splitcomb.c"#define TMP_SAMP_TYPE	    pj_int16_t#define MAX_BUF_CNT	    PJMEDIA_SOUND_BUFFER_COUNT#if 0#   define TRACE_UP_(x)	PJ_LOG(5,x)#   define TRACE_DN_(x)	PJ_LOG(5,x)#else#   define TRACE_UP_(x)#   define TRACE_DN_(x)#endif#if 1#   define LOG_UP_(x)	PJ_LOG(5,x)#   define LOG_DN_(x)	PJ_LOG(5,x)#else#   define LOG_UP_(x)#   define LOG_DN_(x)#endif/* * This structure describes the splitter/combiner. */struct splitcomb{    pjmedia_port      base;    unsigned	      options;    /* Array of ports, one for each channel */    struct {	pjmedia_port *port;	pj_bool_t     reversed;    } *port_desc;    /* Temporary buffers needed to extract mono frame from     * multichannel frame. We could use stack for this, but this     * way it should be safer for devices with small stack size.     */    TMP_SAMP_TYPE    *get_buf;    TMP_SAMP_TYPE    *put_buf;};/* * This structure describes reverse port. */struct reverse_port{    pjmedia_port     base;    struct splitcomb*parent;    unsigned	     ch_num;    /* A reverse port need a temporary buffer to store frame     * (because of the different phase, see splitcomb.h for details).      * Since we can not expect get_frame() and put_frame() to be     * called evenly one after another, we use circular buffers to     * accomodate the "jitter".     */    unsigned	     buf_cnt;    /* Downstream is the direction when get_frame() is called to the     * splitter/combiner port.     */    unsigned	     dn_read_pos, dn_write_pos, 		     dn_overflow_pos, dn_underflow_pos;    pj_int16_t	    *dnstream_buf[MAX_BUF_CNT];    /* Upstream is the direction when put_frame() is called to the     * splitter/combiner port.     */    unsigned	     up_read_pos, up_write_pos, 		     up_overflow_pos, up_underflow_pos;    pj_int16_t	    *upstream_buf[MAX_BUF_CNT];};/* * Prototypes. */static pj_status_t put_frame(pjmedia_port *this_port, 			     const pjmedia_frame *frame);static pj_status_t get_frame(pjmedia_port *this_port, 			     pjmedia_frame *frame);static pj_status_t on_destroy(pjmedia_port *this_port);static pj_status_t rport_put_frame(pjmedia_port *this_port, 				   const pjmedia_frame *frame);static pj_status_t rport_get_frame(pjmedia_port *this_port, 				   pjmedia_frame *frame);static pj_status_t rport_on_destroy(pjmedia_port *this_port);/* * Create the splitter/combiner. */PJ_DEF(pj_status_t) pjmedia_splitcomb_create( pj_pool_t *pool,					      unsigned clock_rate,					      unsigned channel_count,					      unsigned samples_per_frame,					      unsigned bits_per_sample,					      unsigned options,					      pjmedia_port **p_splitcomb){    const pj_str_t name = pj_str("splitcomb");    struct splitcomb *sc;    /* Sanity check */    PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&		     samples_per_frame && bits_per_sample &&		     p_splitcomb, PJ_EINVAL);    /* Only supports 16 bits per sample */    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);    *p_splitcomb = NULL;    /* Create the splitter/combiner structure */    sc = pj_pool_zalloc(pool, sizeof(struct splitcomb));    PJ_ASSERT_RETURN(sc != NULL, PJ_ENOMEM);    /* Create temporary buffers */    sc->get_buf = pj_pool_alloc(pool, samples_per_frame * 				      sizeof(TMP_SAMP_TYPE) /				      channel_count);    PJ_ASSERT_RETURN(sc->get_buf, PJ_ENOMEM);    sc->put_buf = pj_pool_alloc(pool, samples_per_frame * 				      sizeof(TMP_SAMP_TYPE) /				      channel_count);    PJ_ASSERT_RETURN(sc->put_buf, PJ_ENOMEM);    /* Save options */    sc->options = options;    /* Initialize port */    pjmedia_port_info_init(&sc->base.info, &name, SIGNATURE, clock_rate,			   channel_count, bits_per_sample, samples_per_frame);    sc->base.put_frame = &put_frame;    sc->base.get_frame = &get_frame;    sc->base.on_destroy = &on_destroy;    /* Init ports array */    sc->port_desc = pj_pool_zalloc(pool, channel_count*sizeof(*sc->port_desc));    /* Done for now */    *p_splitcomb = &sc->base;    return PJ_SUCCESS;}/* * Attach media port with the same phase as the splitter/combiner. */PJ_DEF(pj_status_t) pjmedia_splitcomb_set_channel( pjmedia_port *splitcomb,						   unsigned ch_num,						   unsigned options,						   pjmedia_port *port){    struct splitcomb *sc = (struct splitcomb*) splitcomb;    /* Sanity check */    PJ_ASSERT_RETURN(splitcomb && port, PJ_EINVAL);    /* Make sure this is really a splitcomb port */    PJ_ASSERT_RETURN(sc->base.info.signature == SIGNATURE, PJ_EINVAL);    /* Check the channel number */    PJ_ASSERT_RETURN(ch_num < sc->base.info.channel_count, PJ_EINVAL);    /* options is unused for now */    PJ_UNUSED_ARG(options);    sc->port_desc[ch_num].port = port;    sc->port_desc[ch_num].reversed = PJ_FALSE;    return PJ_SUCCESS;}/* * Create reverse phase port for the specified channel. */PJ_DEF(pj_status_t) pjmedia_splitcomb_create_rev_channel( pj_pool_t *pool,				      pjmedia_port *splitcomb,				      unsigned ch_num,				      unsigned options,				      pjmedia_port **p_chport){    const pj_str_t name = pj_str("splitcomb-ch");    struct splitcomb *sc = (struct splitcomb*) splitcomb;    struct reverse_port *rport;    unsigned i;    pjmedia_port *port;    /* Sanity check */    PJ_ASSERT_RETURN(pool && splitcomb, PJ_EINVAL);    /* Make sure this is really a splitcomb port */    PJ_ASSERT_RETURN(sc->base.info.signature == SIGNATURE, PJ_EINVAL);    /* Check the channel number */    PJ_ASSERT_RETURN(ch_num < sc->base.info.channel_count, PJ_EINVAL);    /* options is unused for now */    PJ_UNUSED_ARG(options);    /* Create the port */    rport = pj_pool_zalloc(pool, sizeof(struct reverse_port));    rport->parent = sc;    rport->ch_num = ch_num;    /* Initialize port info... */    port = &rport->base;    pjmedia_port_info_init(&port->info, &name, SIGNATURE_PORT, 			   splitcomb->info.clock_rate, 1, 			   splitcomb->info.bits_per_sample, 			   splitcomb->info.samples_per_frame / 				   splitcomb->info.channel_count);    /* ... and the callbacks */    port->put_frame = &rport_put_frame;    port->get_frame = &rport_get_frame;    port->on_destroy = &rport_on_destroy;    rport->buf_cnt = options & 0xFF;    if (rport->buf_cnt == 0)	rport->buf_cnt = MAX_BUF_CNT;    /* Create put buffers */    for (i=0; i<rport->buf_cnt; ++i) {	rport->dnstream_buf[i] = pj_pool_zalloc(pool, port->info.bytes_per_frame);	PJ_ASSERT_RETURN(rport->dnstream_buf[i], PJ_ENOMEM);    }    rport->dn_write_pos = rport->buf_cnt/2;    /* Create get buffers */    for (i=0; i<rport->buf_cnt; ++i) {	rport->upstream_buf[i] = pj_pool_zalloc(pool, 						port->info.bytes_per_frame);	PJ_ASSERT_RETURN(rport->upstream_buf[i], PJ_ENOMEM);    }    rport->up_write_pos = rport->buf_cnt/2;    /* Save port in the splitcomb */    sc->port_desc[ch_num].port = &rport->base;    sc->port_desc[ch_num].reversed = PJ_TRUE;    /* Done */    *p_chport = port;    return PJ_SUCCESS;}/*  * Extract one mono frame from a multichannel frame.  */static void extract_mono_frame( const pj_int16_t *in,			        pj_int16_t *out,				unsigned ch,				unsigned ch_cnt,				unsigned samples_count){    unsigned i;    in += ch;    for (i=0; i<samples_count; ++i) {	*out++ = *in;	in += ch_cnt;    }}/*  * Put one mono frame into a multichannel frame  */static void store_mono_frame( const pj_int16_t *in,			      pj_int16_t *out,			      unsigned ch,			      unsigned ch_cnt,			      unsigned samples_count){    unsigned i;    out += ch;    for (i=0; i<samples_count; ++i) {	*out = *in++;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?