From 5900f75534e21f750e370ec230aec3d6cd58b850 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Tue, 26 Jan 2010 15:29:23 +0000 Subject: Ticket #1028: - Added new API pjmedia_codec_mgr_set_default_param() to set/update default codec parameter and implemented pjsua_codec_set_param() based on it. - Added mutex in codec manager to protect states manipulations. - Modified API pjmedia_codec_mgr_init() to add pool factory param. - Added new API pjmedia_codec_mgr_destroy(). - Updated passthrough codec AMR to regard peer's mode-set setting. - Fixed VAS audio device to apply AMR encoding bitrate setting. - Fixed IPP codec codec_open() to update AMR bitrate info (for stream) when AMR encoding bitrate is not using the default, e.g: requested by peer via format param 'mode-set' in SDP. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3074 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp | 4 + pjmedia/src/pjmedia-codec/ipp_codecs.c | 3 + pjmedia/src/pjmedia-codec/passthrough.c | 61 +++++++- pjmedia/src/pjmedia/codec.c | 216 ++++++++++++++++++++++++-- pjmedia/src/pjmedia/endpoint.c | 3 +- 5 files changed, 274 insertions(+), 13 deletions(-) (limited to 'pjmedia/src') diff --git a/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp index 776fdbf8..ae9b43c6 100644 --- a/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp +++ b/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp @@ -491,6 +491,10 @@ TInt CPjAudioEngine::StartRec() } break; + case EAMR_NB: + enc_fmt_if->SetBitRate(setting_.mode); + break; + default: break; } diff --git a/pjmedia/src/pjmedia-codec/ipp_codecs.c b/pjmedia/src/pjmedia-codec/ipp_codecs.c index aaf1142f..a8b73180 100644 --- a/pjmedia/src/pjmedia-codec/ipp_codecs.c +++ b/pjmedia/src/pjmedia-codec/ipp_codecs.c @@ -1195,6 +1195,9 @@ static pj_status_t ipp_codec_open( pjmedia_codec *codec, (s->enc_setting.amr_nb?"":"-WB"), s->enc_mode, codec_data->info->params.modes.bitrate)); + + /* Return back bitrate info to application */ + attr->info.avg_bps = codec_data->info->params.modes.bitrate; } #endif diff --git a/pjmedia/src/pjmedia-codec/passthrough.c b/pjmedia/src/pjmedia-codec/passthrough.c index 06e4de69..f6a6e119 100644 --- a/pjmedia/src/pjmedia-codec/passthrough.c +++ b/pjmedia/src/pjmedia-codec/passthrough.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -680,13 +681,18 @@ static pj_status_t codec_open( pjmedia_codec *codec, if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) { amr_settings_t *s; pj_uint8_t octet_align = 0; - const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11}; + pj_int8_t enc_mode; + + enc_mode = pjmedia_codec_amr_get_mode(attr->info.avg_bps); + pj_assert(enc_mode >= 0 && enc_mode <= 8); /* Fetch octet-align setting. It should be fine to fetch only * the decoder, since encoder & decoder must use the same setting * (RFC 4867 section 8.3.1). */ for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) { + const pj_str_t STR_FMTP_OCTET_ALIGN = {"octet-align", 11}; + if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_FMTP_OCTET_ALIGN) == 0) { @@ -696,10 +702,56 @@ static pj_status_t codec_open( pjmedia_codec *codec, } } + for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) { + /* mode-set, encoding mode is chosen based on local default mode + * setting: + * - if local default mode is included in the mode-set, use it + * - otherwise, find the closest mode to local default mode; + * if there are two closest modes, prefer to use the higher + * one, e.g: local default mode is 4, the mode-set param + * contains '2,3,5,6', then 5 will be chosen. + */ + const pj_str_t STR_FMTP_MODE_SET = {"mode-set", 8}; + + if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, + &STR_FMTP_MODE_SET) == 0) + { + const char *p; + pj_size_t l; + pj_int8_t diff = 99; + + p = pj_strbuf(&attr->setting.enc_fmtp.param[i].val); + l = pj_strlen(&attr->setting.enc_fmtp.param[i].val); + + while (l--) { + if ((desc->pt==PJMEDIA_RTP_PT_AMR && *p>='0' && *p<='7') || + (desc->pt==PJMEDIA_RTP_PT_AMRWB && *p>='0' && *p<='8')) + { + pj_int8_t tmp = (pj_int8_t)(*p - '0' - enc_mode); + + if (PJ_ABS(diff) > PJ_ABS(tmp) || + (PJ_ABS(diff) == PJ_ABS(tmp) && tmp > diff)) + { + diff = tmp; + if (diff == 0) break; + } + } + ++p; + } + + if (diff == 99) + return PJMEDIA_CODEC_EFAILED; + + enc_mode = (pj_int8_t)(enc_mode + diff); + + break; + } + } + s = PJ_POOL_ZALLOC_T(pool, amr_settings_t); codec_data->codec_setting = s; - s->enc_mode = pjmedia_codec_amr_get_mode(desc->def_bitrate); + s->enc_mode = enc_mode; if (s->enc_mode < 0) return PJMEDIA_CODEC_EINMODE; @@ -715,6 +767,11 @@ static pj_status_t codec_open( pjmedia_codec *codec, s->dec_setting.reorder = PJ_FALSE; /* Note this! passthrough codec doesn't do sensitivity bits reordering */ + + /* Return back bitrate info to application */ + attr->info.avg_bps = s->enc_setting.amr_nb? + pjmedia_codec_amrnb_bitrates[s->enc_mode]: + pjmedia_codec_amrwb_bitrates[s->enc_mode]; } #endif diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c index 708f06e8..d65ede4e 100644 --- a/pjmedia/src/pjmedia/codec.c +++ b/pjmedia/src/pjmedia/codec.c @@ -22,13 +22,19 @@ #include #include #include -#include #include #define THIS_FILE "codec.c" +/* Definition of default codecs parameters */ +struct pjmedia_codec_default_param +{ + pj_pool_t *pool; + pjmedia_codec_param *param; +}; + /* Sort codecs in codec manager based on priorities */ static void sort_codecs(pjmedia_codec_mgr *mgr); @@ -37,13 +43,56 @@ static void sort_codecs(pjmedia_codec_mgr *mgr); /* * Initialize codec manager. */ -PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr) +PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr, + pj_pool_factory *pf) { - PJ_ASSERT_RETURN(mgr, PJ_EINVAL); + pj_status_t status; + + PJ_ASSERT_RETURN(mgr && pf, PJ_EINVAL); + /* Init codec manager */ + pj_bzero(mgr, sizeof(pjmedia_codec_mgr)); + mgr->pf = pf; pj_list_init (&mgr->factory_list); mgr->codec_cnt = 0; + /* Create pool */ + mgr->pool = pj_pool_create(mgr->pf, "codec-mgr", 256, 256, NULL); + + /* Create mutex */ + status = pj_mutex_create_recursive(mgr->pool, "codec-mgr", &mgr->mutex); + if (status != PJ_SUCCESS) + return status; + + return PJ_SUCCESS; +} + +/* + * Initialize codec manager. + */ +PJ_DEF(pj_status_t) pjmedia_codec_mgr_destroy (pjmedia_codec_mgr *mgr) +{ + unsigned i; + + PJ_ASSERT_RETURN(mgr, PJ_EINVAL); + + /* Cleanup all pools of all codec default params */ + for (i=0; icodec_cnt; ++i) { + if (mgr->codec_desc[i].param) { + pj_assert(mgr->codec_desc[i].param->pool); + pj_pool_release(mgr->codec_desc[i].param->pool); + } + } + + /* Destroy mutex */ + pj_mutex_destroy(mgr->mutex); + + /* Release pool */ + pj_pool_release(mgr->pool); + + /* Just for safety, set codec manager states to zero */ + pj_bzero(mgr, sizeof(pjmedia_codec_mgr)); + return PJ_SUCCESS; } @@ -65,11 +114,14 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr, 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)) + if (count + mgr->codec_cnt > PJ_ARRAY_SIZE(mgr->codec_desc)) { + pj_mutex_unlock(mgr->mutex); return PJ_ETOOMANY; + } /* Save the codecs */ @@ -92,6 +144,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr, /* Add factory to the list */ pj_list_push_back(&mgr->factory_list, factory); + pj_mutex_unlock(mgr->mutex); return PJ_SUCCESS; } @@ -107,9 +160,13 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_unregister_factory( unsigned i; PJ_ASSERT_RETURN(mgr && factory, PJ_EINVAL); + pj_mutex_lock(mgr->mutex); + /* Factory must be registered. */ - PJ_ASSERT_RETURN(pj_list_find_node(&mgr->factory_list, factory)==factory, - PJ_ENOTFOUND); + if (pj_list_find_node(&mgr->factory_list, factory) != factory) { + pj_mutex_unlock(mgr->mutex); + return PJ_ENOTFOUND; + } /* Erase factory from the factory list */ pj_list_erase(factory); @@ -121,7 +178,13 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_unregister_factory( for (i=0; icodec_cnt; ) { if (mgr->codec_desc[i].factory == factory) { + /* Release pool of codec default param */ + if (mgr->codec_desc[i].param) { + pj_assert(mgr->codec_desc[i].param->pool); + pj_pool_release(mgr->codec_desc[i].param->pool); + } + /* Remove the codec from array of codec descriptions */ pj_array_erase(mgr->codec_desc, sizeof(mgr->codec_desc[0]), mgr->codec_cnt, i); --mgr->codec_cnt; @@ -131,6 +194,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_unregister_factory( } } + pj_mutex_unlock(mgr->mutex); return PJ_SUCCESS; } @@ -148,6 +212,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_enum_codecs(pjmedia_codec_mgr *mgr, PJ_ASSERT_RETURN(mgr && count && codecs, PJ_EINVAL); + pj_mutex_lock(mgr->mutex); + if (*count > mgr->codec_cnt) *count = mgr->codec_cnt; @@ -162,6 +228,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_enum_codecs(pjmedia_codec_mgr *mgr, prio[i] = mgr->codec_desc[i].prio; } + pj_mutex_unlock(mgr->mutex); + return PJ_SUCCESS; } @@ -177,13 +245,19 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_get_codec_info( pjmedia_codec_mgr *mgr, PJ_ASSERT_RETURN(mgr && p_info && pt>=0 && pt < 96, PJ_EINVAL); + pj_mutex_lock(mgr->mutex); + for (i=0; icodec_cnt; ++i) { if (mgr->codec_desc[i].info.pt == pt) { *p_info = &mgr->codec_desc[i].info; + + pj_mutex_unlock(mgr->mutex); return PJ_SUCCESS; } } + pj_mutex_unlock(mgr->mutex); + return PJMEDIA_CODEC_EUNSUP; } @@ -230,6 +304,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_find_codecs_by_id( pjmedia_codec_mgr *mgr, PJ_ASSERT_RETURN(mgr && codec_id && count && *count, PJ_EINVAL); + pj_mutex_lock(mgr->mutex); + for (i=0; icodec_cnt; ++i) { if (codec_id->slen == 0 || @@ -250,6 +326,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_find_codecs_by_id( pjmedia_codec_mgr *mgr, } + pj_mutex_unlock(mgr->mutex); + *count = found; return found ? PJ_SUCCESS : PJ_ENOTFOUND; @@ -313,6 +391,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_set_codec_priority( PJ_ASSERT_RETURN(mgr && codec_id, PJ_EINVAL); + pj_mutex_lock(mgr->mutex); + /* Update the priorities of affected codecs */ for (i=0; icodec_cnt; ++i) { @@ -325,12 +405,15 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_set_codec_priority( } } - if (!found) + if (!found) { + pj_mutex_unlock(mgr->mutex); return PJ_ENOTFOUND; + } /* Re-sort codecs */ sort_codecs(mgr); - + + pj_mutex_unlock(mgr->mutex); return PJ_SUCCESS; } @@ -350,20 +433,25 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_alloc_codec(pjmedia_codec_mgr *mgr, *p_codec = NULL; + pj_mutex_lock(mgr->mutex); + factory = mgr->factory_list.next; while (factory != &mgr->factory_list) { if ( (*factory->op->test_alloc)(factory, info) == PJ_SUCCESS ) { status = (*factory->op->alloc_codec)(factory, info, p_codec); - if (status == PJ_SUCCESS) + if (status == PJ_SUCCESS) { + pj_mutex_unlock(mgr->mutex); return PJ_SUCCESS; + } } factory = factory->next; } + pj_mutex_unlock(mgr->mutex); return PJMEDIA_CODEC_EUNSUP; } @@ -378,9 +466,36 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_get_default_param( pjmedia_codec_mgr *mgr, { 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) { @@ -392,6 +507,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_get_default_param( pjmedia_codec_mgr *mgr, 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; } @@ -400,11 +516,91 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_get_default_param( pjmedia_codec_mgr *mgr, factory = factory->next; } + pj_mutex_unlock(mgr->mutex); + return PJMEDIA_CODEC_EUNSUP; } +/* + * 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; + 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, release codec param pool */ + if (codec_desc->param) { + pj_assert(codec_desc->param->pool); + pj_pool_release(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); + 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, + ¶m->setting.dec_fmtp.param[i].name); + pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].val, + ¶m->setting.dec_fmtp.param[i].val); + } + for (i = 0; i < param->setting.dec_fmtp.cnt; ++i) { + pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].name, + ¶m->setting.dec_fmtp.param[i].name); + pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].val, + ¶m->setting.dec_fmtp.param[i].val); + } + + pj_mutex_unlock(mgr->mutex); + + return PJ_SUCCESS; +} + + /* * Dealloc codec. */ diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c index a3e988d5..8840589d 100644 --- a/pjmedia/src/pjmedia/endpoint.c +++ b/pjmedia/src/pjmedia/endpoint.c @@ -127,7 +127,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf, goto on_error; /* Init codec manager. */ - status = pjmedia_codec_mgr_init(&endpt->codec_mgr); + status = pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf); if (status != PJ_SUCCESS) goto on_error; @@ -172,6 +172,7 @@ on_error: if (endpt->ioqueue && endpt->own_ioqueue) pj_ioqueue_destroy(endpt->ioqueue); + pjmedia_codec_mgr_destroy(&endpt->codec_mgr); pjmedia_aud_subsys_shutdown(); pj_pool_release(pool); return status; -- cgit v1.2.3