From c7b0bd5a2320cc342474e5713adb00f92532aa23 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Wed, 15 Jul 2009 17:55:16 +0000 Subject: Ticket #919: - Added default ilbc mode into codec passthrough setting. - Added iLBC mode 'negotiation' in iLBC codec_open(). - Updated stream_create() to prioritize codec_open(), that may update the codec params, over stream initializations involving codec params. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2834 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia-codec/passthrough.h | 1 + pjmedia/src/pjmedia-codec/ilbc.c | 49 +++++++-------- pjmedia/src/pjmedia-codec/passthrough.c | 97 ++++++++++++++++++++++++++--- pjmedia/src/pjmedia/stream.c | 36 +++++------ pjsip/src/pjsua-lib/pjsua_media.c | 1 + 5 files changed, 130 insertions(+), 54 deletions(-) diff --git a/pjmedia/include/pjmedia-codec/passthrough.h b/pjmedia/include/pjmedia-codec/passthrough.h index 7b237c3c..c4f94a91 100644 --- a/pjmedia/include/pjmedia-codec/passthrough.h +++ b/pjmedia/include/pjmedia-codec/passthrough.h @@ -58,6 +58,7 @@ typedef struct pjmedia_codec_passthrough_setting to be enabled. */ pjmedia_format *fmts; /**< Encoding formats to be enabled. */ + unsigned ilbc_mode; /**< iLBC default mode. */ } pjmedia_codec_passthrough_setting; diff --git a/pjmedia/src/pjmedia-codec/ilbc.c b/pjmedia/src/pjmedia-codec/ilbc.c index c60d4285..1c7fd1fe 100644 --- a/pjmedia/src/pjmedia-codec/ilbc.c +++ b/pjmedia/src/pjmedia-codec/ilbc.c @@ -376,7 +376,9 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec, { struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec; pj_status_t status; - unsigned i, dec_fmtp_mode = 0, enc_fmtp_mode = 0; + unsigned i; + pj_uint16_t dec_fmtp_mode = DEFAULT_MODE, + enc_fmtp_mode = DEFAULT_MODE; pj_assert(ilbc_codec != NULL); pj_assert(ilbc_codec->enc_ready == PJ_FALSE && @@ -386,7 +388,7 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec, for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) { if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0) { - dec_fmtp_mode = (unsigned) + dec_fmtp_mode = (pj_uint16_t) pj_strtoul(&attr->setting.dec_fmtp.param[i].val); break; } @@ -400,30 +402,31 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec, for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) { if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0) { - enc_fmtp_mode = (unsigned) + enc_fmtp_mode = (pj_uint16_t) pj_strtoul(&attr->setting.enc_fmtp.param[i].val); break; } } - /* The enc mode must be set in the attribute - * (from the mode parameter in fmtp attribute in the SDP - * received from remote) - */ - if (enc_fmtp_mode == 0) - enc_fmtp_mode = dec_fmtp_mode; - - PJ_ASSERT_RETURN(enc_fmtp_mode==20 || - enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE); + PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30, + PJMEDIA_CODEC_EINMODE); - /* Update enc_ptime in the param */ + /* Both sides of a bi-directional session MUST use the same "mode" value. + * In this point, possible values are only 20 or 30, so when encoder and + * decoder modes are not same, just use the default mode, it is 30. + */ if (enc_fmtp_mode != dec_fmtp_mode) { - attr->info.enc_ptime = (pj_uint16_t)enc_fmtp_mode; - } else { - attr->info.enc_ptime = 0; + enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE; + PJ_LOG(4,(ilbc_codec->obj_name, + "Normalized iLBC encoder and decoder modes to %d", + DEFAULT_MODE)); } - /* Create enc */ + /* Update some attributes based on negotiated mode. */ + attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200); + attr->info.frm_ptime = dec_fmtp_mode; + + /* Create encoder */ ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode); ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000; ilbc_codec->enc_ready = PJ_TRUE; @@ -432,14 +435,7 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec, ilbc_codec->dec_samples_per_frame = initDecode(&ilbc_codec->dec, dec_fmtp_mode, attr->setting.penh); - if (dec_fmtp_mode == 20) - ilbc_codec->dec_frame_size = 38; - else if (dec_fmtp_mode == 30) - ilbc_codec->dec_frame_size = 50; - else { - pj_assert(!"Invalid iLBC mode"); - ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size; - } + ilbc_codec->dec_frame_size = (dec_fmtp_mode == 20? 38 : 50); ilbc_codec->dec_ready = PJ_TRUE; /* Save plc flags */ @@ -459,8 +455,7 @@ static pj_status_t ilbc_codec_open(pjmedia_codec *codec, pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0); PJ_LOG(5,(ilbc_codec->obj_name, - "iLBC codec opened, encoder mode=%d, decoder mode=%d", - enc_fmtp_mode, dec_fmtp_mode)); + "iLBC codec opened, mode=%d", dec_fmtp_mode)); return PJ_SUCCESS; } diff --git a/pjmedia/src/pjmedia-codec/passthrough.c b/pjmedia/src/pjmedia-codec/passthrough.c index e1572f48..c96e921d 100644 --- a/pjmedia/src/pjmedia-codec/passthrough.c +++ b/pjmedia/src/pjmedia-codec/passthrough.c @@ -114,6 +114,10 @@ typedef struct codec_private { int codec_idx; /**< Codec index. */ void *codec_setting; /**< Specific codec setting. */ pj_uint16_t avg_frame_size; /**< Average of frame size. */ + unsigned samples_per_frame; /**< Samples per frame, for iLBC + this can be 240 or 160, can + only be known after codec is + opened. */ } codec_private_t; @@ -380,6 +384,23 @@ PJ_DEF(pj_status_t) pjmedia_codec_passthrough_init2( codec_desc[i].enabled = enabled; } + +#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC + /* Update iLBC codec description based on default mode setting. */ + for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) { + if (codec_desc[i].enabled && + codec_desc[i].fmt_id == PJMEDIA_FORMAT_ILBC) + { + codec_desc[i].samples_per_frame = + (setting->ilbc_mode == 20? 160 : 240); + codec_desc[i].def_bitrate = + (setting->ilbc_mode == 20? 15200 : 13333); + pj_strset2(&codec_desc[i].dec_fmtp.param[0].val, + (setting->ilbc_mode == 20? "20" : "30")); + break; + } + } +#endif } return pjmedia_codec_passthrough_init(endpt); @@ -645,8 +666,11 @@ static pj_status_t codec_open( pjmedia_codec *codec, pool = codec_data->pool; - /* Get bitstream size */ - i = attr->info.avg_bps * desc->samples_per_frame; + /* Cache samples per frame value */ + codec_data->samples_per_frame = desc->samples_per_frame; + + /* Calculate bitstream size */ + i = attr->info.avg_bps * codec_data->samples_per_frame; j = desc->clock_rate << 3; codec_data->avg_frame_size = (pj_uint16_t)(i / j); if (i % j) ++codec_data->avg_frame_size; @@ -694,6 +718,63 @@ static pj_status_t codec_open( pjmedia_codec *codec, } #endif +#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC + { + enum { DEFAULT_MODE = 30 }; + static pj_str_t STR_MODE = {"mode", 4}; + pj_uint16_t dec_fmtp_mode = DEFAULT_MODE, + enc_fmtp_mode = DEFAULT_MODE; + + /* Get decoder mode */ + for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) { + if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0) + { + dec_fmtp_mode = (pj_uint16_t) + pj_strtoul(&attr->setting.dec_fmtp.param[i].val); + break; + } + } + + /* Decoder mode must be set */ + PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30, + PJMEDIA_CODEC_EINMODE); + + /* Get encoder mode */ + for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) { + if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0) + { + enc_fmtp_mode = (pj_uint16_t) + pj_strtoul(&attr->setting.enc_fmtp.param[i].val); + break; + } + } + + PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30, + PJMEDIA_CODEC_EINMODE); + + /* Both sides of a bi-directional session MUST use the same "mode" value. + * In this point, possible values are only 20 or 30, so when encoder and + * decoder modes are not same, just use the default mode, it is 30. + */ + if (enc_fmtp_mode != dec_fmtp_mode) { + enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE; + PJ_LOG(4,(pool->obj_name, + "Normalized iLBC encoder and decoder modes to %d", + DEFAULT_MODE)); + } + + /* Update some attributes based on negotiated mode. */ + attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200); + attr->info.frm_ptime = dec_fmtp_mode; + + /* Override average frame size */ + codec_data->avg_frame_size = (dec_fmtp_mode == 30? 50 : 38); + + /* Override samples per frame */ + codec_data->samples_per_frame = (dec_fmtp_mode == 30? 240 : 160); + } +#endif + return PJ_SUCCESS; } @@ -745,7 +826,8 @@ static pj_status_t codec_parse( pjmedia_codec *codec, frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; frames[count].buf = pkt; frames[count].size = codec_data->avg_frame_size; - frames[count].timestamp.u64 = ts->u64 + count*desc->samples_per_frame; + frames[count].timestamp.u64 = ts->u64 + + count * codec_data->samples_per_frame; pkt = (pj_uint8_t*)pkt + codec_data->avg_frame_size; pkt_size -= codec_data->avg_frame_size; @@ -757,7 +839,8 @@ static pj_status_t codec_parse( pjmedia_codec *codec, frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO; frames[count].buf = pkt; frames[count].size = pkt_size; - frames[count].timestamp.u64 = ts->u64 + count*desc->samples_per_frame; + frames[count].timestamp.u64 = ts->u64 + + count * codec_data->samples_per_frame; ++count; } @@ -854,7 +937,7 @@ static pj_status_t codec_decode( pjmedia_codec *codec, pjmedia_frame_ext_append_subframe(output_, input_.buf, (pj_uint16_t)(input_.size << 3), - (pj_uint16_t)desc->samples_per_frame); + (pj_uint16_t)codec_data->samples_per_frame); output->timestamp = input->timestamp; return PJ_SUCCESS; @@ -863,7 +946,7 @@ static pj_status_t codec_decode( pjmedia_codec *codec, pjmedia_frame_ext_append_subframe(output_, input->buf, (pj_uint16_t)(input->size << 3), - (pj_uint16_t)desc->samples_per_frame); + (pj_uint16_t)codec_data->samples_per_frame); output->timestamp = input->timestamp; return PJ_SUCCESS; @@ -883,7 +966,7 @@ static pj_status_t codec_recover( pjmedia_codec *codec, PJ_UNUSED_ARG(output_buf_len); pjmedia_frame_ext_append_subframe(output_, NULL, 0, - (pj_uint16_t)desc->samples_per_frame); + (pj_uint16_t)codec_data->samples_per_frame); return PJ_SUCCESS; } diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index d103979a..35b6dc90 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -1673,20 +1673,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, stream->port.info.clock_rate = info->fmt.clock_rate; stream->port.info.channel_count = info->fmt.channel_cnt; stream->port.port_data.pdata = stream; - if (info->param==NULL || info->param->info.fmt_id == PJMEDIA_FORMAT_L16) { - stream->port.info.format.id = PJMEDIA_FORMAT_L16; - - stream->port.put_frame = &put_frame; - stream->port.get_frame = &get_frame; - } else { - stream->port.info.format.id = info->param->info.fmt_id; - stream->port.info.format.bitrate = info->param->info.avg_bps; - stream->port.info.format.vad = (info->param->setting.vad != 0); - - stream->port.put_frame = &put_frame; - stream->port.get_frame = &get_frame_ext; - } - /* Init stream: */ stream->endpt = endpt; @@ -1745,7 +1731,12 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, if (stream->codec_param.setting.frm_per_pkt < 1) stream->codec_param.setting.frm_per_pkt = 1; - /* Set additional info. */ + /* Open the codec. */ + status = stream->codec->op->open(stream->codec, &stream->codec_param); + if (status != PJ_SUCCESS) + goto err_cleanup; + + /* Set additional info and callbacks. */ stream->port.info.bits_per_sample = 16; stream->port.info.samples_per_frame = info->fmt.clock_rate * stream->codec_param.info.channel_cnt * @@ -1762,11 +1753,16 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, ++stream->port.info.bytes_per_frame; } - /* Open the codec: */ - - status = stream->codec->op->open(stream->codec, &stream->codec_param); - if (status != PJ_SUCCESS) - goto err_cleanup; + stream->port.info.format.id = stream->codec_param.info.fmt_id; + if (stream->codec_param.info.fmt_id == PJMEDIA_FORMAT_L16) { + stream->port.put_frame = &put_frame; + stream->port.get_frame = &get_frame; + } else { + stream->port.info.format.bitrate = stream->codec_param.info.avg_bps; + stream->port.info.format.vad = (stream->codec_param.setting.vad != 0); + stream->port.put_frame = &put_frame; + stream->port.get_frame = &get_frame_ext; + } /* If encoder and decoder's ptime are asymmetric, then we need to * create buffer on the encoder side. This could happen for example diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index edf13ba3..ff0210d5 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -237,6 +237,7 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg) /* Init the passthrough codec with supported formats only */ setting.fmt_cnt = ext_fmt_cnt; setting.fmts = ext_fmts; + setting.ilbc_mode = cfg->ilbc_mode; status = pjmedia_codec_passthrough_init2(pjsua_var.med_endpt, &setting); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error initializing passthrough codecs", -- cgit v1.2.3