Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 4070)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 4071)
@@ -137,4 +137,8 @@
     unsigned		 med_cnt;   /**< Number of media in SDP.	    */
     pjsua_call_media     media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media   */
+    unsigned		 med_prov_cnt;/**< Number of provisional media.	    */
+    pjsua_call_media	 media_prov[PJSUA_MAX_CALL_MEDIA];
+				    /**< Array of provisional media.	    */
+
     int			 audio_idx; /**< First active audio media.	    */
     pj_mutex_t          *med_ch_mutex;/**< Media channel callback's mutex.  */
@@ -604,4 +608,6 @@
 void pjsua_set_media_tp_state(pjsua_call_media *call_med, pjsua_med_tp_st tp_st);
 
+void pjsua_media_prov_clean_up(pjsua_call_id call_id);
+
 /* Callback to receive media events */
 pj_status_t call_media_on_event(pjmedia_event *event,
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 4070)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 4071)
@@ -545,7 +545,10 @@
 	call->opt = *opt;
 
-	/* Reinit media channel when media count is changed */
-	if (opt->aud_cnt != old_opt.aud_cnt ||
-	    opt->vid_cnt != old_opt.vid_cnt)
+	/* Reinit media channel when media count is changed or we are the
+	 * answerer (as remote offer may 'extremely' modify the existing
+	 * media session, e.g: media type order).
+	 */
+	if (rem_sdp ||
+	    opt->aud_cnt!=old_opt.aud_cnt || opt->vid_cnt!=old_opt.vid_cnt)
 	{
 	    pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
@@ -1199,5 +1202,4 @@
 	pjsip_dlg_terminate(dlg);
 	 */
-	pjsua_media_channel_deinit(call->index);
 	goto on_return;
     }
@@ -1318,4 +1320,5 @@
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Unable to send 100 response", status);
+	    pjsua_media_channel_deinit(call->index);
 	    goto on_return;
 	}
@@ -3225,4 +3228,7 @@
 	pjsua_perror(THIS_FILE, "SDP negotiation has failed", status);
 
+	/* Clean up provisional media */
+	pjsua_media_prov_clean_up(call->index);
+
 	/* Do not deinitialize media since this may be a re-INVITE or
 	 * UPDATE (which in this case the media should not get affected
@@ -3428,15 +3434,9 @@
 	call->opt = opt;
     }
-
+    
     /* Re-init media for the new remote offer before creating SDP */
-    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,
-				      call->secure_level,
-				      call->inv->pool_prov,
-				      offer, NULL,
-                                      PJ_FALSE, NULL);
-    if (status != PJ_SUCCESS) {
-	pjsua_perror(THIS_FILE, "Error re-initializing media channel", status);
-	goto on_return;
-    }
+    status = apply_call_setting(call, &call->opt, offer);
+    if (status != PJ_SUCCESS)
+	goto on_return;
 
     status = pjsua_media_channel_create_sdp(call->index, 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 4070)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 4071)
@@ -2771,24 +2771,45 @@
 
     PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
-    // Suppress compile warning caused by unreferenced var.
-    PJ_UNUSED_ARG(i);
-#if DISABLED_FOR_TICKET_1185
     for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
 	pjsua_call *call = &pjsua_var.calls[i];
