conference.c

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

C
1,932
字号
{    return conf->connect_cnt;}/* * Remove the specified port. */PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,					      unsigned port ){    struct conf_port *conf_port;    unsigned i;    /* Check arguments */    PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL);    /* Port must be valid. */    PJ_ASSERT_RETURN(conf->ports[port] != NULL, PJ_EINVAL);    /* Suspend the sound devices.     * Don't want to remove port while port is being accessed by sound     * device's threads!     */    pj_mutex_lock(conf->mutex);    conf_port = conf->ports[port];    conf_port->tx_setting = PJMEDIA_PORT_DISABLE;    conf_port->rx_setting = PJMEDIA_PORT_DISABLE;    /* Remove this port from transmit array of other ports. */    for (i=0; i<conf->max_ports; ++i) {	unsigned j;	conf_port = conf->ports[i];	if (!conf_port)	    continue;	if (conf_port->listener_cnt == 0)	    continue;	for (j=0; j<conf_port->listener_cnt; ++j) {	    if (conf_port->listener_slots[j] == port) {		pj_array_erase(conf_port->listener_slots, sizeof(SLOT_TYPE),			       conf_port->listener_cnt, j);		--conf->connect_cnt;		--conf_port->listener_cnt;		break;	    }	}    }    /* Update conf's connection count. */    conf_port = conf->ports[port];    conf->connect_cnt -= conf_port->listener_cnt;    /* Remove the port. */    conf->ports[port] = NULL;    --conf->port_cnt;    pj_mutex_unlock(conf->mutex);    /* Stop sound if there's no connection. */    if (conf->connect_cnt == 0) {	pause_sound(conf);    }    return PJ_SUCCESS;}/* * Enum ports. */PJ_DEF(pj_status_t) pjmedia_conf_enum_ports( pjmedia_conf *conf,					     unsigned ports[],					     unsigned *p_count ){    unsigned i, count=0;    PJ_ASSERT_RETURN(conf && p_count && ports, PJ_EINVAL);    for (i=0; i<conf->max_ports && count<*p_count; ++i) {	if (!conf->ports[i])	    continue;	ports[count++] = i;    }    *p_count = count;    return PJ_SUCCESS;}/* * Get port info */PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,						unsigned slot,						pjmedia_conf_port_info *info){    struct conf_port *conf_port;    /* Check arguments */    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);    /* Port must be valid. */    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL);    conf_port = conf->ports[slot];    info->slot = slot;    info->name = conf_port->name;    info->tx_setting = conf_port->tx_setting;    info->rx_setting = conf_port->rx_setting;    info->listener_cnt = conf_port->listener_cnt;    info->listener_slots = conf_port->listener_slots;    info->clock_rate = conf_port->clock_rate;    info->channel_count = conf->channel_count;    info->samples_per_frame = conf_port->samples_per_frame;    info->bits_per_sample = conf->bits_per_sample;    info->tx_adj_level = conf_port->tx_adj_level - NORMAL_LEVEL;    info->rx_adj_level = conf_port->rx_adj_level - NORMAL_LEVEL;    return PJ_SUCCESS;}PJ_DEF(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf,						unsigned *size,						pjmedia_conf_port_info info[]){    unsigned i, count=0;    PJ_ASSERT_RETURN(conf && size && info, PJ_EINVAL);    for (i=0; i<conf->max_ports && count<*size; ++i) {	if (!conf->ports[i])	    continue;	pjmedia_conf_get_port_info(conf, i, &info[count]);	++count;    }    *size = count;    return PJ_SUCCESS;}/* * Get signal level. */PJ_DEF(pj_status_t) pjmedia_conf_get_signal_level( pjmedia_conf *conf,						   unsigned slot,						   unsigned *tx_level,						   unsigned *rx_level){    struct conf_port *conf_port;    /* Check arguments */    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);    /* Port must be valid. */    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL);    conf_port = conf->ports[slot];    if (tx_level != NULL) {	*tx_level = conf_port->tx_level;    }    if (rx_level != NULL) 	*rx_level = conf_port->rx_level;    return PJ_SUCCESS;}/* * Adjust RX level of individual port. */PJ_DEF(pj_status_t) pjmedia_conf_adjust_rx_level( pjmedia_conf *conf,						  unsigned slot,						  int adj_level ){    struct conf_port *conf_port;    /* Check arguments */    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);    /* Port must be valid. */    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL);    /* Value must be from -128 to +127 */    /* Disabled, you can put more than +127, at your own risk:      PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);     */    PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);    conf_port = conf->ports[slot];    /* Set normalized adjustment level. */    conf_port->rx_adj_level = adj_level + NORMAL_LEVEL;    return PJ_SUCCESS;}/* * Adjust TX level of individual port. */PJ_DEF(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf,						  unsigned slot,						  int adj_level ){    struct conf_port *conf_port;    /* Check arguments */    PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL);    /* Port must be valid. */    PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL);    /* Value must be from -128 to +127 */    /* Disabled, you can put more than +127,, at your own risk:     PJ_ASSERT_RETURN(adj_level >= -128 && adj_level <= 127, PJ_EINVAL);     */    PJ_ASSERT_RETURN(adj_level >= -128, PJ_EINVAL);    conf_port = conf->ports[slot];    /* Set normalized adjustment level. */    conf_port->tx_adj_level = adj_level + NORMAL_LEVEL;    return PJ_SUCCESS;}/* Convert signed 16bit pcm sample to unsigned 16bit sample */static pj_uint16_t pcm2unsigned(pj_int32_t pcm){    return (pj_uint16_t)(pcm + 32768);}/* Convert unsigned 16bit sample to signed 16bit pcm sample */static pj_int16_t unsigned2pcm(pj_uint32_t uns){    return (pj_int16_t)(uns - 32768);}/* * Read from port. */static pj_status_t read_port( pjmedia_conf *conf,			      struct conf_port *cport, pj_int16_t *frame,			      pj_size_t count, pjmedia_frame_type *type ){    pj_assert(count == conf->samples_per_frame);    TRACE_((THIS_FILE, "read_port %.*s: count=%d", 		       (int)cport->name.slen, cport->name.ptr,		       count));    /* If port's samples per frame and sampling rate matches conference     * bridge's settings, get the frame directly from the port.     */    if (cport->rx_buf_cap == 0) {	pjmedia_frame f;	pj_status_t status;	f.buf = frame;	f.size = count * BYTES_PER_SAMPLE;	TRACE_((THIS_FILE, "  get_frame %.*s: count=%d", 		   (int)cport->name.slen, cport->name.ptr,		   count));	status = pjmedia_port_get_frame(cport->port, &f);	*type = f.type;	return status;    } else {	/*	 * If we don't have enough samples in rx_buf, read from the port 	 * first. Remember that rx_buf may be in different clock rate!	 */	while (cport->rx_buf_count < count * 1.0 *		cport->clock_rate / conf->clock_rate) {	    pjmedia_frame f;	    pj_status_t status;	    f.buf = cport->rx_buf + cport->rx_buf_count;	    f.size = cport->samples_per_frame * BYTES_PER_SAMPLE;	    TRACE_((THIS_FILE, "  get_frame, count=%d", 		       cport->samples_per_frame));	    status = pjmedia_port_get_frame(cport->port, &f);	    if (status != PJ_SUCCESS) {		/* Fatal error! */		return status;	    }	    if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) {		TRACE_((THIS_FILE, "  get_frame returned non-audio"));		pjmedia_zero_samples( cport->rx_buf + cport->rx_buf_count,				      cport->samples_per_frame);	    }	    cport->rx_buf_count += cport->samples_per_frame;	    TRACE_((THIS_FILE, "  rx buffer size is now %d",		    cport->rx_buf_count));	    pj_assert(cport->rx_buf_count <= cport->rx_buf_cap);	}	/*	 * If port's clock_rate is different, resample.	 * Otherwise just copy.	 */	if (cport->clock_rate != conf->clock_rate) {	    	    unsigned src_count;	    TRACE_((THIS_FILE, "  resample, input count=%d", 		    pjmedia_resample_get_input_size(cport->rx_resample)));	    pjmedia_resample_run( cport->rx_resample,cport->rx_buf, frame);	    src_count = (unsigned)(count * 1.0 * cport->clock_rate / 				   conf->clock_rate);	    cport->rx_buf_count -= src_count;	    if (cport->rx_buf_count) {		pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+src_count,				     cport->rx_buf_count);	    }	    TRACE_((THIS_FILE, "  rx buffer size is now %d",		    cport->rx_buf_count));	} else {	    pjmedia_copy_samples(frame, cport->rx_buf, count);	    cport->rx_buf_count -= count;	    if (cport->rx_buf_count) {		pjmedia_copy_samples(cport->rx_buf, cport->rx_buf+count,				     cport->rx_buf_count);	    }	}    }    return PJ_SUCCESS;}/* * Write the mixed signal to the port. */static pj_status_t write_port(pjmedia_conf *conf, struct conf_port *cport,			      const pj_timestamp *timestamp, 			      pjmedia_frame_type *frm_type){    pj_int16_t *buf;    unsigned j, ts;    pj_status_t status;    *frm_type = PJMEDIA_FRAME_TYPE_AUDIO;    /* If port is muted or nobody is transmitting to this port,      * transmit NULL frame.      */    if (cport->tx_setting == PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0) {	pjmedia_frame frame;	/* Adjust the timestamp */	frame.timestamp.u64 = timestamp->u64 * cport->clock_rate /				conf->clock_rate;	frame.type = PJMEDIA_FRAME_TYPE_NONE;	frame.buf = NULL;	frame.size = 0;	if (cport->port && cport->port->put_frame) {	    pjmedia_port_put_frame(cport->port, &frame);	}	cport->tx_level = 0;	*frm_type = PJMEDIA_FRAME_TYPE_NONE;	return PJ_SUCCESS;    } else if (cport->src_level==0) {	pjmedia_frame frame;	/* If silence is transmitted to this port, transmit silence	 * PCM frame (otherwise if we transmit NULL frame, nothing will	 * be written to WAV port). This would work with stream too	 * since stream has it's own silence detector.	 */	pjmedia_zero_samples((pj_int16_t*)cport->mix_buf, 			     cport->samples_per_frame);	/* Adjust the timestamp */	frame.timestamp.u64 = timestamp->u64 * cport->clock_rate /				conf->clock_rate;	frame.type = PJMEDIA_FRAME_TYPE_NONE;	frame.buf = (void*)cport->mix_buf;	frame.size = (cport->samples_per_frame << 1);	if (cport->port && cport->port->put_frame) {	    pjmedia_port_put_frame(cport->port, &frame);	}	cport->tx_level = 0;	*frm_type = PJMEDIA_FRAME_TYPE_NONE;	return PJ_SUCCESS;    } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) {	cport->tx_level = 0;	*frm_type = PJMEDIA_FRAME_TYPE_NONE;	return PJ_SUCCESS;    }    buf = (pj_int16_t*)cport->mix_buf;    /* This is the convention set in get_frame(). For optimization purpose,     * if we only have one transmitter transmitting to this port, then     * the transmitter will directly copy the original 16bit frame to     * mix_buf.     */    if (cport->transmitter_cnt==1 && cport->src_cnt == 1) {	/* But still see if we need to adjust the level */	if (cport->tx_adj_level != NORMAL_LEVEL) {	    pj_int16_t *input = buf;	    pj_int32_t adj = cport->tx_adj_level;	    for (j=0; j<conf->samples_per_frame; ++j) {		pj_int32_t itemp;		/* For the level adjustment, we need to store the sample to		 * a temporary 32bit integer value to avoid overflowing the		 * 16bit sample storage.		 */		itemp = input[j];		/*itemp = itemp * adj / NORMAL_LEVEL; */		itemp = (itemp * adj) >> 7;		/* Clip the signal if it's too loud */		if (itemp > 32767) itemp = 32767;		else if (itemp < -32768) itemp = -32768;		input[j] = (pj_int16_t) itemp;	    }	}    }     /* If there are sources in the mix buffer, convert the mixed samples     * to the mixed samples itself. This is possible because mixed sample     * is 32bit.     *     * In addition to this process, if we need to change the level of     * TX signal, we adjust is here too.     */    else if (cport->tx_adj_level != NORMAL_LEVEL && cport->src_level) {	pj_int32_t adj_level = cport->tx_adj_level;	/* We need to adjust signal level. */	for (j=0; j<conf->samples_per_frame; ++j) {	    pj_int32_t itemp;

⌨️ 快捷键说明

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