summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2013-01-23 02:57:30 +0000
committerNanang Izzuddin <nanang@teluu.com>2013-01-23 02:57:30 +0000
commit89e43bc5c1f286d4466d606fb96618cb87c4bf90 (patch)
tree7de5acf14dfd41ed719c4988005eba82448ea9da
parent5a9d4fd7b11151e1b21d627d7197ceafccd38343 (diff)
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
-rw-r--r--pjmedia/include/pjmedia/codec.h12
-rw-r--r--pjmedia/src/pjmedia/codec.c33
-rw-r--r--pjmedia/src/pjmedia/session.c19
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h11
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c131
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
@@ -41,6 +41,39 @@ 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.
*/
PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr,
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);