📄 conference.c
字号:
PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports",
max_ports));
/* Create and init conf structure. */
conf = PJ_POOL_ZALLOC_T(pool, pjmedia_conf);
PJ_ASSERT_RETURN(conf, PJ_ENOMEM);
conf->ports = (struct conf_port**)
pj_pool_zalloc(pool, max_ports*sizeof(void*));
PJ_ASSERT_RETURN(conf->ports, PJ_ENOMEM);
conf->options = options;
conf->max_ports = max_ports;
conf->clock_rate = clock_rate;
conf->channel_count = channel_count;
conf->samples_per_frame = samples_per_frame;
conf->bits_per_sample = bits_per_sample;
/* Create and initialize the master port interface. */
conf->master_port = PJ_POOL_ZALLOC_T(pool, pjmedia_port);
PJ_ASSERT_RETURN(conf->master_port, PJ_ENOMEM);
pjmedia_port_info_init(&conf->master_port->info, &name, SIGNATURE,
clock_rate, channel_count, bits_per_sample,
samples_per_frame);
conf->master_port->port_data.pdata = conf;
conf->master_port->port_data.ldata = 0;
conf->master_port->get_frame = &get_frame;
conf->master_port->put_frame = &put_frame;
conf->master_port->on_destroy = &destroy_port;
/* Create port zero for sound device. */
status = create_sound_port(pool, conf);
if (status != PJ_SUCCESS)
return status;
/* Create temporary buffer. */
conf->uns_buf = (pj_uint16_t*)
pj_pool_zalloc(pool, samples_per_frame *
sizeof(conf->uns_buf[0]));
/* Create mutex. */
status = pj_mutex_create_recursive(pool, "conf", &conf->mutex);
if (status != PJ_SUCCESS)
return status;
/* If sound device was created, connect sound device to the
* master port.
*/
if (conf->snd_dev_port) {
status = pjmedia_snd_port_connect( conf->snd_dev_port,
conf->master_port );
if (status != PJ_SUCCESS) {
pjmedia_conf_destroy(conf);
return status;
}
}
/* Done */
*p_conf = conf;
return PJ_SUCCESS;
}
/*
* Pause sound device.
*/
static pj_status_t pause_sound( pjmedia_conf *conf )
{
/* Do nothing. */
PJ_UNUSED_ARG(conf);
return PJ_SUCCESS;
}
/*
* Resume sound device.
*/
static pj_status_t resume_sound( pjmedia_conf *conf )
{
/* Do nothing. */
PJ_UNUSED_ARG(conf);
return PJ_SUCCESS;
}
/**
* Destroy conference bridge.
*/
PJ_DEF(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf )
{
PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL);
/* Destroy sound device port. */
if (conf->snd_dev_port) {
pjmedia_snd_port_destroy(conf->snd_dev_port);
conf->snd_dev_port = NULL;
}
/* Destroy mutex */
pj_mutex_destroy(conf->mutex);
return PJ_SUCCESS;
}
/*
* Destroy the master port (will destroy the conference)
*/
static pj_status_t destroy_port(pjmedia_port *this_port)
{
pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata;
return pjmedia_conf_destroy(conf);
}
/*
* Get port zero interface.
*/
PJ_DEF(pjmedia_port*) pjmedia_conf_get_master_port(pjmedia_conf *conf)
{
/* Sanity check. */
PJ_ASSERT_RETURN(conf != NULL, NULL);
/* Can only return port interface when PJMEDIA_CONF_NO_DEVICE was
* present in the option.
*/
PJ_ASSERT_RETURN((conf->options & PJMEDIA_CONF_NO_DEVICE) != 0, NULL);
return conf->master_port;
}
/*
* Set master port name.
*/
PJ_DEF(pj_status_t) pjmedia_conf_set_port0_name(pjmedia_conf *conf,
const pj_str_t *name)
{
unsigned len;
/* Sanity check. */
PJ_ASSERT_RETURN(conf != NULL && name != NULL, PJ_EINVAL);
len = name->slen;
if (len > sizeof(conf->master_name_buf))
len = sizeof(conf->master_name_buf);
if (len > 0) pj_memcpy(conf->master_name_buf, name->ptr, len);
conf->ports[0]->name.ptr = conf->master_name_buf;
conf->ports[0]->name.slen = len;
if (conf->master_port)
conf->master_port->info.name = conf->ports[0]->name;
return PJ_SUCCESS;
}
/*
* Add stream port to the conference bridge.
*/
PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf,
pj_pool_t *pool,
pjmedia_port *strm_port,
const pj_str_t *port_name,
unsigned *p_port )
{
struct conf_port *conf_port;
unsigned index;
pj_status_t status;
PJ_ASSERT_RETURN(conf && pool && strm_port, PJ_EINVAL);
/* If port_name is not specified, use the port's name */
if (!port_name)
port_name = &strm_port->info.name;
/* For this version of PJMEDIA, port MUST have the same number of
* PCM channels.
*/
if (strm_port->info.channel_count != conf->channel_count) {
pj_assert(!"Number of channels mismatch");
return PJMEDIA_ENCCHANNEL;
}
pj_mutex_lock(conf->mutex);
if (conf->port_cnt >= conf->max_ports) {
pj_assert(!"Too many ports");
pj_mutex_unlock(conf->mutex);
return PJ_ETOOMANY;
}
/* Find empty port in the conference bridge. */
for (index=0; index < conf->max_ports; ++index) {
if (conf->ports[index] == NULL)
break;
}
pj_assert(index != conf->max_ports);
/* Create conf port structure. */
status = create_conf_port(pool, conf, strm_port, port_name, &conf_port);
if (status != PJ_SUCCESS) {
pj_mutex_unlock(conf->mutex);
return status;
}
/* Put the port. */
conf->ports[index] = conf_port;
conf->port_cnt++;
/* Done. */
if (p_port) {
*p_port = index;
}
pj_mutex_unlock(conf->mutex);
return PJ_SUCCESS;
}
/*
* Add passive port.
*/
PJ_DEF(pj_status_t) pjmedia_conf_add_passive_port( pjmedia_conf *conf,
pj_pool_t *pool,
const pj_str_t *name,
unsigned clock_rate,
unsigned channel_count,
unsigned samples_per_frame,
unsigned bits_per_sample,
unsigned options,
unsigned *p_slot,
pjmedia_port **p_port )
{
struct conf_port *conf_port;
pjmedia_port *port;
unsigned index;
pj_str_t tmp;
pj_status_t status;
PJ_ASSERT_RETURN(conf && pool, PJ_EINVAL);
/* For this version of PJMEDIA, port MUST have the same number of
* PCM channels.
*/
if (channel_count != conf->channel_count) {
pj_assert(!"Number of channels mismatch");
return PJMEDIA_ENCCHANNEL;
}
/* For this version, options must be zero */
PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
PJ_UNUSED_ARG(options);
pj_mutex_lock(conf->mutex);
if (conf->port_cnt >= conf->max_ports) {
pj_assert(!"Too many ports");
pj_mutex_unlock(conf->mutex);
return PJ_ETOOMANY;
}
/* Find empty port in the conference bridge. */
for (index=0; index < conf->max_ports; ++index) {
if (conf->ports[index] == NULL)
break;
}
pj_assert(index != conf->max_ports);
if (name == NULL) {
name = &tmp;
tmp.ptr = (char*) pj_pool_alloc(pool, 32);
tmp.slen = pj_ansi_snprintf(tmp.ptr, 32, "ConfPort#%d", index);
}
/* Create and initialize the media port structure. */
port = PJ_POOL_ZALLOC_T(pool, pjmedia_port);
PJ_ASSERT_RETURN(port, PJ_ENOMEM);
pjmedia_port_info_init(&port->info, name, SIGNATURE_PORT,
clock_rate, channel_count, bits_per_sample,
samples_per_frame);
port->port_data.pdata = conf;
port->port_data.ldata = index;
port->get_frame = &get_frame_pasv;
port->put_frame = &put_frame;
port->on_destroy = NULL;
/* Create conf port structure. */
status = create_pasv_port(conf, pool, name, port, &conf_port);
if (status != PJ_SUCCESS) {
pj_mutex_unlock(conf->mutex);
return status;
}
/* Put the port. */
conf->ports[index] = conf_port;
conf->port_cnt++;
/* Done. */
if (p_slot)
*p_slot = index;
if (p_port)
*p_port = port;
pj_mutex_unlock(conf->mutex);
return PJ_SUCCESS;
}
/*
* Change TX and RX settings for the port.
*/
PJ_DECL(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf,
unsigned slot,
pjmedia_port_op tx,
pjmedia_port_op rx)
{
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 != PJMEDIA_PORT_NO_CHANGE)
conf_port->tx_setting = tx;
if (rx != PJMEDIA_PORT_NO_CHANGE)
conf_port->rx_setting = rx;
return PJ_SUCCESS;
}
/*
* Connect port.
*/
PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf,
unsigned src_slot,
unsigned sink_slot,
int level )
{
struct conf_port *src_port, *dst_port;
pj_bool_t start_sound = PJ_FALSE;
unsigned i;
/* Check arguments */
PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&
sink_slot<conf->max_ports, PJ_EINVAL);
/* Ports must be valid. */
PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL);
PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL);
/* For now, level MUST be zero. */
PJ_ASSERT_RETURN(level == 0, PJ_EINVAL);
pj_mutex_lock(conf->mutex);
src_port = conf->ports[src_slot];
dst_port = conf->ports[sink_slot];
/* Check if connection has been made */
for (i=0; i<src_port->listener_cnt; ++i) {
if (src_port->listener_slots[i] == sink_slot)
break;
}
if (i == src_port->listener_cnt) {
src_port->listener_slots[src_port->listener_cnt] = sink_slot;
++conf->connect_cnt;
++src_port->listener_cnt;
++dst_port->transmitter_cnt;
if (conf->connect_cnt == 1)
start_sound = 1;
PJ_LOG(4,(THIS_FILE,"Port %d (%.*s) transmitting to port %d (%.*s)",
src_slot,
(int)src_port->name.slen,
src_port->name.ptr,
sink_slot,
(int)dst_port->name.slen,
dst_port->name.ptr));
}
pj_mutex_unlock(conf->mutex);
/* Sound device must be started without mutex, otherwise the
* sound thread will deadlock (?)
*/
if (start_sound)
resume_sound(conf);
return PJ_SUCCESS;
}
/*
* Disconnect port
*/
PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
unsigned src_slot,
unsigned sink_slot )
{
struct conf_port *src_port, *dst_port;
unsigned i;
/* Check arguments */
PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports &&
sink_slot<conf->max_ports, PJ_EINVAL);
/* Ports must be valid. */
PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL);
PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL);
pj_mutex_lock(conf->mutex);
src_port = conf->ports[src_slot];
dst_port = conf->ports[sink_slot];
/* Check if connection has been made */
for (i=0; i<src_port->listener_cnt; ++i) {
if (src_port->listener_slots[i] == sink_slot)
break;
}
if (i != src_port->listener_cnt) {
pj_assert(src_port->listener_cnt > 0 &&
src_port->listener_cnt < conf->max_ports);
pj_assert(dst_port->transmitter_cnt > 0 &&
dst_port->transmitter_cnt < conf->max_ports);
pj_array_erase(src_port->listener_slots, sizeof(SLOT_TYPE),
src_port->listener_cnt, i);
--conf->connect_cnt;
--src_port->listener_cnt;
--dst_port->transmitter_cnt;
PJ_LOG(4,(THIS_FILE,
"Port %d (%.*s) stop transmitting to port %d (%.*s)",
src_slot,
(int)src_port->name.slen,
src_port->name.ptr,
sink_slot,
(int)dst_port->name.slen,
dst_port->name.ptr));
}
pj_mutex_unlock(conf->mutex);
if (conf->connect_cnt == 0) {
pause_sound(conf);
}
return PJ_SUCCESS;
}
/*
* Get number of ports currently registered to the conference bridge.
*/
PJ_DEF(unsigned) pjmedia_conf_get_port_count(pjmedia_conf *conf)
{
return conf->port_cnt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -