Beispiel #1
0
/*
 * Create the ZRTP transport.
 */
PJ_DEF(pj_status_t) pjmedia_transport_zrtp_create(pjmedia_endpt *endpt,
        const char *name,
        pjmedia_transport *transport,
        pjmedia_transport **p_tp,
        pj_bool_t close_slave)
{
    pj_pool_t *pool;
    struct tp_zrtp *zrtp;
    pj_status_t rc;

    if (name == NULL)
        name = "tzrtp%p";

    /* Create the pool and initialize the adapter structure */
    pool = pjmedia_endpt_create_pool(endpt, name, 5*1024, 512);
    zrtp = PJ_POOL_ZALLOC_T(pool, struct tp_zrtp);
    zrtp->pool = pool;
    pj_ansi_strncpy(zrtp->base.name, pool->obj_name,
                    sizeof(zrtp->base.name));
    zrtp->base.type = (pjmedia_transport_type)
                      (PJMEDIA_TRANSPORT_TYPE_USER + 2);
    zrtp->base.op = &tp_zrtp_op;

#ifndef DYNAMIC_TIMER
    if (timer_pool == NULL)
    {
        timer_pool = pjmedia_endpt_create_pool(endpt, "zrtp_timer", 256, 256);
        rc = timer_initialize();
        if (rc != PJ_SUCCESS)
        {
            pj_pool_release(timer_pool);
            pj_pool_release(zrtp->pool);
            return rc;
        }
    }
#else
    zrtp->timer_heap = pjsip_endpt_get_timer_heap(pjsua_var.endpt);
#endif

    /* Create the empty wrapper */
    zrtp->zrtpCtx = zrtp_CreateWrapper();

    /* Initialize standard values */
    zrtp->clientIdString = clientId;    /* Set standard name */
    zrtp->zrtpSeq = 1;                  /* TODO: randomize */
    rc = pj_mutex_create_simple(zrtp->pool, "zrtp", &zrtp->zrtpMutex);
    zrtp->zrtpBuffer = pj_pool_zalloc(pool, MAX_ZRTP_SIZE);
    zrtp->sendBuffer = pj_pool_zalloc(pool, MAX_RTP_BUFFER_LEN);
    zrtp->sendBufferCtrl = pj_pool_zalloc(pool, MAX_RTCP_BUFFER_LEN);

    zrtp->slave_tp = transport;
    zrtp->close_slave = close_slave;
    zrtp->mitmMode = PJ_FALSE;

    /* Done */
    zrtp->refcount++;
    *p_tp = &zrtp->base;
    return PJ_SUCCESS;
}
Beispiel #2
0
/*
 * Allocate a new Opus codec instance.
 */
static pj_status_t factory_alloc_codec( pjmedia_codec_factory *factory, 
					const pjmedia_codec_info *ci, 
					pjmedia_codec **p_codec )
{
    pjmedia_codec *codec;
    pj_pool_t *pool;
    pj_status_t status;
    struct opus_data *opus_data;
    struct opus_codec_factory *f = (struct opus_codec_factory*) factory;

    TRACE_((THIS_FILE, "%s:%d: - TRACE", __FUNCTION__, __LINE__));

    pool = pjmedia_endpt_create_pool(f->endpt, "opus", 512, 512);
    if (!pool) return PJ_ENOMEM;
    
    opus_data = PJ_POOL_ZALLOC_T(pool, struct opus_data);
    codec     = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);

    status = pj_mutex_create_simple (pool, "opus_mutex", &opus_data->mutex);
    if (status != PJ_SUCCESS) {
    	pj_pool_release(pool);
    	return status;
    }

    pj_memcpy(&opus_data->cfg, &opus_cfg, sizeof(pjmedia_codec_opus_config));
    opus_data->pool      = pool;
    codec->op            = &opus_op;
    codec->factory       = factory;
    codec->codec_data    = opus_data;

    *p_codec = codec;
    return PJ_SUCCESS;
}
/*
 * Create the adapter.
 */
PJ_DEF(pj_status_t) pjmedia_tp_adapter_create( pjmedia_endpt *endpt,
        const char *name,
        pjmedia_transport *transport,
        pj_bool_t del_base,
        pjmedia_transport **p_tp)
{
    pj_pool_t *pool;
    struct tp_adapter *adapter;

    if (name == NULL)
        name = "tpad%p";

    /* Create the pool and initialize the adapter structure */
    pool = pjmedia_endpt_create_pool(endpt, name, 512, 512);
    adapter = PJ_POOL_ZALLOC_T(pool, struct tp_adapter);
    adapter->pool = pool;
    pj_ansi_strncpy(adapter->base.name, pool->obj_name,
                    sizeof(adapter->base.name));
    adapter->base.type = (pjmedia_transport_type)
                         (PJMEDIA_TRANSPORT_TYPE_USER + 1);
    adapter->base.op = &tp_adapter_op;

    /* Save the transport as the slave transport */
    adapter->slave_tp = transport;
    adapter->del_base = del_base;

    /* Done */
    *p_tp = &adapter->base;
    return PJ_SUCCESS;
}
Beispiel #4
0
/*
 * Allocate a new iLBC codec instance.
 */
static pj_status_t ilbc_alloc_codec(pjmedia_codec_factory *factory, 
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pj_pool_t *pool;
    struct ilbc_codec *codec;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &ilbc_factory.base, PJ_EINVAL);

    pool = pjmedia_endpt_create_pool(ilbc_factory.endpt, "iLBC%p",
				     2000, 2000);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    codec = PJ_POOL_ZALLOC_T(pool, struct ilbc_codec);
    codec->base.op = &ilbc_op;
    codec->base.factory = factory;
    codec->pool = pool;

    pj_ansi_snprintf(codec->obj_name,  sizeof(codec->obj_name),
		     "ilbc%p", codec);

    *p_codec = &codec->base;
    return PJ_SUCCESS;
}
Beispiel #5
0
/*
 * Allocate a new SILK codec instance.
 */
static pj_status_t silk_alloc_codec(pjmedia_codec_factory *factory,
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pj_pool_t *pool;
    pjmedia_codec *codec;
    silk_private *silk;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &silk_factory.base, PJ_EINVAL);

    /* Create pool for codec instance */
    pool = pjmedia_endpt_create_pool(silk_factory.endpt, "silk", 512, 512);

    /* Allocate codec */
    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
    codec->op = &silk_op;
    codec->factory = factory;
    codec->codec_data = PJ_POOL_ZALLOC_T(pool, silk_private);
    silk = (silk_private*) codec->codec_data;
    silk->pool = pool;
    silk->enc_ready = PJ_FALSE;
    silk->dec_ready = PJ_FALSE;
    silk->mode = silk_get_mode_from_clock_rate(id->clock_rate);

    *p_codec = codec;
    return PJ_SUCCESS;
}
Beispiel #6
0
/*
 * Initialize and register AMR codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amr_init( pjmedia_endpt *endpt,
                                                     unsigned options)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_str_t codec_name;
    pj_status_t status;

    if (amr_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create AMR codec factory. */
    amr_codec_factory.base.op = &amr_factory_op;
    amr_codec_factory.base.factory_data = NULL;
    amr_codec_factory.endpt = endpt;
#ifdef USE_AMRNB
    amr_codec_factory.init[IDX_AMR_NB] = ((options & PJMEDIA_AMR_NO_NB) == 0);
#else
    amr_codec_factory.init[IDX_AMR_NB] = PJ_FALSE;
#endif
#ifdef USE_AMRWB
    amr_codec_factory.init[IDX_AMR_WB] = ((options & PJMEDIA_AMR_NO_WB) == 0);
#else
    amr_codec_factory.init[IDX_AMR_WB] = PJ_FALSE;
#endif

    amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amr", 1000,
						       1000);
    if (!amr_codec_factory.pool)
	return PJ_ENOMEM;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Register format match callback. */
    pj_cstr(&codec_name, "AMR");
    status = pjmedia_sdp_neg_register_fmt_match_cb(
					&codec_name,
					&pjmedia_codec_amr_match_sdp);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&amr_codec_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(amr_codec_factory.pool);
    amr_codec_factory.pool = NULL;
    return status;
}
PJ_DEF(pj_status_t) pjmedia_codec_l16_init(pjmedia_endpt *endpt,
					   unsigned options)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;


    PJ_UNUSED_ARG(options);


    if (l16_factory.endpt != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Init factory */
    l16_factory.base.op = &l16_factory_op;
    l16_factory.base.factory_data = NULL;
    l16_factory.endpt = endpt;

    /* Create pool */
    l16_factory.pool = pjmedia_endpt_create_pool(endpt, "l16", 4000, 4000);
    if (!l16_factory.pool)
	return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(l16_factory.pool, "l16", 
				    &l16_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	return PJ_EINVALIDOP;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&l16_factory.base);
    if (status != PJ_SUCCESS)
	return status;


    return PJ_SUCCESS;

on_error:
    if (l16_factory.mutex) {
	pj_mutex_destroy(l16_factory.mutex);
	l16_factory.mutex = NULL;
    }
    if (l16_factory.pool) {
	pj_pool_release(l16_factory.pool);
	l16_factory.pool = NULL;
    }
    return status;
}
static pj_status_t l16_alloc_codec( pjmedia_codec_factory *factory, 
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pjmedia_codec *codec = NULL;
    struct l16_data *data;
    unsigned ptime;
    pj_pool_t *pool;

    pj_status_t status;

    PJ_ASSERT_RETURN(factory==&l16_factory.base, PJ_EINVAL);

    /* Lock mutex. */
    pj_mutex_lock(l16_factory.mutex);


    pool = pjmedia_endpt_create_pool(l16_factory.endpt, "l16", 4000, 4000);
    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
    codec->codec_data = pj_pool_alloc(pool, sizeof(struct l16_data));
    codec->factory = factory;
    codec->op = &l16_op;

    /* Init private data */
    ptime = GET_PTIME(id->clock_rate);
    data = (struct l16_data*) codec->codec_data;
    data->frame_size = ptime * id->clock_rate * id->channel_cnt * 2 / 1000;
    data->clock_rate = id->clock_rate;
    data->pool = pool;

#if !PLC_DISABLED
    /* Create PLC */
    status = pjmedia_plc_create(pool, id->clock_rate, 
				data->frame_size >> 1, 0, 
				&data->plc);
    if (status != PJ_SUCCESS) {
	pj_mutex_unlock(l16_factory.mutex);
	return status;
    }
#endif

    /* Create silence detector */
    status = pjmedia_silence_det_create(pool, id->clock_rate, 
					data->frame_size >> 1,
					&data->vad);
    if (status != PJ_SUCCESS) {
	pj_mutex_unlock(l16_factory.mutex);
	return status;
    }

    *p_codec = codec;

    /* Unlock mutex. */
    pj_mutex_unlock(l16_factory.mutex);

    return PJ_SUCCESS;
}
Beispiel #9
0
PJ_DEF(pj_status_t) pjmedia_codec_opus_init(pjmedia_endpt *endpt) {
  pjmedia_codec_mgr *codec_mgr;
  pj_status_t status;

  if (opus_factory.endpt != NULL) {
    /* Already initialized. */
    return PJ_SUCCESS;
  }

  /* Init factory */
  opus_factory.base.op = &opus_factory_op;
  opus_factory.base.factory_data = NULL;
  opus_factory.endpt = endpt;
  if (opus_factory.internal_clock_rate == 0) {
    opus_factory.internal_clock_rate = 48000;
  }

  /* Create pool */
  opus_factory.pool =
      pjmedia_endpt_create_pool(endpt, "opus codecs", 4000, 4000);
  if (!opus_factory.pool) return PJ_ENOMEM;

  /* Init list */
  pj_list_init(&opus_factory.codec_list);

  /* Create mutex. */
  status = pj_mutex_create_simple(opus_factory.pool, "opus codecs",
                                  &opus_factory.mutex);
  if (status != PJ_SUCCESS) goto on_error;
  PJ_LOG(5, (THIS_FILE, "Init opus"));

  /* Get the codec manager. */
  codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
  if (!codec_mgr) {
    return PJ_EINVALIDOP;
  }

  PJ_LOG(5, (THIS_FILE, "Init opus > DONE"));

  /* Register codec factory to endpoint. */
  status = pjmedia_codec_mgr_register_factory(codec_mgr, &opus_factory.base);
  if (status != PJ_SUCCESS) return status;

  return PJ_SUCCESS;

on_error:
  if (opus_factory.mutex) {
    pj_mutex_destroy(opus_factory.mutex);
    opus_factory.mutex = NULL;
  }
  if (opus_factory.pool) {
    pj_pool_release(opus_factory.pool);
    opus_factory.pool = NULL;
  }

  return status;
}
Beispiel #10
0
/*
 * Create ICE media transport.
 */
