Beispiel #1
0
/*
 * Register a codec factory.
 */
PJ_DEF(pj_status_t) pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr,
				    pjmedia_codec_factory *factory)
{
    pjmedia_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
    unsigned i, count;
    pj_status_t status;

    PJ_ASSERT_RETURN(mgr && factory, PJ_EINVAL);

    /* Since 2.0 we require codec factory to implement "destroy" op. Please
     * see: https://trac.pjsip.org/repos/ticket/1294
     *
     * Really! Please do see it.
     */
    PJ_ASSERT_RETURN(factory->op->destroy != NULL, PJ_ENOTSUP);

    /* Enum codecs */
    count = PJ_ARRAY_SIZE(info);
    status = factory->op->enum_info(factory, &count, info);
    if (status != PJ_SUCCESS)
	return status;

    pj_mutex_lock(mgr->mutex);

    /* Check codec count */
    if (count + mgr->codec_cnt > PJ_ARRAY_SIZE(mgr->codec_desc)) {
	pj_mutex_unlock(mgr->mutex);
	return PJ_ETOOMANY;
    }


    /* Save the codecs */
    for (i=0; i<count; ++i) {
	pj_memcpy( &mgr->codec_desc[mgr->codec_cnt+i],
		   &info[i], sizeof(pjmedia_codec_info));
	mgr->codec_desc[mgr->codec_cnt+i].prio = PJMEDIA_CODEC_PRIO_NORMAL;
	mgr->codec_desc[mgr->codec_cnt+i].factory = factory;
	pjmedia_codec_info_to_id( &info[i],
				  mgr->codec_desc[mgr->codec_cnt+i].id,
				  sizeof(pjmedia_codec_id));
    }

    /* Update count */
    mgr->codec_cnt += count;

    /* Re-sort codec based on priorities */
    sort_codecs(mgr);

    /* Add factory to the list */
    pj_list_push_back(&mgr->factory_list, factory);

    pj_mutex_unlock(mgr->mutex);

    return PJ_SUCCESS;
}
Beispiel #2
0
void list_codecs(pjmedia_endpt *ep) {
    unsigned int count = 100;
    int i;
    char buffer[100];
    pjmedia_codec_mgr *mgr = 0;
    pjmedia_codec_info codec[20];

    mgr = pjmedia_endpt_get_codec_mgr(ep);
    pjmedia_codec_mgr_enum_codecs(mgr, &count, codec, NULL);
    
    PJ_LOG(3, (__FILE__, "THERE ARE %d codecs", count));
    for ( i = 0; i < count; i++ ) {
        pj_bzero(buffer, sizeof(buffer));
        pjmedia_codec_info_to_id(&codec[i], buffer, sizeof(buffer));
        PJ_LOG(3, (__FILE__, "Codec : %s", buffer));
    }
}
Beispiel #3
0
/*
 * Register a codec factory.
 */
PJ_DEF(pj_status_t) pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr,
				    pjmedia_codec_factory *factory)
{
    pjmedia_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
    unsigned i, count;
    pj_status_t status;

    PJ_ASSERT_RETURN(mgr && factory, PJ_EINVAL);

    /* Enum codecs */
    count = PJ_ARRAY_SIZE(info);
    status = factory->op->enum_info(factory, &count, info);
    if (status != PJ_SUCCESS)
	return status;
    

    /* Check codec count */
    if (count + mgr->codec_cnt > PJ_ARRAY_SIZE(mgr->codec_desc))
	return PJ_ETOOMANY;


    /* Save the codecs */
    for (i=0; i<count; ++i) {
	pj_memcpy( &mgr->codec_desc[mgr->codec_cnt+i],
		   &info[i], sizeof(pjmedia_codec_info));
	mgr->codec_desc[mgr->codec_cnt+i].prio = PJMEDIA_CODEC_PRIO_NORMAL;
	mgr->codec_desc[mgr->codec_cnt+i].factory = factory;
	pjmedia_codec_info_to_id( &info[i],
				  mgr->codec_desc[mgr->codec_cnt+i].id,
				  sizeof(pjmedia_codec_id));
    }

    /* Update count */
    mgr->codec_cnt += count;

    /* Re-sort codec based on priorities */
    sort_codecs(mgr);

    /* Add factory to the list */
    pj_list_push_back(&mgr->factory_list, factory);


    return PJ_SUCCESS;
}
Beispiel #4
0
/*
 * Internal function for collecting codec info and param from the SDP media.
 */
