From 89e43bc5c1f286d4466d606fb96618cb87c4bf90 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Wed, 23 Jan 2013 02:57:30 +0000 Subject: Re #1568: backported to 1.x branch. git-svn-id: http://svn.pjsip.org/repos/pjproject/branches/1.x@4329 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/codec.h | 12 ++++ pjmedia/src/pjmedia/codec.c | 33 ++++++++++ pjmedia/src/pjmedia/session.c | 19 ++++++ pjsip/include/pjsua-lib/pjsua.h | 11 ++++ pjsip/src/pjsua-lib/pjsua_media.c | 131 +++++++++++++++++++++++++++++++++++--- 5 files changed, 196 insertions(+), 10 deletions(-) diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h index 50f70297..ea3f71f9 100644 --- a/pjmedia/include/pjmedia/codec.h +++ b/pjmedia/include/pjmedia/codec.h @@ -309,6 +309,18 @@ typedef struct pjmedia_codec_param } pjmedia_codec_param; +/** + * Duplicate codec parameter. + * + * @param pool The pool. + * @param src The codec parameter to be duplicated. + * + * @return Duplicated codec parameter. + */ +PJ_DECL(pjmedia_codec_param*) pjmedia_codec_param_clone( + pj_pool_t *pool, + const pjmedia_codec_param *src); + /* * Forward declaration for pjmedia_codec. diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c index 647b0b5d..35a90625 100644 --- a/pjmedia/src/pjmedia/codec.c +++ b/pjmedia/src/pjmedia/codec.c @@ -40,6 +40,39 @@ struct pjmedia_codec_default_param static void sort_codecs(pjmedia_codec_mgr *mgr); +/* + * Duplicate codec parameter. + */ +PJ_DEF(pjmedia_codec_param*) pjmedia_codec_param_clone( + pj_pool_t *pool, + const pjmedia_codec_param *src) +{ + pjmedia_codec_param *p; + unsigned i; + + PJ_ASSERT_RETURN(pool && src, NULL); + + p = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param); + + /* Update codec param */ + pj_memcpy(p, src, sizeof(pjmedia_codec_param)); + for (i = 0; i < src->setting.dec_fmtp.cnt; ++i) { + pj_strdup(pool, &p->setting.dec_fmtp.param[i].name, + &src->setting.dec_fmtp.param[i].name); + pj_strdup(pool, &p->setting.dec_fmtp.param[i].val, + &src->setting.dec_fmtp.param[i].val); + } + for (i = 0; i < src->setting.enc_fmtp.cnt; ++i) { + pj_strdup(pool, &p->setting.enc_fmtp.param[i].name, + &src->setting.enc_fmtp.param[i].name); + pj_strdup(pool, &p->setting.enc_fmtp.param[i].val, + &src->setting.enc_fmtp.param[i].val); + } + + return p; +} + + /* * Initialize codec manager. */ diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c index 787cbb4c..ff195119 100644 --- a/pjmedia/src/pjmedia/session.c +++ b/pjmedia/src/pjmedia/session.c @@ -671,6 +671,25 @@ PJ_DEF(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt, pj_memcpy(session->stream_info, si->stream_info, si->stream_cnt * sizeof(pjmedia_stream_info)); + /* Clone codec param */ + for (i=0; i<(int)si->stream_cnt; ++i) { + if (session->stream_info[i].param) { + session->stream_info[i].param = + pjmedia_codec_param_clone(pool, si->stream_info[i].param); + } else { + pjmedia_codec_param cp; + status = pjmedia_codec_mgr_get_default_param( + pjmedia_endpt_get_codec_mgr(endpt), + &si->stream_info[i].fmt, + &cp); + if (status != PJ_SUCCESS) + return status; + + session->stream_info[i].param = + pjmedia_codec_param_clone(pool, &cp); + } + } + /* * Now create and start the stream! */ diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index fc7c473d..417301e5 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -4433,6 +4433,17 @@ struct pjsua_media_config * Default : 1 */ int snd_auto_close_time; + + /** + * Disable smart media update (ticket #1568). The smart media update + * will check for any changes in the media properties after a successful + * SDP negotiation and the media will only be reinitialized when any + * change is found. When it is disabled, media streams will always be + * reinitialized after a successful SDP negotiation. + * + * Default: PJ_FALSE + */ + pj_bool_t no_smart_media_update; }; diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index dc996c97..a408f4c2 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -1566,6 +1566,99 @@ static void stop_media_session(pjsua_call_id call_id) call->media_st = PJSUA_CALL_MEDIA_NONE; } +/* Match codec fmtp. This will compare the values and the order. */ +static pj_bool_t match_codec_fmtp(const pjmedia_codec_fmtp *fmtp1, + const pjmedia_codec_fmtp *fmtp2) +{ + unsigned i; + + if (fmtp1->cnt != fmtp2->cnt) + return PJ_FALSE; + + for (i = 0; i < fmtp1->cnt; ++i) { + if (pj_stricmp(&fmtp1->param[i].name, &fmtp2->param[i].name)) + return PJ_FALSE; + if (pj_stricmp(&fmtp1->param[i].val, &fmtp2->param[i].val)) + return PJ_FALSE; + } + + return PJ_TRUE; +} + + +static pj_bool_t is_media_changed(const pjsua_call *call, + int new_audio_idx, + const pjmedia_session_info *new_sess) +{ + pjmedia_session_info old_sess; + const pjmedia_stream_info *old_si = NULL; + const pjmedia_stream_info *new_si; + const pjmedia_codec_info *old_ci = NULL; + const pjmedia_codec_info *new_ci; + const pjmedia_codec_param *old_cp = NULL; + const pjmedia_codec_param *new_cp; + + /* Init new stream info (shortcut vars) */ + new_si = &new_sess->stream_info[new_audio_idx]; + new_ci = &new_si->fmt; + new_cp = new_si->param; + + /* Get current stream info */ + if (call->session) { + pjmedia_session_get_info(call->session, &old_sess); + /* PJSUA always uses one stream per session */ + pj_assert(old_sess.stream_cnt == 1); + old_si = &old_sess.stream_info[0]; + old_ci = &old_si->fmt; + old_cp = old_si->param; + } + + /* Check for audio index change (is this really necessary?) */ + if (new_audio_idx != call->audio_idx) + return PJ_TRUE; + + /* Check if stream stays inactive */ + if (!old_si && new_si->dir == PJMEDIA_DIR_NONE) + return PJ_FALSE; + + /* Compare media direction */ + if (!old_si || (old_si && old_si->dir != new_si->dir)) + return PJ_TRUE; + + /* Compare remote RTP address */ + if (pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr)) + return PJ_TRUE; + + /* Compare codec info */ + if (pj_stricmp(&old_ci->encoding_name, &new_ci->encoding_name) || + old_ci->clock_rate != new_ci->clock_rate || + old_ci->channel_cnt != new_ci->channel_cnt || + //old_si->rx_pt != new_si->rx_pt || + old_si->tx_pt != new_si->tx_pt || + old_si->rx_event_pt != new_si->tx_event_pt || + old_si->tx_event_pt != new_si->tx_event_pt) + { + return PJ_TRUE; + } + + /* Compare codec param */ + if (old_cp->setting.frm_per_pkt != new_cp->setting.frm_per_pkt || + old_cp->setting.vad != new_cp->setting.vad || + old_cp->setting.cng != new_cp->setting.cng || + old_cp->setting.plc != new_cp->setting.plc || + old_cp->setting.penh != new_cp->setting.penh || + !match_codec_fmtp(&old_cp->setting.dec_fmtp, + &new_cp->setting.dec_fmtp) || + !match_codec_fmtp(&old_cp->setting.enc_fmtp, + &new_cp->setting.enc_fmtp)) + { + return PJ_TRUE; + } + + return PJ_FALSE; +} + + pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id) { pjsua_call *call = &pjsua_var.calls[call_id]; @@ -1613,6 +1706,12 @@ static void dtmf_callback(pjmedia_stream *strm, void *user_data, } +/* Internal function: update media channel after SDP negotiation. + * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov, + * for creating stream, etc, as after SDP negotiation and when + * the SDP media is not changed, the stream should remain running + * while the temporary/flip-flop pool may be released. + */ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, const pjmedia_sdp_session *local_sdp, const pjmedia_sdp_session *remote_sdp) @@ -1624,31 +1723,43 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, pjmedia_stream_info *si = NULL; pjmedia_port *media_port; pj_status_t status; + int audio_idx; if (!pjsua_var.med_endpt) { /* We're being shutdown */ return PJ_EBUSY; } - /* Destroy existing media session, if any. */ - prev_media_st = call->media_st; - stop_media_session(call->index); - - /* Create media session info based on SDP parameters. - */ - status = pjmedia_session_info_from_sdp( call->inv->pool_prov, - pjsua_var.med_endpt, + /* Create media session info based on SDP parameters. */ + status = pjmedia_session_info_from_sdp( call->inv->pool_prov, + pjsua_var.med_endpt, PJMEDIA_MAX_SDP_MEDIA, &sess_info, local_sdp, remote_sdp); if (status != PJ_SUCCESS) return status; + /* Get audio index from the negotiated SDP */ + audio_idx = find_audio_index(local_sdp, PJ_TRUE); + + /* Check if media has just been changed. */ + if (!pjsua_var.media_cfg.no_smart_media_update && + !is_media_changed(call, audio_idx, &sess_info)) + { + PJ_LOG(4,(THIS_FILE, "Media session for call %d is unchanged", + call_id)); + return PJ_SUCCESS; + } + + /* Destroy existing media session, if any. */ + prev_media_st = call->media_st; + stop_media_session(call->index); + for (i = 0; i < sess_info.stream_cnt; ++i) { sess_info.stream_info[i].rtcp_sdes_bye_disabled = PJ_TRUE; } /* Update audio index from the negotiated SDP */ - call->audio_idx = find_audio_index(local_sdp, PJ_TRUE); + call->audio_idx = audio_idx; /* Find which session is audio */ PJ_ASSERT_RETURN(call->audio_idx != -1, PJ_EBUG); @@ -1807,7 +1918,7 @@ pj_status_t pjsua_media_channel_update(pjsua_call_id call_id, port_name = pj_str("call"); } status = pjmedia_conf_add_port( pjsua_var.mconf, - call->inv->pool_prov, + call->inv->pool, media_port, &port_name, (unsigned*)&call->conf_slot); -- cgit v1.2.3