PJ_DEF(pj_status_t) pjmedia_ice_create2(pjmedia_endpt *endpt,
				        const char *name,
				        unsigned comp_cnt,
				        const pj_ice_strans_cfg *cfg,
				        const pjmedia_ice_cb *cb,
					unsigned options,
	    			        pjmedia_transport **p_tp)
{
    pj_pool_t *pool;
    pj_ice_strans_cb ice_st_cb;
    struct transport_ice *tp_ice;
    pj_status_t status;

    PJ_ASSERT_RETURN(endpt && comp_cnt && cfg && p_tp, PJ_EINVAL);

    /* Create transport instance */
    pool = pjmedia_endpt_create_pool(endpt, name, 512, 512);
    tp_ice = PJ_POOL_ZALLOC_T(pool, struct transport_ice);
    tp_ice->pool = pool;
    tp_ice->af = cfg->af;
    tp_ice->options = options;
    tp_ice->comp_cnt = comp_cnt;
    pj_ansi_strcpy(tp_ice->base.name, pool->obj_name);
    tp_ice->base.op = &transport_ice_op;
    tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE;
    tp_ice->initial_sdp = PJ_TRUE;
    tp_ice->oa_role = ROLE_NONE;
    tp_ice->use_ice = PJ_FALSE;

    if (cb)
	pj_memcpy(&tp_ice->cb, cb, sizeof(pjmedia_ice_cb));

    /* Assign return value first because ICE might call callback
     * in create()
     */
    *p_tp = &tp_ice->base;

    /* Configure ICE callbacks */
    pj_bzero(&ice_st_cb, sizeof(ice_st_cb));
    ice_st_cb.on_ice_complete = &ice_on_ice_complete;
    ice_st_cb.on_rx_data = &ice_on_rx_data;

    /* Create ICE */
    status = pj_ice_strans_create(name, cfg, comp_cnt, tp_ice, 
				  &ice_st_cb, &tp_ice->ice_st);
    if (status != PJ_SUCCESS) {
	pj_pool_release(pool);
	*p_tp = NULL;
	return status;
    }

    /* Done */
    return PJ_SUCCESS;
}
Beispiel #11
0
PJ_DEF(pj_status_t) pjmedia_codec_g711_init(pjmedia_endpt *endpt)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (g711_factory.endpt != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Init factory */
    g711_factory.base.op = &g711_factory_op;
    g711_factory.base.factory_data = NULL;
    g711_factory.endpt = endpt;

    pj_list_init(&g711_factory.codec_list);

    /* Create pool */
    g711_factory.pool = pjmedia_endpt_create_pool(endpt, "g711", 4000, 4000);
    if (!g711_factory.pool)
	return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(g711_factory.pool, "g611", 
				    &g711_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	return PJ_EINVALIDOP;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&g711_factory.base);
    if (status != PJ_SUCCESS)
	return status;


    return PJ_SUCCESS;

on_error:
    if (g711_factory.mutex) {
	pj_mutex_destroy(g711_factory.mutex);
	g711_factory.mutex = NULL;
    }
    if (g711_factory.pool) {
	pj_pool_release(g711_factory.pool);
	g711_factory.pool = NULL;
    }
    return status;
}
Beispiel #12
0
/*
 * Initialize and register G722 codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_g722_init( pjmedia_endpt *endpt )
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (g722_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create G722 codec factory. */
    g722_codec_factory.base.op = &g722_factory_op;
    g722_codec_factory.base.factory_data = NULL;
    g722_codec_factory.endpt = endpt;
    g722_codec_factory.pcm_shift = PJMEDIA_G722_DEFAULT_PCM_SHIFT;

    g722_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g722", 1000, 
						        1000);
    if (!g722_codec_factory.pool)
	return PJ_ENOMEM;

    pj_list_init(&g722_codec_factory.codec_list);

    /* Create mutex. */
    status = pj_mutex_create_simple(g722_codec_factory.pool, "g722", 
				    &g722_codec_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&g722_codec_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    TRACE_((THIS_FILE, "G722 codec factory initialized"));
    
    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(g722_codec_factory.pool);
    g722_codec_factory.pool = NULL;
    return status;
}
Beispiel #13
0
/*
 * Initialize and register GSM codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_gsm_init( pjmedia_endpt *endpt )
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (gsm_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create GSM codec factory. */
    gsm_codec_factory.base.op = &gsm_factory_op;
    gsm_codec_factory.base.factory_data = NULL;
    gsm_codec_factory.endpt = endpt;

    gsm_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "gsm", 4000, 
						       4000);
    if (!gsm_codec_factory.pool)
	return PJ_ENOMEM;

    pj_list_init(&gsm_codec_factory.codec_list);

    /* Create mutex. */
    status = pj_mutex_create_simple(gsm_codec_factory.pool, "gsm", 
				    &gsm_codec_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&gsm_codec_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(gsm_codec_factory.pool);
    gsm_codec_factory.pool = NULL;
    return status;
}
/*
 * Initialize and register AMR-NB codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_opencore_amrnb_init( pjmedia_endpt *endpt )
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;
    pj_str_t codec_name;

    if (amr_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create AMR-NB codec factory. */
    amr_codec_factory.base.op = &amr_factory_op;
    amr_codec_factory.base.factory_data = NULL;
    amr_codec_factory.endpt = endpt;

    amr_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "amrnb", 1000,
						       1000);
    if (!amr_codec_factory.pool)
	return PJ_ENOMEM;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }
    /* Register format match callback. */
    pj_cstr(&codec_name, "AMR");
    status = pjmedia_sdp_neg_register_fmt_match_cb( &codec_name,
    		&pjmedia_codec_amr_match_sdp);
    if (status != PJ_SUCCESS){
    	goto on_error;
    }
    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr,
						&amr_codec_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(amr_codec_factory.pool);
    amr_codec_factory.pool = NULL;
    return status;
}
Beispiel #15
0
/*
 * Initialize and register Opus codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_opus_init( pjmedia_endpt *endpt )
{
    pj_status_t status;
    pjmedia_codec_mgr *codec_mgr;

    PJ_ASSERT_RETURN(endpt, PJ_EINVAL);

    if (opus_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create the Opus codec factory */
    opus_codec_factory.base.op           = &opus_factory_op;
    opus_codec_factory.base.factory_data = &opus_codec_factory;
    opus_codec_factory.endpt             = endpt;

    opus_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "opus-factory",
    							1024, 1024);
    if (!opus_codec_factory.pool) {
	PJ_LOG(2, (THIS_FILE, "Unable to create memory pool for Opus codec"));
	return PJ_ENOMEM;
    }

    /* Get the codec manager */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	PJ_LOG(2, (THIS_FILE, "Unable to get the codec manager"));
	status = PJ_EINVALIDOP;
	goto on_codec_factory_error;
    }

    /* Register the codec factory */
    status = pjmedia_codec_mgr_register_factory (codec_mgr,
						 &opus_codec_factory.base);
    if (status != PJ_SUCCESS) {
	PJ_LOG(2, (THIS_FILE, "Unable to register the codec factory"));
	goto on_codec_factory_error;
    }

    return PJ_SUCCESS;

on_codec_factory_error:
    pj_pool_release(opus_codec_factory.pool);
    opus_codec_factory.pool = NULL;
    return status;
}
Beispiel #16
0
/*
 * Allocate a new G726 codec instance.
 */
static pj_status_t g726_alloc_codec( pjmedia_codec_factory *factory, 
				     const pjmedia_codec_info *id,
				     pjmedia_codec **p_codec)
{
    pj_pool_t *pool;
    pjmedia_codec *codec;
    struct g726_private *priv;
    pj_status_t status;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &g726_codec_factory.base, PJ_EINVAL);

    pool = pjmedia_endpt_create_pool(g726_codec_factory.endpt, "g726-inst", 512, 512);

    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
    PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
    codec->op = &g726_op;
    codec->factory = factory;

    priv = PJ_POOL_ZALLOC_T(pool, struct g726_private);
    priv->pool = pool;
    codec->codec_data = priv;

#if USE_PJMEDIA_PLC
    /* Create PLC */
    status = pjmedia_plc_create(pool, SAMPLE_RATE, SAMPLES_PER_FRAME, 0, &priv->plc);
    if (status != PJ_SUCCESS) {
	return status;
    }
#else
    PJ_UNUSED_ARG(status);
#endif

    /* Create VAD */
    status = pjmedia_silence_det_create(pool, SAMPLE_RATE,
					SAMPLES_PER_FRAME, &priv->vad);
    if (status != PJ_SUCCESS) {
	return status;
    }

    *p_codec = codec;
    return PJ_SUCCESS;
}
/*
 * Allocate a new AMR-NB codec instance.
 */
static pj_status_t amr_alloc_codec( pjmedia_codec_factory *factory,
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pj_pool_t *pool;
    pjmedia_codec *codec;
    struct amr_data *amr_data;
    pj_status_t status = PJ_SUCCESS;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &amr_codec_factory.base, PJ_EINVAL);

    pool = pjmedia_endpt_create_pool(amr_codec_factory.endpt, "amrnb-inst",
				     512, 512);

    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
    PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
    codec->op = &amr_op;
    codec->factory = factory;

    amr_data = PJ_POOL_ZALLOC_T(pool, struct amr_data);
    codec->codec_data = amr_data;
    amr_data->pool = pool;

#if USE_PJMEDIA_PLC
    /* Create PLC */
    status = pjmedia_plc_create(pool, 8000, 160, 0, &amr_data->plc);
    if (status != PJ_SUCCESS) {
	return status;
    }
#else
    PJ_UNUSED_ARG(status);
#endif

    status = dlsym_stagefright(amr_data);
    if(status != PJ_SUCCESS){
    	return status;
    }

    *p_codec = codec;
    return PJ_SUCCESS;
}
Beispiel #18
0
/*
 * Allocate a new SILK codec instance.
 */