static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si,
					      pj_pool_t *pool,
					      pjmedia_codec_mgr *mgr,
					      const pjmedia_sdp_media *local_m,
					      const pjmedia_sdp_media *rem_m)
{
    const pjmedia_sdp_attr *attr;
    pjmedia_sdp_rtpmap *rtpmap;
    unsigned i, fmti, pt = 0;
    pj_status_t status;

    /* Find the first codec which is not telephone-event */
    for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) {
	pjmedia_sdp_rtpmap r;

	if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) )
	    return PJMEDIA_EINVALIDPT;
	pt = pj_strtoul(&local_m->desc.fmt[fmti]);

	if (pt < 96) {
	    /* This is known static PT. Skip rtpmap checking because it is
	     * optional. */
	    break;
	}

	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
					   &local_m->desc.fmt[fmti]);
	if (attr == NULL)
	    continue;

	status = pjmedia_sdp_attr_get_rtpmap(attr, &r);
	if (status != PJ_SUCCESS)
	    continue;

	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) != 0)
	    break;
    }
    if ( fmti >= local_m->desc.fmt_count )
	return PJMEDIA_EINVALIDPT;

    /* Get payload type for receiving direction */
    si->rx_pt = pt;

    /* Get codec info.
     * For static payload types, get the info from codec manager.
     * For dynamic payload types, MUST get the rtpmap.
     */
    if (pt < 96) {
	pj_bool_t has_rtpmap;

	rtpmap = NULL;
	has_rtpmap = PJ_TRUE;

	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
					   &local_m->desc.fmt[fmti]);
	if (attr == NULL) {
	    has_rtpmap = PJ_FALSE;
	}
	if (attr != NULL) {
	    status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
	    if (status != PJ_SUCCESS)
		has_rtpmap = PJ_FALSE;
	}

	/* Build codec format info: */
	if (has_rtpmap) {
	    si->fmt.type = si->type;
	    si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
	    pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
	    si->fmt.clock_rate = rtpmap->clock_rate;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
	    /* The session info should have the actual clock rate, because
	     * this info is used for calculationg buffer size, etc in stream
	     */
	    if (si->fmt.pt == PJMEDIA_RTP_PT_G722)
		si->fmt.clock_rate = 16000;
#endif

	    /* For audio codecs, rtpmap parameters denotes the number of
	     * channels.
	     */
	    if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
		si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
	    } else {
		si->fmt.channel_cnt = 1;
	    }

	} else {
	    const pjmedia_codec_info *p_info;

	    status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info);
	    if (status != PJ_SUCCESS)
		return status;

	    pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));
	}

	/* For static payload type, pt's are symetric */
	si->tx_pt = pt;

    } else {
	pjmedia_codec_id codec_id;
	pj_str_t codec_id_st;
	const pjmedia_codec_info *p_info;

	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,
					   &local_m->desc.fmt[fmti]);
	if (attr == NULL)
	    return PJMEDIA_EMISSINGRTPMAP;

	status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
	if (status != PJ_SUCCESS)
	    return status;

	/* Build codec format info: */

	si->fmt.type = si->type;
	si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
	si->fmt.encoding_name = rtpmap->enc_name;
	si->fmt.clock_rate = rtpmap->clock_rate;

	/* For audio codecs, rtpmap parameters denotes the number of
	 * channels.
	 */
	if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
	    si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
	} else {
	    si->fmt.channel_cnt = 1;
	}

	/* Normalize the codec info from codec manager. Note that the
	 * payload type will be resetted to its default (it might have
	 * been rewritten by the SDP negotiator to match to the remote
	 * offer), this is intentional as currently some components may
	 * prefer (or even require) the default PT in codec info.
	 */
	pjmedia_codec_info_to_id(&si->fmt, codec_id, sizeof(codec_id));

	i = 1;
	codec_id_st = pj_str(codec_id);
	status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,
						     &i, &p_info, NULL);
	if (status != PJ_SUCCESS)
	    return status;

	pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));

	/* Determine payload type for outgoing channel, by finding
	 * dynamic payload type in remote SDP that matches the answer.
	 */
	si->tx_pt = 0xFFFF;
	for (i=0; i<rem_m->desc.fmt_count; ++i) {
	    if (pjmedia_sdp_neg_fmt_match(pool,
					  (pjmedia_sdp_media*)local_m, fmti,
					  (pjmedia_sdp_media*)rem_m, i, 0) ==
		PJ_SUCCESS)
	    {
		/* Found matched codec. */
		si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]);
		break;
	    }
	}

	if (si->tx_pt == 0xFFFF)
	    return PJMEDIA_EMISSINGRTPMAP;
    }


    /* Now that we have codec info, get the codec param. */
    si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param);
    status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt,
					         si->param);

    /* Get remote fmtp for our encoder. */
    pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt,
				   &si->param->setting.enc_fmtp);

    /* Get local fmtp for our decoder. */
    pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
				   &si->param->setting.dec_fmtp);

    if (!pj_stricmp2(&si->fmt.encoding_name, "opus")) {
	get_opus_channels_and_clock_rate(&si->param->setting.enc_fmtp,
					 &si->param->setting.dec_fmtp,
					 &si->fmt.channel_cnt,
					 &si->fmt.clock_rate);
    }


    /* Get the remote ptime for our encoder. */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "ptime", NULL);
    if (attr) {
	pj_str_t tmp_val = attr->value;
	unsigned frm_per_pkt;

	pj_strltrim(&tmp_val);

	/* Round up ptime when the specified is not multiple of frm_ptime */
	frm_per_pkt = (pj_strtoul(&tmp_val) +
		      si->param->info.frm_ptime/2) /
		      si->param->info.frm_ptime;
	if (frm_per_pkt != 0) {
            si->param->setting.frm_per_pkt = (pj_uint8_t)frm_per_pkt;
        }
    }

    /* Get remote maxptime for our encoder. */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "maxptime", NULL);
    if (attr) {
	pj_str_t tmp_val = attr->value;

	pj_strltrim(&tmp_val);
	si->tx_maxptime = pj_strtoul(&tmp_val);
    }

    /* When direction is NONE (it means SDP negotiation has failed) we don't
     * need to return a failure here, as returning failure will cause
     * the whole SDP to be rejected. See ticket #:
     *	http://
     *
     * Thanks Alain Totouom
     */
    if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)
	return status;


    /* Get incomming payload type for telephone-events */
    si->rx_event_pt = -1;
    for (i=0; i<local_m->attr_count; ++i) {
	pjmedia_sdp_rtpmap r;

	attr = local_m->attr[i];
	if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
	    continue;
	if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
	    continue;
	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
	    si->rx_event_pt = pj_strtoul(&r.pt);
	    break;
	}
    }

    /* Get outgoing payload type for telephone-events */
    si->tx_event_pt = -1;
    for (i=0; i<rem_m->attr_count; ++i) {
	pjmedia_sdp_rtpmap r;

	attr = rem_m->attr[i];
	if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
	    continue;
	if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
	    continue;
	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
	    si->tx_event_pt = pj_strtoul(&r.pt);
	    break;
	}
    }

    return PJ_SUCCESS;
}
Beispiel #5
0
/*
 * Set default codec parameter.
 */