-	pjmedia_transport_info tpinfo;
-	char addr_buf[80];
-
-	/* MSVC complains about tpinfo not being initialized */
-	//pj_bzero(&tpinfo, sizeof(tpinfo));
-
-	pjmedia_transport_info_init(&tpinfo);
-	pjmedia_transport_get_info(call->med_tp, &tpinfo);
-
-	PJ_LOG(3,(THIS_FILE, " %s: %s",
-		  (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"),
-		  pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name, addr_buf,
-				    sizeof(addr_buf), 3)));
-    }
-#endif
+	pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2];
+	unsigned tp_cnt = 0;
+	unsigned j;
+
+	/* Collect media transports in this call */
+	for (j = 0; j < call->med_cnt; ++j) {
+	    if (call->media[j].tp != NULL)
+		tp[tp_cnt++] = call->media[j].tp;
+	}
+	for (j = 0; j < call->med_prov_cnt; ++j) {
+	    pjmedia_transport *med_tp = call->media_prov[j].tp;
+	    if (med_tp) {
+		unsigned k;
+		pj_bool_t used = PJ_FALSE;
+		for (k = 0; k < tp_cnt; ++k) {
+		    if (med_tp == tp[k]) {
+			used = PJ_TRUE;
+			break;
+		    }
+		}
+		if (!used)
+		    tp[tp_cnt++] = med_tp;
+	    }
+	}
+
+	/* Dump the media transports in this call */
+	for (j = 0; j < tp_cnt; ++j) {
+	    pjmedia_transport_info tpinfo;
+	    char addr_buf[80];
+
+	    pjmedia_transport_info_init(&tpinfo);
+	    pjmedia_transport_get_info(tp[j], &tpinfo);
+	    PJ_LOG(3,(THIS_FILE, " %s: %s",
+		      (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"),
+		      pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name,
+					addr_buf,
+					sizeof(addr_buf), 3)));
+	}
+    }
 
     pjsip_tsx_layer_dump(detail);
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 4070)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 4071)
@@ -1146,4 +1146,5 @@
 	pjmedia_srtp_setting_default(&srtp_opt);
 	srtp_opt.close_member_tp = PJ_TRUE;
+
 	/* If media session has been ever established, let's use remote's 
 	 * preference in SRTP usage policy, especially when it is stricter.
@@ -1180,4 +1181,5 @@
 on_return:
     if (status != PJ_SUCCESS && call_med->tp) {
+	pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
 	pjmedia_transport_close(call_med->tp);
 	call_med->tp = NULL;
@@ -1218,5 +1220,12 @@
     call_med->type = type;
 
-    /* Create the media transport for initial call. */
+    /* Create the media transport for initial call. Here are the possible
+     * media transport state and the action needed:
+     * - PJSUA_MED_TP_NULL or call_med->tp==NULL, create one.
+     * - PJSUA_MED_TP_RUNNING, do nothing.
+     * - PJSUA_MED_TP_DISABLED, re-init (media_create(), etc). Currently,
+     *   this won't happen as media_channel_update() will always clean up
+     *   the unused transport of a disabled media.
+     */
     if (call_med->tp == NULL) {
 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
@@ -1258,5 +1267,7 @@
     } else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
 	/* Media is being reenabled. */
-	pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_INIT);
+	//pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+
+	pj_assert(!"Currently no media transport reuse");
     }
 
@@ -1281,5 +1292,5 @@
          * has completed.
          */
-        call->media[info->med_idx].med_init_cb = NULL;
+        call->media_prov[info->med_idx].med_init_cb = NULL;
 
         /* In case of failure, save the information to be returned
@@ -1292,6 +1303,6 @@
          * callbacks.
          */