static pj_status_t silk_alloc_codec(pjmedia_codec_factory *factory,
				    const pjmedia_codec_info *id,
				    pjmedia_codec **p_codec)
{
    pjmedia_codec *codec;
    struct silk_private *silk;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory == &silk_factory.base, PJ_EINVAL);


    pj_mutex_lock(silk_factory.mutex);

    /* Get free nodes, if any. */
    if (!pj_list_empty(&silk_factory.codec_list)) {
		codec = silk_factory.codec_list.next;
		pj_list_erase(codec);
    } else {
		codec = PJ_POOL_ZALLOC_T(silk_factory.pool, pjmedia_codec);
		PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
		codec->op = &silk_op;
		codec->factory = factory;
		codec->codec_data = pj_pool_alloc(silk_factory.pool,
						  sizeof(struct silk_private));
    }

    pj_mutex_unlock(silk_factory.mutex);

    silk = (struct silk_private*) codec->codec_data;
    silk->enc_ready = PJ_FALSE;
    silk->dec_ready = PJ_FALSE;
    silk->param_id = silk_get_type_for_clock_rate(id->clock_rate);

    /* Create pool for codec instance */
    silk->pool = pjmedia_endpt_create_pool(silk_factory.endpt, "silkcodec", 512, 512);

    *p_codec = codec;
    return PJ_SUCCESS;
}
Beispiel #19
0
/*
 * Initialize and register G726 codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_g726_init( pjmedia_endpt *endpt )
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (g726_codec_factory.pool != NULL)
	return PJ_SUCCESS;

    /* Create G726 codec factory. */
    g726_codec_factory.base.op = &g726_factory_op;
    g726_codec_factory.base.factory_data = NULL;
    g726_codec_factory.endpt = endpt;

    g726_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "g726", 512, 512);
    if (!g726_codec_factory.pool)
	return PJ_ENOMEM;

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&g726_codec_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(g726_codec_factory.pool);
    g726_codec_factory.pool = NULL;
    return status;
}
Beispiel #20
0
/*
 * Allocate a new OPUS codec instance.
 */
static pj_status_t opus_alloc_codec(pjmedia_codec_factory *factory,
                                    const pjmedia_codec_info *id,
                                    pjmedia_codec **p_codec) {
  pjmedia_codec *codec;
  struct opus_private *opus;

  PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
  PJ_ASSERT_RETURN(factory == &opus_factory.base, PJ_EINVAL);

  pj_mutex_lock(opus_factory.mutex);

  /* Get free nodes, if any. */
  if (!pj_list_empty(&opus_factory.codec_list)) {
    codec = opus_factory.codec_list.next;
    pj_list_erase(codec);
  } else {
    codec = PJ_POOL_ZALLOC_T(opus_factory.pool, pjmedia_codec);
    PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
    codec->op = &opus_op;
    codec->factory = factory;
    codec->codec_data =
        pj_pool_alloc(opus_factory.pool, sizeof(struct opus_private));
  }

  pj_mutex_unlock(opus_factory.mutex);

  opus = (struct opus_private *)codec->codec_data;
  opus->enc_ready = PJ_FALSE;
  opus->dec_ready = PJ_FALSE;

  /* Create pool for codec instance */
  opus->pool =
      pjmedia_endpt_create_pool(opus_factory.endpt, "opuscodec", 512, 512);

  *p_codec = codec;
  return PJ_SUCCESS;
}
Beispiel #21
0
/**
 * Create loopback transport.
 */
