📄 conference.c
字号:
}
/*
* 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 + -