PJ_DEF(pj_status_t) pjmedia_codec_mgr_set_default_param( 
					    pjmedia_codec_mgr *mgr,
					    const pjmedia_codec_info *info,
					    const pjmedia_codec_param *param )
{
    unsigned i;
    pjmedia_codec_id codec_id;
    pj_pool_t *pool, *old_pool = NULL;
    struct pjmedia_codec_desc *codec_desc = NULL;
    pjmedia_codec_default_param *p;

    PJ_ASSERT_RETURN(mgr && info, PJ_EINVAL);

    if (!pjmedia_codec_info_to_id(info, (char*)&codec_id, sizeof(codec_id)))
	return PJ_EINVAL;

    pj_mutex_lock(mgr->mutex);

    /* Lookup codec desc */
    for (i=0; i < mgr->codec_cnt; ++i) {
	if (pj_ansi_stricmp(codec_id, mgr->codec_desc[i].id) == 0) {
	    codec_desc = &mgr->codec_desc[i];
	    break;
	}
    }

    /* Codec not found */
    if (!codec_desc) {
	pj_mutex_unlock(mgr->mutex);
	return PJMEDIA_CODEC_EUNSUP;
    }

    /* If codec param is previously set, reset the codec param but release
     * the codec param pool later after the new param is set (ticket #1171).
     */
    if (codec_desc->param) {
	pj_assert(codec_desc->param->pool);
        old_pool = codec_desc->param->pool;
	codec_desc->param = NULL;
    }

    /* When param is set to NULL, i.e: setting default codec param to library
     * default setting, just return PJ_SUCCESS.
     */
    if (NULL == param) {
	pj_mutex_unlock(mgr->mutex);
        if (old_pool)
	    pj_pool_release(old_pool);
	return PJ_SUCCESS;
    }

    /* Instantiate and initialize codec param */
    pool = pj_pool_create(mgr->pf, (char*)codec_id, 256, 256, NULL);
    codec_desc->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_default_param);
    p = codec_desc->param;
    p->pool = pool;
    p->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param);

    /* Update codec param */
    pj_memcpy(p->param, param, sizeof(pjmedia_codec_param));
    for (i = 0; i < param->setting.dec_fmtp.cnt; ++i) {
	pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].name, 
		  &param->setting.dec_fmtp.param[i].name);
	pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].val, 
		  &param->setting.dec_fmtp.param[i].val);
    }
    for (i = 0; i < param->setting.enc_fmtp.cnt; ++i) {
	pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].name, 
		  &param->setting.enc_fmtp.param[i].name);
	pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].val, 
		  &param->setting.enc_fmtp.param[i].val);
    }

    pj_mutex_unlock(mgr->mutex);

    if (old_pool)
	pj_pool_release(old_pool);

    return PJ_SUCCESS;
}
Beispiel #6
0
/*
 * Get default codec parameter.
 */