PJ_DEF(pj_status_t) pjmedia_transport_loop_create(pjmedia_endpt *endpt,
						  pjmedia_transport **p_tp)
{
    struct transport_loop *tp;
    pj_pool_t *pool;

    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && p_tp, PJ_EINVAL);

    /* Create transport structure */
    pool = pjmedia_endpt_create_pool(endpt, "tploop", 512, 512);
    if (!pool)
	return PJ_ENOMEM;

    tp = PJ_POOL_ZALLOC_T(pool, struct transport_loop);
    tp->pool = pool;
    pj_ansi_strncpy(tp->base.name, tp->pool->obj_name, PJ_MAX_OBJ_NAME-1);
    tp->base.op = &transport_udp_op;
    tp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;

    /* Done */
    *p_tp = &tp->base;
    return PJ_SUCCESS;
}
Beispiel #22
0
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt)
{
    pjmedia_codec_mgr *codec_mgr;
    silk_param *sp;
    pj_status_t status;

    if (silk_factory.endpt != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Init factory */
    pj_bzero(&silk_factory, sizeof(silk_factory));
    silk_factory.base.op = &silk_factory_op;
    silk_factory.base.factory_data = NULL;
    silk_factory.endpt = endpt;

    /* Create pool */
    silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk", 4000, 4000);
    if (!silk_factory.pool)
	return PJ_ENOMEM;

    /* Create mutex. */
    status = pj_mutex_create_simple(silk_factory.pool, "silk",
				    &silk_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Initialize default codec params */

    /* From SILK docs:
       - SILK bitrate tables:
         +----------------+---------+-----------+
         |                | fs (Hz) | BR (kbps) |
         +----------------+---------+-----------+
         |   Narrowband   |   8000  |   6 - 20  |
         |   Mediumband   |  12000  |   7 - 25  |
         |    Wideband    |  16000  |   8 - 30  |
         | Super Wideband |  24000  |  12 - 40  |
         +----------------+---------+-----------+
       - The upper limits of the bit rate ranges in this table are
         recommended values.
     */

    sp = &silk_factory.silk_param[PARAM_NB];
    sp->pt = PJMEDIA_RTP_PT_SILK_NB;
    sp->clock_rate = 8000;
    sp->max_bitrate = 22000;
    sp->bitrate = CALC_BITRATE(sp->max_bitrate);
    sp->ptime = FRAME_LENGTH_MS;
    sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY;
    sp->enabled = 1;

    sp = &silk_factory.silk_param[PARAM_MB];
    sp->pt = PJMEDIA_RTP_PT_SILK_MB;
    sp->clock_rate = 12000;
    sp->max_bitrate = 28000;
    sp->bitrate = CALC_BITRATE(sp->max_bitrate);
    sp->ptime = FRAME_LENGTH_MS;
    sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY;
    sp->enabled = 0;

    sp = &silk_factory.silk_param[PARAM_WB];
    sp->pt = PJMEDIA_RTP_PT_SILK_WB;
    sp->clock_rate = 16000;
    sp->max_bitrate = 36000;
    sp->bitrate = CALC_BITRATE(sp->max_bitrate);
    sp->ptime = FRAME_LENGTH_MS;
    sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY;
    sp->enabled = 1;

    sp = &silk_factory.silk_param[PARAM_SWB];
    sp->pt = PJMEDIA_RTP_PT_SILK_SWB;
    sp->clock_rate = 24000;
    sp->max_bitrate = 46000;
    sp->bitrate = CALC_BITRATE(sp->max_bitrate);
    sp->ptime = FRAME_LENGTH_MS;
    sp->complexity = PJMEDIA_CODEC_SILK_DEFAULT_COMPLEXITY;
    sp->enabled = 0;


    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	return PJ_EINVALIDOP;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr,
						&silk_factory.base);
    if (status != PJ_SUCCESS)
	return status;

    PJ_LOG(4,(THIS_FILE, "SILK codec version %s initialized",
	      SKP_Silk_SDK_get_version()));
    return PJ_SUCCESS;

on_error:
    if (silk_factory.mutex) {
	pj_mutex_destroy(silk_factory.mutex);
	silk_factory.mutex = NULL;
    }
    if (silk_factory.pool) {
	pj_pool_release(silk_factory.pool);
	silk_factory.pool = NULL;
    }

    return status;
}
Beispiel #23
0
/*
 * main()
 *
 * If called with argument, treat argument as SIP URL to be called.
 * Otherwise wait for incoming calls.
 */
int main(int argc, char *argv[])
{
    pj_pool_t *pool = NULL;
    pj_status_t status;
    unsigned i;

    /* Must init PJLIB first: */
    status = pj_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    pj_log_set_level(5);

    /* Then init PJLIB-UTIL: */
    status = pjlib_util_init();
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);


    /* Create global endpoint: */
    {
	const pj_str_t *hostname;
	const char *endpt_name;

	/* Endpoint MUST be assigned a globally unique name.
	 * The name will be used as the hostname in Warning header.
	 */

	/* For this implementation, we'll use hostname for simplicity */
	hostname = pj_gethostname();
	endpt_name = hostname->ptr;

	/* Create the endpoint: */

	status = pjsip_endpt_create(&cp.factory, endpt_name, 
				    &g_endpt);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }


    /* 
     * Add UDP transport, with hard-coded port 
     * Alternatively, application can use pjsip_udp_transport_attach() to
     * start UDP transport, if it already has an UDP socket (e.g. after it
     * resolves the address with STUN).
     */
    {
	pj_sockaddr addr;

	pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
	
	if (AF == pj_AF_INET()) {
	    status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL, 
						1, NULL);
	} else if (AF == pj_AF_INET6()) {
	    status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL,
						1, NULL);
	} else {
	    status = PJ_EAFNOTSUP;
	}

	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to start UDP transport", status);
	    return 1;
	}
    }


    /* 
     * Init transaction layer.
     * This will create/initialize transaction hash tables etc.
     */
    status = pjsip_tsx_layer_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize UA layer module.
     * This will create/initialize dialog hash tables etc.
     */
    status = pjsip_ua_init_module( g_endpt, NULL );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Init invite session module.
     * The invite session module initialization takes additional argument,
     * i.e. a structure containing callbacks to be called on specific
     * occurence of events.
     *
     * The on_state_changed and on_new_session callbacks are mandatory.
     * Application must supply the callback function.
     *
     * We use on_media_update() callback in this application to start
     * media transmission.
     */
    {
	pjsip_inv_callback inv_cb;

	/* Init the callback for INVITE session: */
	pj_bzero(&inv_cb, sizeof(inv_cb));
	inv_cb.on_state_changed = &call_on_state_changed;
	inv_cb.on_new_session = &call_on_forked;
	inv_cb.on_media_update = &call_on_media_update;

	/* Initialize invite session module:  */
	status = pjsip_inv_usage_init(g_endpt, &inv_cb);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    }

    /* Initialize 100rel support */
    status = pjsip_100rel_init_module(g_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /*
     * Register our module to receive incoming requests.
     */
    status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /*
     * Register message logger module.
     */
    status = pjsip_endpt_register_module( g_endpt, &msg_logger);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
#if PJ_HAS_THREADS
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
#else
    status = pjmedia_endpt_create(&cp.factory, 
				  pjsip_endpt_get_ioqueue(g_endpt), 
				  0, &g_med_endpt);
#endif
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* 
     * Add PCMA/PCMU codec to the media endpoint. 
     */
#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
    status = pjmedia_codec_g711_init(g_med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#endif


#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Init video subsystem */
    pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512);
    status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_converter_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_codec_mgr_create(pool, NULL);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
    status = pjmedia_vid_dev_subsys_init(&cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

#  if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    /* Init ffmpeg video codecs */
    status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#  endif  /* PJMEDIA_HAS_FFMPEG_VID_CODEC */

#endif	/* PJMEDIA_HAS_VIDEO */
    
    /* 
     * Create media transport used to send/receive RTP/RTCP socket.
     * One media transport is needed for each call. Application may
     * opt to re-use the same media transport for subsequent calls.
     */
    for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) {
	status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL, 
					       RTP_PORT + i*2, 0, 
					       &g_med_transport[i]);
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create media transport", status);
	    return 1;
	}

	/* 
	 * Get socket info (address, port) of the media transport. We will
	 * need this info to create SDP (i.e. the address and port info in
	 * the SDP).
	 */
	pjmedia_transport_info_init(&g_med_tpinfo[i]);
	pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]);

	pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info,
		  sizeof(pjmedia_sock_info));
    }

    /*
     * If URL is specified, then make call immediately.
     */
    if (argc > 1) {
	pj_sockaddr hostaddr;
	char hostip[PJ_INET6_ADDRSTRLEN+2];
	char temp[80];
	pj_str_t dst_uri = pj_str(argv[1]);
	pj_str_t local_uri;
	pjsip_dialog *dlg;
	pjmedia_sdp_session *local_sdp;
	pjsip_tx_data *tdata;

	if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
	    return 1;
	}
	pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);

	pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>", 
			hostip, SIP_PORT);
	local_uri = pj_str(temp);

	/* Create UAC dialog */
	status = pjsip_dlg_create_uac( pjsip_ua_instance(), 
				       &local_uri,  /* local URI */
				       &local_uri,  /* local Contact */
				       &dst_uri,    /* remote URI */
				       &dst_uri,    /* remote target */
				       &dlg);	    /* dialog */
	if (status != PJ_SUCCESS) {
	    app_perror(THIS_FILE, "Unable to create UAC dialog", status);
	    return 1;
	}

	/* If we expect the outgoing INVITE to be challenged, then we should
	 * put the credentials in the dialog here, with something like this:
	 *
	    {
		pjsip_cred_info	cred[1];

		cred[0].realm	  = pj_str("sip.server.realm");
		cred[0].scheme    = pj_str("digest");
		cred[0].username  = pj_str("theuser");
		cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
		cred[0].data      = pj_str("thepassword");

		pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred);
	    }
	 *
	 */


	/* Get the SDP body to be put in the outgoing INVITE, by asking
	 * media endpoint to create one for us.
	 */
	status = pjmedia_endpt_create_sdp( g_med_endpt,	    /* the media endpt	*/
					   dlg->pool,	    /* pool.		*/
					   MAX_MEDIA_CNT,   /* # of streams	*/
					   g_sock_info,     /* RTP sock info	*/
					   &local_sdp);	    /* the SDP result	*/
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Create the INVITE session, and pass the SDP returned earlier
	 * as the session's initial capability.
	 */
	status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

	/* If we want the initial INVITE to travel to specific SIP proxies,
	 * then we should put the initial dialog's route set here. The final
	 * route set will be updated once a dialog has been established.
	 * To set the dialog's initial route set, we do it with something
	 * like this:
	 *
	    {
		pjsip_route_hdr route_set;
		pjsip_route_hdr *route;
		const pj_str_t hname = { "Route", 5 };
		char *uri = "sip:proxy.server;lr";

		pj_list_init(&route_set);

		route = pjsip_parse_hdr( dlg->pool, &hname, 
					 uri, strlen(uri),
					 NULL);
		PJ_ASSERT_RETURN(route != NULL, 1);
		pj_list_push_back(&route_set, route);

		pjsip_dlg_set_route_set(dlg, &route_set);
	    }
	 *
	 * Note that Route URI SHOULD have an ";lr" parameter!
	 */

	/* Create initial INVITE request.
	 * This INVITE request will contain a perfectly good request and 
	 * an SDP body as well.
	 */
	status = pjsip_inv_invite(g_inv, &tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);



	/* Send initial INVITE request. 
	 * From now on, the invite session's state will be reported to us
	 * via the invite session callbacks.
	 */
	status = pjsip_inv_send_msg(g_inv, tdata);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);


    } else {

	/* No URL to make call to */

	PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
    }


    /* Loop until one call is completed */
    for (;!g_complete;) {
	pj_time_val timeout = {0, 10};
	pjsip_endpt_handle_events(g_endpt, &timeout);
    }

    /* On exit, dump current memory usage: */
    dump_pool_usage(THIS_FILE, &cp);

    /* Destroy audio ports. Destroy the audio port first
     * before the stream since the audio port has threads
     * that get/put frames to the stream.
     */
    if (g_snd_port)
	pjmedia_snd_port_destroy(g_snd_port);

#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    /* Destroy video ports */
    if (g_vid_capturer)
	pjmedia_vid_port_destroy(g_vid_capturer);
    if (g_vid_renderer)
	pjmedia_vid_port_destroy(g_vid_renderer);
#endif

    /* Destroy streams */
    if (g_med_stream)
	pjmedia_stream_destroy(g_med_stream);
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
    if (g_med_vstream)
	pjmedia_vid_stream_destroy(g_med_vstream);

    /* Deinit ffmpeg codec */
#   if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
    pjmedia_codec_ffmpeg_vid_deinit();
#   endif

#endif

    /* Destroy media transports */
    for (i = 0; i < MAX_MEDIA_CNT; ++i) {
	if (g_med_transport[i])
	    pjmedia_transport_close(g_med_transport[i]);
    }

    /* Deinit pjmedia endpoint */
    if (g_med_endpt)
	pjmedia_endpt_destroy(g_med_endpt);

    /* Deinit pjsip endpoint */
    if (g_endpt)
	pjsip_endpt_destroy(g_endpt);

    /* Release pool */
    if (pool)
	pj_pool_release(pool);

    return 0;
}
Beispiel #24
0
/*
 * Create an SRTP media transport.
 */
PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
				       pjmedia_endpt *endpt,
				       pjmedia_transport *tp,
				       const pjmedia_srtp_setting *opt,
				       pjmedia_transport **p_tp)
{
    pj_pool_t *pool;
    transport_srtp *srtp;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(endpt && tp && p_tp, PJ_EINVAL);

    /* Check crypto availability */
    if (opt && opt->crypto_count == 0 && 
	opt->use == PJMEDIA_SRTP_MANDATORY)
	return PJMEDIA_SRTP_ESDPREQCRYPTO;

    /* Check crypto */
    if (opt && opt->use != PJMEDIA_SRTP_DISABLED) {
	for (i=0; i < opt->crypto_count; ++i) {
	    int cs_idx = get_crypto_idx(&opt->crypto[i].name);

	    /* check crypto name */
	    if (cs_idx == -1)
		return PJMEDIA_SRTP_ENOTSUPCRYPTO;

	    /* check key length */
	    if (opt->crypto[i].key.slen && 
		opt->crypto[i].key.slen < 
		(pj_ssize_t)crypto_suites[cs_idx].cipher_key_len)
		return PJMEDIA_SRTP_EINKEYLEN;
	}
    }

    /* Init libsrtp. */
    status = pjmedia_srtp_init_lib();
    if (status != PJ_SUCCESS)
	return status;

    pool = pjmedia_endpt_create_pool(endpt, "srtp%p", 1000, 1000);
    srtp = PJ_POOL_ZALLOC_T(pool, transport_srtp);

    srtp->pool = pool;
    srtp->session_inited = PJ_FALSE;
    srtp->bypass_srtp = PJ_FALSE;
    srtp->probation_cnt = PROBATION_CNT_INIT;

    if (opt) {
	srtp->setting = *opt;
	if (opt->use == PJMEDIA_SRTP_DISABLED)
	    srtp->setting.crypto_count = 0;

	for (i=0; i < srtp->setting.crypto_count; ++i) {
	    int cs_idx = get_crypto_idx(&opt->crypto[i].name);
	    pj_str_t tmp_key = opt->crypto[i].key;

	    /* re-set crypto */
	    srtp->setting.crypto[i].name = pj_str(crypto_suites[cs_idx].name);
	    /* cut key length */
	    if (tmp_key.slen)
		tmp_key.slen = crypto_suites[cs_idx].cipher_key_len;
	    pj_strdup(pool, &srtp->setting.crypto[i].key, &tmp_key);
	}
    } else {
	pjmedia_srtp_setting_default(&srtp->setting);
    }

    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &srtp->mutex);
    if (status != PJ_SUCCESS) {
	pj_pool_release(pool);
	return status;
    }

    /* Initialize base pjmedia_transport */
    pj_memcpy(srtp->base.name, pool->obj_name, PJ_MAX_OBJ_NAME);
    if (tp)
	srtp->base.type = tp->type;
    else
	srtp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;
    srtp->base.op = &transport_srtp_op;

    /* Set underlying transport */
    srtp->member_tp = tp;

    /* Initialize peer's SRTP usage mode. */
    srtp->peer_use = srtp->setting.use;

    /* Done */
    *p_tp = &srtp->base;

    return PJ_SUCCESS;
}
Beispiel #25
0
static pj_status_t g729_alloc_codec( pjmedia_codec_factory *factory,
				     const pjmedia_codec_info *id,
				     pjmedia_codec **p_codec)
{
    pjmedia_codec *codec = NULL;
    pj_status_t status;
    pj_pool_t *pool;

    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
    PJ_ASSERT_RETURN(factory==&g729_factory.base, PJ_EINVAL);

    /* Lock mutex. */
    pj_mutex_lock(g729_factory.mutex);

    /* Allocate new codec if no more is available */
	struct g729_private *codec_priv;

  /* Create pool for codec instance */
  pool = pjmedia_endpt_create_pool(g729_factory.endpt, "g729codec", 512, 512);

	codec = PJ_POOL_ALLOC_T(pool, pjmedia_codec);
	codec_priv = PJ_POOL_ZALLOC_T(pool, struct g729_private);
	if (!codec || !codec_priv) {
	  pj_pool_release(pool);
	    pj_mutex_unlock(g729_factory.mutex);
	    return PJ_ENOMEM;
	}

	codec_priv->pool = pool;
	/* Set the payload type */
	codec_priv->pt = id->pt;

#if !PLC_DISABLED
	/* Create PLC, always with 10ms ptime */
	status = pjmedia_plc_create(pool, 8000, 80, 0, &codec_priv->plc);
	if (status != PJ_SUCCESS) {
	  pj_pool_release(pool);
	    pj_mutex_unlock(g729_factory.mutex);
	    return status;
	}
#endif

	/* Create VAD */
	status = pjmedia_silence_det_create(g729_factory.pool,
					    8000, 80,
					    &codec_priv->vad);
	if (status != PJ_SUCCESS) {
	    pj_mutex_unlock(g729_factory.mutex);
	    return status;
	}

	codec->factory = factory;
	codec->op = &g729_op;
	codec->codec_data = codec_priv;

    *p_codec = codec;

    /* Unlock mutex. */
    pj_mutex_unlock(g729_factory.mutex);

    return PJ_SUCCESS;
}
Beispiel #26
0
/**
 * Create new session.
 */