-        for (mi=0; mi < call->med_cnt; ++mi) {
-            pjsua_call_media *call_med = &call->media[mi];
+        for (mi=0; mi < call->med_prov_cnt; ++mi) {
+            pjsua_call_media *call_med = &call->media_prov[mi];
 
             if (call_med->med_init_cb) {
@@ -1314,11 +1325,11 @@
 
     if (status != PJ_SUCCESS) {
-        pjsua_media_channel_deinit(call_id);
+	pjsua_media_prov_clean_up(call_id);
         goto on_return;
     }
 
     /* Tell the media transport of a new offer/answer session */
-    for (mi=0; mi < call->med_cnt; ++mi) {
-	pjsua_call_media *call_med = &call->media[mi];
+    for (mi=0; mi < call->med_prov_cnt; ++mi) {
+	pjsua_call_media *call_med = &call->media_prov[mi];
 
 	/* Note: tp may be NULL if this media line is disabled */
@@ -1355,5 +1366,5 @@
                 call->med_ch_info.state = call_med->tp_st;
                 call->med_ch_info.sip_err_code = PJSIP_SC_NOT_ACCEPTABLE;
-		pjsua_media_channel_deinit(call_id);
+		pjsua_media_prov_clean_up(call_id);
 		goto on_return;
 	    }
@@ -1371,4 +1382,41 @@
     return status;
 }
+
+
+/* Clean up media transports in provisional media that is not used
+ * by call media.
+ */
+void pjsua_media_prov_clean_up(pjsua_call_id call_id)
+{
+    pjsua_call *call = &pjsua_var.calls[call_id];
+    unsigned i;
+
+    for (i = 0; i < call->med_prov_cnt; ++i) {
+	pjsua_call_media *call_med = &call->media_prov[i];
+	unsigned j;
+	pj_bool_t used = PJ_FALSE;
+
+	if (call_med->tp == NULL)
+	    continue;
+
+	for (j = 0; j < call->med_cnt; ++j) {
+	    if (call->media[j].tp == call_med->tp) {
+		used = PJ_TRUE;
+		break;
+	    }
+	}
+
+	if (!used) {
+	    if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
+		pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+		pjmedia_transport_media_stop(call_med->tp);
+	    }
+	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
+	    pjmedia_transport_close(call_med->tp);
+	    call_med->tp = call_med->tp_orig = NULL;
+	}
+    }
+}
+
 
 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
@@ -1423,4 +1471,22 @@
     pj_log_push_indent();
 
+    /* Init provisional media state */
+    if (call->med_cnt == 0) {
+	/* New media session, just copy whole from call media state. */
+	pj_memcpy(call->media_prov, call->media, sizeof(call->media));
+    } else {
+	/* Clean up any unused transports. Note that when local SDP reoffer
+	 * is rejected by remote, there may be any initialized transports that
+	 * are not used by call media and currently there is no notification
+	 * from PJSIP level regarding the reoffer rejection.
+	 */
+	pjsua_media_prov_clean_up(call_id);
+
+	/* Updating media session, copy from call media state. */
+	pj_memcpy(call->media_prov, call->media,
+		  sizeof(call->media[0]) * call->med_cnt);
+    }
+    call->med_prov_cnt = call->med_cnt;
+
 #if DISABLED_FOR_TICKET_1185
     /* Return error if media transport has not been created yet
@@ -1442,5 +1508,4 @@
 	    /* Expecting audio in the offer */
 	    if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
-	    pjsua_media_channel_deinit(call_id);
 	    status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
 	    goto on_error;
@@ -1459,6 +1524,7 @@
 	 * count setting (of the call setting) before the SDP negotiation.
 	 */
-	if (call->med_cnt < rem_sdp->media_count)
-	    call->med_cnt = PJ_MIN(rem_sdp->media_count, PJSUA_MAX_CALL_MEDIA);
+	if (call->med_prov_cnt < rem_sdp->media_count)
+	    call->med_prov_cnt = PJ_MIN(rem_sdp->media_count,
+					PJSUA_MAX_CALL_MEDIA);
 
 	call->rem_offerer = PJ_TRUE;
@@ -1496,5 +1562,5 @@
 	    {
 		for (mi = 0; mi < call->opt.aud_cnt - mtotaudcnt; ++mi)
-		    maudidx[maudcnt++] = (pj_uint8_t)call->med_cnt++;
+		    maudidx[maudcnt++] = (pj_uint8_t)call->med_prov_cnt++;
 		
 		mtotaudcnt = call->opt.aud_cnt;
@@ -1507,5 +1573,5 @@
 	    {
 		for (mi = 0; mi < call->opt.vid_cnt - mtotvidcnt; ++mi)
-		    mvididx[mvidcnt++] = (pj_uint8_t)call->med_cnt++;
+		    mvididx[mvidcnt++] = (pj_uint8_t)call->med_prov_cnt++;
 
 		mtotvidcnt = call->opt.vid_cnt;
@@ -1523,5 +1589,5 @@
 		mvididx[mi] = (pj_uint8_t)(maudcnt + mi);
 	    }
-	    call->med_cnt = maudcnt + mvidcnt;
+	    call->med_prov_cnt = maudcnt + mvidcnt;
 
 	    /* Need to publish supported media? */
@@ -1529,10 +1595,10 @@
 		if (mtotaudcnt == 0) {
 		    mtotaudcnt = 1;
-		    maudidx[0] = (pj_uint8_t)call->med_cnt++;
+		    maudidx[0] = (pj_uint8_t)call->med_prov_cnt++;
 		}
 #if PJMEDIA_HAS_VIDEO
 		if (mtotvidcnt == 0) {
 		    mtotvidcnt = 1;
-		    mvididx[0] = (pj_uint8_t)call->med_cnt++;
+		    mvididx[0] = (pj_uint8_t)call->med_prov_cnt++;
 		}
 #endif
@@ -1543,8 +1609,7 @@
     }
 
-    if (call->med_cnt == 0) {
+    if (call->med_prov_cnt == 0) {
 	/* Expecting at least one media */
 	if (sip_err_code) *sip_err_code = PJSIP_SC_NOT_ACCEPTABLE_HERE;
-	pjsua_media_channel_deinit(call_id);
 	status = PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE_HERE);
 	goto on_error;
@@ -1565,6 +1630,6 @@
 
     /* Initialize each media line */
-    for (mi=0; mi < call->med_cnt; ++mi) {
-	pjsua_call_media *call_med = &call->media[mi];
+    for (mi=0; mi < call->med_prov_cnt; ++mi) {
+	pjsua_call_media *call_med = &call->media_prov[mi];
 	pj_bool_t enabled = PJ_FALSE;
 	pjmedia_type media_type = PJMEDIA_TYPE_UNKNOWN;
@@ -1610,5 +1675,5 @@
                 }
 
-                pjsua_media_channel_deinit(call_id);
+                pjsua_media_prov_clean_up(call_id);
 		goto on_error;
 	    }
@@ -1619,5 +1684,7 @@
 	    if (call_med->tp) {
 		// Don't close transport here, as SDP negotiation has not been
-		// done and stream may be still active.
+		// done and stream may be still active. Once SDP negotiation
+		// is done (channel_update() invoked), this transport will be
+		// closed there.
 		//pjmedia_transport_close(call_med->tp);
 		//call_med->tp = NULL;
@@ -1736,12 +1803,12 @@
     /* Get one address to use in the origin field */
     pj_bzero(&origin, sizeof(origin));
-    for (mi=0; mi<call->med_cnt; ++mi) {
+    for (mi=0; mi<call->med_prov_cnt; ++mi) {
 	pjmedia_transport_info tpinfo;
 
-	if (call->media[mi].tp == NULL)
+	if (call->media_prov[mi].tp == NULL)
 	    continue;
 
 	pjmedia_transport_info_init(&tpinfo);
-	pjmedia_transport_get_info(call->media[mi].tp, &tpinfo);
+	pjmedia_transport_get_info(call->media_prov[mi].tp, &tpinfo);
 	pj_sockaddr_cp(&origin, &tpinfo.sock_info.rtp_addr_name);
 	break;
@@ -1755,6 +1822,6 @@
 
     /* Process each media line */
-    for (mi=0; mi<call->med_cnt; ++mi) {
-	pjsua_call_media *call_med = &call->media[mi];
+    for (mi=0; mi<call->med_prov_cnt; ++mi) {
+	pjsua_call_media *call_med = &call->media_prov[mi];
 	pjmedia_sdp_media *m = NULL;
 	pjmedia_transport_info tpinfo;
@@ -1999,4 +2066,32 @@
         call_med->prev_state = call_med->state;
 	call_med->state = PJSUA_CALL_MEDIA_NONE;
+
+	/* Try to sync recent changes to provisional media */
+	if (mi<call->med_prov_cnt && call->media_prov[mi].tp==call_med->tp)
+	{
+	    pjsua_call_media *prov_med = &call->media_prov[mi];
+
+	    /* Media state */
+	    prov_med->prev_state = call_med->prev_state;
+	    prov_med->state	 = call_med->state;
+
+	    /* RTP seq/ts */
+	    prov_med->rtp_tx_seq_ts_set = call_med->rtp_tx_seq_ts_set;
+	    prov_med->rtp_tx_seq	= call_med->rtp_tx_seq;
+	    prov_med->rtp_tx_ts		= call_med->rtp_tx_ts;
+
+	    /* Stream */
+	    if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+		prov_med->strm.a.conf_slot = call_med->strm.a.conf_slot;
+		prov_med->strm.a.stream	   = call_med->strm.a.stream;
+	    }
+#if PJMEDIA_HAS_VIDEO
+	    else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+		prov_med->strm.v.cap_win_id = call_med->strm.v.cap_win_id;
+		prov_med->strm.v.rdr_win_id = call_med->strm.v.rdr_win_id;
+		prov_med->strm.v.stream	    = call_med->strm.v.stream;
+	    }
+#endif
+	}
     }
 
@@ -2029,19 +2124,17 @@
     stop_media_session(call_id);
 
+    /* Clean up media transports */
+    pjsua_media_prov_clean_up(call_id);
+    call->med_prov_cnt = 0;
     for (mi=0; mi<call->med_cnt; ++mi) {
 	pjsua_call_media *call_med = &call->media[mi];
 
         if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
+	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
 	    pjmedia_transport_media_stop(call_med->tp);
-	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
-	}
-
-	//if (call_med->tp_orig && call_med->tp &&
-	//	call_med->tp != call_med->tp_orig)
-	//{
-	//    pjmedia_transport_close(call_med->tp);
-	//    call_med->tp = call_med->tp_orig;
-	//}
+	}
+
 	if (call_med->tp) {
+	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
 	    pjmedia_transport_close(call_med->tp);
 	    call_med->tp = call_med->tp_orig = NULL;
@@ -2089,5 +2182,5 @@
      * it may not be equal when remote removed any SDP media line.
      */
-    pj_assert(call->med_cnt >= local_sdp->media_count);
+    pj_assert(call->med_prov_cnt >= local_sdp->media_count);
 
     /* Reset audio_idx first */
@@ -2136,6 +2229,6 @@
 
     /* Process each media stream */
-    for (mi=0; mi < call->med_cnt; ++mi) {
-	pjsua_call_media *call_med = &call->media[mi];
+    for (mi=0; mi < call->med_prov_cnt; ++mi) {
+	pjsua_call_media *call_med = &call->media_prov[mi];
 
 	if (mi >= local_sdp->media_count ||
@@ -2288,8 +2381,6 @@
 	    /* Check if no media is active */
 	    if (si->dir == PJMEDIA_DIR_NONE) {
-		/* Call media state */
+		/* Update call media state and direction */
 		call_med->state = PJSUA_CALL_MEDIA_NONE;
-
-		/* Call media direction */
 		call_med->dir = PJMEDIA_DIR_NONE;
 
@@ -2394,7 +2485,7 @@
 	 */
 	if (local_sdp->media[mi]->desc.port==0 && call_med->tp) {
+	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
 	    pjmedia_transport_close(call_med->tp);
 	    call_med->tp = call_med->tp_orig = NULL;
-	    pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
 	}
 
@@ -2406,4 +2497,9 @@
 	}
     }
+
+    /* Update call media from provisional media */
+    call->med_cnt = call->med_prov_cnt;
+    pj_memcpy(call->media, call->media_prov,
+	      sizeof(call->media_prov[0]) * call->med_prov_cnt);
 
     /* Perform SDP re-negotiation if needed. */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 4070)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 4071)
@@ -1533,7 +1533,14 @@
     sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp);
 
+    /* Clean up provisional media before using it */
+    pjsua_media_prov_clean_up(call->index);
+
+    /* Update provisional media from call media */
+    call->med_prov_cnt = call->med_cnt;
+    pj_memcpy(call->media_prov, call->media,
+	      sizeof(call->media[0]) * call->med_cnt);
+
     /* Initialize call media */
-    call_med = &call->media[call->med_cnt++];
-
+    call_med = &call->media_prov[call->med_prov_cnt++];
     status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO,
 				   &acc_cfg->rtp_cfg, call->secure_level,
@@ -1598,4 +1605,5 @@
 on_error:
     if (call_med->tp) {
+	pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_NULL);
 	pjmedia_transport_close(call_med->tp);
 	call_med->tp = call_med->tp_orig = NULL;
@@ -1630,5 +1638,13 @@
     }
 
-    call_med = &call->media[med_idx];
+    /* Clean up provisional media before using it */
+    pjsua_media_prov_clean_up(call->index);
+
+    /* Update provisional media from call media */
+    call->med_prov_cnt = call->med_cnt;
+    pj_memcpy(call->media_prov, call->media,
+	      sizeof(call->media[0]) * call->med_cnt);
+
+    call_med = &call->media_prov[med_idx];
 
     /* Verify if the stream media type is video */
@@ -1736,4 +1752,5 @@
 on_error:
 	if (status != PJ_SUCCESS) {
+	    pjsua_media_prov_clean_up(call->index);
 	    return status;
 	}