PJ_DEF(pj_status_t) pjmedia_codec_mgr_get_default_param( pjmedia_codec_mgr *mgr,
							const pjmedia_codec_info *info,
							pjmedia_codec_param *param )
{
    pjmedia_codec_factory *factory;
    pj_status_t status;
    pjmedia_codec_id codec_id;
    struct pjmedia_codec_desc *codec_desc = NULL;
    unsigned i;

    PJ_ASSERT_RETURN(mgr && info && param, PJ_EINVAL);

    if (!pjmedia_codec_info_to_id(info, (char*)&codec_id, sizeof(codec_id)))
	return PJ_EINVAL;

    pj_mutex_lock(mgr->mutex);

    /* First, lookup default param in codec desc */
    for (i=0; i < mgr->codec_cnt; ++i) {
	if (pj_ansi_stricmp(codec_id, mgr->codec_desc[i].id) == 0) {
	    codec_desc = &mgr->codec_desc[i];
	    break;
	}
    }

    /* If we found the codec and its default param is set, return it */
    if (codec_desc && codec_desc->param) {
	pj_assert(codec_desc->param->param);
	pj_memcpy(param, codec_desc->param->param, 
		  sizeof(pjmedia_codec_param));

	pj_mutex_unlock(mgr->mutex);
	return PJ_SUCCESS;
    }

    /* Otherwise query the default param from codec factory */
    factory = mgr->factory_list.next;
    while (factory != &mgr->factory_list) {

	if ( (*factory->op->test_alloc)(factory, info) == PJ_SUCCESS ) {

	    status = (*factory->op->default_attr)(factory, info, param);
	    if (status == PJ_SUCCESS) {
		/* Check for invalid max_bps. */
		if (param->info.max_bps < param->info.avg_bps)
		    param->info.max_bps = param->info.avg_bps;

		pj_mutex_unlock(mgr->mutex);
		return PJ_SUCCESS;
	    }

	}

	factory = factory->next;
    }

    pj_mutex_unlock(mgr->mutex);


    return PJMEDIA_CODEC_EUNSUP;
}