PJ_DEF(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt, 
					    const pjmedia_session_info *si,
					    pjmedia_transport *transports[],
					    void *user_data,
					    pjmedia_session **p_session )
{
    pj_pool_t *pool;
    pjmedia_session *session;
    int i; /* Must be signed */
    pj_status_t status;

    /* Verify arguments. */
    PJ_ASSERT_RETURN(endpt && si && p_session, PJ_EINVAL);

    /* Create pool for the session. */
    pool = pjmedia_endpt_create_pool( endpt, "session", 
				      PJMEDIA_SESSION_SIZE, 
				      PJMEDIA_SESSION_INC);
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);

    session = PJ_POOL_ZALLOC_T(pool, pjmedia_session);
    session->pool = pool;
    session->endpt = endpt;
    session->stream_cnt = si->stream_cnt;
    session->user_data = user_data;

    /* Copy stream info (this simple memcpy may break sometime) */
    pj_memcpy(session->stream_info, si->stream_info,
	      si->stream_cnt * sizeof(pjmedia_stream_info));

    /*
     * Now create and start the stream!
     */
    for (i=0; i<(int)si->stream_cnt; ++i) {

	/* Create the stream */
	status = pjmedia_stream_create(endpt, session->pool,
				       &session->stream_info[i],
				       (transports?transports[i]:NULL),
				       session,
				       &session->stream[i]);
	if (status == PJ_SUCCESS)
	    status = pjmedia_stream_start(session->stream[i]);

	if (status != PJ_SUCCESS) {

	    for ( --i; i>=0; --i) {
		pjmedia_stream_destroy(session->stream[i]);
	    }

	    pj_pool_release(session->pool);
	    return status;
	}
    }


    /* Done. */

    *p_session = session;
    return PJ_SUCCESS;
}
Beispiel #27
0
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (silk_factory.endpt != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Init factory */
    silk_factory.base.op = &silk_factory_op;
    silk_factory.base.factory_data = NULL;
    silk_factory.endpt = endpt;

    /* Create pool */
    silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk codecs", 4000, 4000);
    if (!silk_factory.pool)
	return PJ_ENOMEM;

    /* Init list */
    pj_list_init(&silk_factory.codec_list);

    /* Create mutex. */
    status = pj_mutex_create_simple(silk_factory.pool, "silk codecs",
				    &silk_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;
    PJ_LOG(5, (THIS_FILE, "Init silk"));

    /* Table from silk docs
    				| fs (Hz) | BR (kbps)
    ----------------+---------+----------
    Narrowband		|    8000 |  5 - 20
    Mediumband		|   12000 |  7 - 25
    Wideband		|   16000 |  8 - 30
    Super Wideband	|   24000 | 20 - 40
    */
    // The max_bitrate is based on the maximum bitrate that can be used for the encoder.
    // BTW, if a remote side send us something very big, we will not get lost.
    // If such a remote side send us big packets it could be considered unefficient.
    // On our side we set for bitrate the medium value of bitrate for each clock rate based
    // on table above.
    struct silk_param *silk_param;
    silk_param = &silk_factory.silk_param[PARAM_NB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_NB;
    silk_param->clock_rate = 8000;
    silk_param->bitrate = 13000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
	silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_MB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_MB;
    silk_param->clock_rate = 12000;
    silk_param->bitrate = 16000;
    pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
    silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
    silk_param->packet_size_ms = FRAME_LENGTH_MS;
    silk_param->complexity = 2;
    silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_WB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_WB;
	silk_param->clock_rate = 16000;
	silk_param->bitrate = 19000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
	silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_UWB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_UWB;
    silk_param->clock_rate = 24000;
    silk_param->bitrate = 30000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
    silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;


    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	return PJ_EINVALIDOP;
    }

    PJ_LOG(5, (THIS_FILE, "Init silk > DONE"));

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr,
						&silk_factory.base);
    if (status != PJ_SUCCESS)
	return status;

    return PJ_SUCCESS;

on_error:
    if (silk_factory.mutex) {
	pj_mutex_destroy(silk_factory.mutex);
	silk_factory.mutex = NULL;
    }
    if (silk_factory.pool) {
	pj_pool_release(silk_factory.pool);
	silk_factory.pool = NULL;
    }

    return status;
}
Beispiel #28
0
/*
 * Initialize and register Speex codec factory to pjmedia endpoint.
 */
PJ_DEF(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt,
					      unsigned options,
					      int quality,
					      int complexity )
{
    pjmedia_codec_mgr *codec_mgr;
    unsigned i;
    pj_status_t status;

    if (spx_factory.pool != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Get defaults */
    if (quality < 0) quality = PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY;
    if (complexity < 0) complexity = PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY;

    /* Validate quality & complexity */
    PJ_ASSERT_RETURN(quality >= 0 && quality <= 10, PJ_EINVAL);
    PJ_ASSERT_RETURN(complexity >= 1 && complexity <= 10, PJ_EINVAL);

    /* Create Speex codec factory. */
    spx_factory.base.op = &spx_factory_op;
    spx_factory.base.factory_data = NULL;
    spx_factory.endpt = endpt;

    spx_factory.pool = pjmedia_endpt_create_pool(endpt, "speex", 
						       4000, 4000);
    if (!spx_factory.pool)
	return PJ_ENOMEM;

    pj_list_init(&spx_factory.codec_list);

    /* Create mutex. */
    status = pj_mutex_create_simple(spx_factory.pool, "speex", 
				    &spx_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Initialize default Speex parameter. */
    spx_factory.speex_param[PARAM_NB].enabled = 
	((options & PJMEDIA_SPEEX_NO_NB) == 0);
    spx_factory.speex_param[PARAM_NB].pt = PJMEDIA_RTP_PT_SPEEX_NB;
    spx_factory.speex_param[PARAM_NB].mode = speex_lib_get_mode(SPEEX_MODEID_NB);
    spx_factory.speex_param[PARAM_NB].clock_rate = 8000;
    spx_factory.speex_param[PARAM_NB].quality = quality;
    spx_factory.speex_param[PARAM_NB].complexity = complexity;

    spx_factory.speex_param[PARAM_WB].enabled = 
	((options & PJMEDIA_SPEEX_NO_WB) == 0);
    spx_factory.speex_param[PARAM_WB].pt = PJMEDIA_RTP_PT_SPEEX_WB;
    spx_factory.speex_param[PARAM_WB].mode = speex_lib_get_mode(SPEEX_MODEID_WB);
    spx_factory.speex_param[PARAM_WB].clock_rate = 16000;
    spx_factory.speex_param[PARAM_WB].quality = quality;
    spx_factory.speex_param[PARAM_WB].complexity = complexity;

    spx_factory.speex_param[PARAM_UWB].enabled = 
	((options & PJMEDIA_SPEEX_NO_UWB) == 0);
    spx_factory.speex_param[PARAM_UWB].pt = PJMEDIA_RTP_PT_SPEEX_UWB;
    spx_factory.speex_param[PARAM_UWB].mode = speex_lib_get_mode(SPEEX_MODEID_UWB);
    spx_factory.speex_param[PARAM_UWB].clock_rate = 32000;
    spx_factory.speex_param[PARAM_UWB].quality = quality;
    spx_factory.speex_param[PARAM_UWB].complexity = complexity;

    /* Somehow quality <=4 is broken in linux. */
    if (quality <= 4 && quality >= 0) {
	PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb"));
	spx_factory.speex_param[PARAM_UWB].quality = 5;
    }

    /* Get codec framesize and avg bitrate for each mode. */
    for (i=0; i<PJ_ARRAY_SIZE(spx_factory.speex_param); ++i) {
	status = get_speex_info(&spx_factory.speex_param[i]);
    }

    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr, 
						&spx_factory.base);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done. */
    return PJ_SUCCESS;

on_error:
    pj_pool_release(spx_factory.pool);
    spx_factory.pool = NULL;
    return status;
}
Beispiel #29
0
/**
 * Create UDP stream transport from existing socket info.
 */
PJ_DEF(pj_status_t) pjmedia_transport_udp_attach( pjmedia_endpt *endpt,
						  const char *name,
						  const pjmedia_sock_info *si,
						  unsigned options,
						  pjmedia_transport **p_tp)
{
    struct transport_udp *tp;
    pj_pool_t *pool;
    pj_ioqueue_t *ioqueue;
    pj_ioqueue_callback rtp_cb, rtcp_cb;
    pj_ssize_t size;
    unsigned i;
    pj_status_t status;


    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && si && p_tp, PJ_EINVAL);

    /* Check name */
    if (!name)
	name = "udpmedia";

    /* Get ioqueue instance */
    ioqueue = pjmedia_endpt_get_ioqueue(endpt);


    /* Create transport structure */
    pool = pjmedia_endpt_create_pool(endpt, name, 4000, 4000);
    if (!pool)
	return PJ_ENOMEM;

    tp = pj_pool_zalloc(pool, sizeof(struct transport_udp));
    tp->pool = pool;
    tp->options = options;
    pj_ansi_strcpy(tp->base.name, name);
    tp->base.op = &transport_udp_op;

    /* Copy socket infos */
    tp->rtp_sock = si->rtp_sock;
    tp->rtp_addr_name = si->rtp_addr_name;
    tp->rtcp_sock = si->rtcp_sock;
    tp->rtcp_addr_name = si->rtcp_addr_name;

    /* If address is 0.0.0.0, use host's IP address */
    if (tp->rtp_addr_name.sin_addr.s_addr == 0) {
	pj_in_addr hostip;

	status = pj_gethostip(&hostip);
	if (status != PJ_SUCCESS)
	    goto on_error;

	tp->rtp_addr_name.sin_addr = hostip;
    }

    /* Same with RTCP */
    if (tp->rtcp_addr_name.sin_addr.s_addr == 0) {
	tp->rtcp_addr_name.sin_addr.s_addr = tp->rtp_addr_name.sin_addr.s_addr;
    }

    /* Setup RTP socket with the ioqueue */
    pj_bzero(&rtp_cb, sizeof(rtp_cb));
    rtp_cb.on_read_complete = &on_rx_rtp;

    status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtp_sock, tp,
				      &rtp_cb, &tp->rtp_key);
    if (status != PJ_SUCCESS)
	goto on_error;
    
    pj_ioqueue_op_key_init(&tp->rtp_read_op, sizeof(tp->rtp_read_op));
    for (i=0; i<PJ_ARRAY_SIZE(tp->rtp_pending_write); ++i)
	pj_ioqueue_op_key_init(&tp->rtp_pending_write[i].op_key, 
			       sizeof(tp->rtp_pending_write[i].op_key));

    /* Kick of pending RTP read from the ioqueue */
    tp->rtp_addrlen = sizeof(tp->rtp_src_addr);
    size = sizeof(tp->rtp_pkt);
    status = pj_ioqueue_recvfrom(tp->rtp_key, &tp->rtp_read_op,
			         tp->rtp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
				 &tp->rtp_src_addr, &tp->rtp_addrlen);
    if (status != PJ_EPENDING)
	goto on_error;


    /* Setup RTCP socket with ioqueue */
    pj_bzero(&rtcp_cb, sizeof(rtcp_cb));
    rtcp_cb.on_read_complete = &on_rx_rtcp;

    status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtcp_sock, tp,
				      &rtcp_cb, &tp->rtcp_key);
    if (status != PJ_SUCCESS)
	goto on_error;

    pj_ioqueue_op_key_init(&tp->rtcp_read_op, sizeof(tp->rtcp_read_op));
    pj_ioqueue_op_key_init(&tp->rtcp_write_op, sizeof(tp->rtcp_write_op));


    /* Kick of pending RTCP read from the ioqueue */
    size = sizeof(tp->rtcp_pkt);
    tp->rtcp_addr_len = sizeof(tp->rtcp_src_addr);
    status = pj_ioqueue_recvfrom( tp->rtcp_key, &tp->rtcp_read_op,
				  tp->rtcp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
				  &tp->rtcp_src_addr, &tp->rtcp_addr_len);
    if (status != PJ_EPENDING)
	goto on_error;


    /* Done */
    *p_tp = &tp->base;
    return PJ_SUCCESS;


