⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 conference.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}

/*
 * Get total number of ports connections currently set up in the bridge.
 */
PJ_DECL(unsigned) pjmedia_conf_get_connect_count(pjmedia_conf *conf)
{
    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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -