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 + -
显示快捷键?