on_error:
    pjmedia_transport_udp_close(&tp->base);
    return status;
}
Beispiel #30
0
/**
 * Create UDP stream transport from existing socket info.
 */
PJ_DEF(pj_status_t) pjmedia_transport_udp_attach( pjmedia_endpt *endpt,
						  const char *name,
						  const pjmedia_sock_info *si,
						  unsigned options,
						  pjmedia_transport **p_tp)
{
    struct transport_udp *tp;
    pj_pool_t *pool;
    pj_ioqueue_t *ioqueue;
    pj_ioqueue_callback rtp_cb, rtcp_cb;
    pj_ssize_t size;
    unsigned i;
    pj_status_t status;


    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && si && p_tp, PJ_EINVAL);

    /* Get ioqueue instance */
    ioqueue = pjmedia_endpt_get_ioqueue(endpt);

    if (name==NULL)
	name = "udp%p";

    /* Create transport structure */
    pool = pjmedia_endpt_create_pool(endpt, name, 512, 512);
    if (!pool)
	return PJ_ENOMEM;

    tp = PJ_POOL_ZALLOC_T(pool, struct transport_udp);
    tp->pool = pool;
    tp->options = options;
    pj_memcpy(tp->base.name, pool->obj_name, PJ_MAX_OBJ_NAME);
    tp->base.op = &transport_udp_op;
    tp->base.type = PJMEDIA_TRANSPORT_TYPE_UDP;

    /* Copy socket infos */
    tp->rtp_sock = si->rtp_sock;
    tp->rtp_addr_name = si->rtp_addr_name;
    tp->rtcp_sock = si->rtcp_sock;
    tp->rtcp_addr_name = si->rtcp_addr_name;

    /* If address is 0.0.0.0, use host's IP address */
    if (!pj_sockaddr_has_addr(&tp->rtp_addr_name)) {
	pj_sockaddr hostip;

	status = pj_gethostip(tp->rtp_addr_name.addr.sa_family, &hostip);
	if (status != PJ_SUCCESS)
	    goto on_error;

	pj_memcpy(pj_sockaddr_get_addr(&tp->rtp_addr_name), 
		  pj_sockaddr_get_addr(&hostip),
		  pj_sockaddr_get_addr_len(&hostip));
    }

    /* Same with RTCP */
    if (!pj_sockaddr_has_addr(&tp->rtcp_addr_name)) {
	pj_memcpy(pj_sockaddr_get_addr(&tp->rtcp_addr_name),
		  pj_sockaddr_get_addr(&tp->rtp_addr_name),
		  pj_sockaddr_get_addr_len(&tp->rtp_addr_name));
    }

    /* Setup RTP socket with the ioqueue */
    pj_bzero(&rtp_cb, sizeof(rtp_cb));
    rtp_cb.on_read_complete = &on_rx_rtp;

    status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtp_sock, tp,
				      &rtp_cb, &tp->rtp_key);
    if (status != PJ_SUCCESS)
	goto on_error;
    
    /* Disallow concurrency so that detach() and destroy() are
     * synchronized with the callback.
     */
    status = pj_ioqueue_set_concurrency(tp->rtp_key, PJ_FALSE);
    if (status != PJ_SUCCESS)
	goto on_error;

    pj_ioqueue_op_key_init(&tp->rtp_read_op, sizeof(tp->rtp_read_op));
    for (i=0; i<PJ_ARRAY_SIZE(tp->rtp_pending_write); ++i)
	pj_ioqueue_op_key_init(&tp->rtp_pending_write[i].op_key, 
			       sizeof(tp->rtp_pending_write[i].op_key));

    /* Kick of pending RTP read from the ioqueue */
    tp->rtp_addrlen = sizeof(tp->rtp_src_addr);
    size = sizeof(tp->rtp_pkt);
    status = pj_ioqueue_recvfrom(tp->rtp_key, &tp->rtp_read_op,
			         tp->rtp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
				 &tp->rtp_src_addr, &tp->rtp_addrlen);
    if (status != PJ_EPENDING)
	goto on_error;


    /* Setup RTCP socket with ioqueue */
    pj_bzero(&rtcp_cb, sizeof(rtcp_cb));
    rtcp_cb.on_read_complete = &on_rx_rtcp;

    status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtcp_sock, tp,
				      &rtcp_cb, &tp->rtcp_key);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_ioqueue_set_concurrency(tp->rtcp_key, PJ_FALSE);
    if (status != PJ_SUCCESS)
	goto on_error;

    pj_ioqueue_op_key_init(&tp->rtcp_read_op, sizeof(tp->rtcp_read_op));
    pj_ioqueue_op_key_init(&tp->rtcp_write_op, sizeof(tp->rtcp_write_op));


    /* Kick of pending RTCP read from the ioqueue */
    size = sizeof(tp->rtcp_pkt);
    tp->rtcp_addr_len = sizeof(tp->rtcp_src_addr);
    status = pj_ioqueue_recvfrom( tp->rtcp_key, &tp->rtcp_read_op,
				  tp->rtcp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
				  &tp->rtcp_src_addr, &tp->rtcp_addr_len);
    if (status != PJ_EPENDING)
	goto on_error;


    /* Done */
    *p_tp = &tp->base;
    return PJ_SUCCESS;


on_error:
    transport_destroy(&tp->base);
    return status;
}