Index: pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c	(revision 4261)
+++ pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c	(revision 4329)
@@ -1567,4 +1567,97 @@
 }
 
+/* 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)
 {
@@ -1614,4 +1707,10 @@
 
 
+/* 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,
@@ -1625,4 +1724,5 @@
     pjmedia_port *media_port;
     pj_status_t status;
+    int audio_idx;
 
     if (!pjsua_var.med_endpt) {
@@ -1631,12 +1731,7 @@
     }
 
-    /* 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);
@@ -1644,4 +1739,20 @@
 	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;
@@ -1649,5 +1760,5 @@
 
     /* 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 */
@@ -1808,5 +1919,5 @@
 	    }
 	    status = pjmedia_conf_add_port( pjsua_var.mconf, 
-					    call->inv->pool_prov,
+					    call->inv->pool,
 					    media_port, 
 					    &port_name,
