/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
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; }
/* * 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; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/** * 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; }
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; }
/* * 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; }
/* * 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; }
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; }
/** * 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; }
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; }
/* * 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; }
/** * 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; }
/** * 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; }