Index: pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h	(revision 4553)
+++ pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h	(revision 4554)
@@ -314,4 +314,20 @@
 
 /**
+ * Flags to be given to pjmedia_sdp_neg_modify_local_offer2().
+ */
+typedef enum pjmedia_mod_offer_flag
+{
+   /**
+    * Allow media type in the SDP to be changed.
+    * When generating a new offer, in the case that a media line doesn't match
+    * the active SDP, the new media line will be considered to replace the
+    * existing media at the same position.
+    */
+   PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE = 1
+
+} pjmedia_mod_offer_flag;
+
+
+/**
  * Get the state string description of the specified state.
  *
@@ -494,4 +510,26 @@
 pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg,
 			       const pjmedia_sdp_session **local);
+
+/**
+ * Modify local session with a new SDP and treat this as a new offer. 
+ * This function can only be called in state PJMEDIA_SDP_NEG_STATE_DONE.
+ * After calling this function, application can send the SDP as offer 
+ * to remote party, using signaling protocol such as SIP.
+ * The negotiator state will move to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER,
+ * where it waits for SDP answer from remote. See also
+ * #pjmedia_sdp_neg_modify_local_offer2()
+ *
+ * @param pool		Pool to allocate memory. The pool's lifetime needs
+ *			to be valid for the duration of the negotiator.
+ * @param neg		The SDP negotiator instance.
+ * @param local		The new local SDP.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) 
+pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool,
+				    pjmedia_sdp_neg *neg,
+				    const pjmedia_sdp_session *local);
 
 /**
@@ -506,4 +544,5 @@
  *			to be valid for the duration of the negotiator.
  * @param neg		The SDP negotiator instance.
+ * @param flags         Bitmask from pjmedia_mod_offer_flag.
  * @param local		The new local SDP.
  *
@@ -512,7 +551,8 @@
  */
 PJ_DECL(pj_status_t) 
-pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool,
-				    pjmedia_sdp_neg *neg,
-				    const pjmedia_sdp_session *local);
+pjmedia_sdp_neg_modify_local_offer2( pj_pool_t *pool,
+				     pjmedia_sdp_neg *neg,
+                                     unsigned flags,
+				     const pjmedia_sdp_session *local);
 
 /**
Index: pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 4553)
+++ pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 4554)
@@ -277,4 +277,13 @@
 				    const pjmedia_sdp_session *local)
 {
+    return pjmedia_sdp_neg_modify_local_offer2(pool, neg, 0, local);
+}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2(
+                                    pj_pool_t *pool,
+				    pjmedia_sdp_neg *neg,
+                                    unsigned flags,
+				    const pjmedia_sdp_session *local)
+{
     pjmedia_sdp_session *new_offer;
     pjmedia_sdp_session *old_offer;
@@ -315,43 +324,61 @@
     pj_strdup(pool, &new_offer->origin.addr, &old_offer->origin.addr);
 
-    /* Generating the new offer, in the case media lines doesn't match the
-     * active SDP (e.g. current/active SDP's have m=audio and m=video lines, 
-     * and the new offer only has m=audio line), the negotiator will fix 
-     * the new offer by reordering and adding the missing media line with 
-     * port number set to zero.
-     */
-    for (oi = 0; oi < old_offer->media_count; ++oi) {
-	pjmedia_sdp_media *om;
-	pjmedia_sdp_media *nm;
-	unsigned ni; /* new offer media index */
-	pj_bool_t found = PJ_FALSE;
-
-	om = old_offer->media[oi];
-	for (ni = oi; ni < new_offer->media_count; ++ni) {
-	    nm = new_offer->media[ni];
-	    if (pj_strcmp(&nm->desc.media, &om->desc.media) == 0) {
-		if (ni != oi) {
-		    /* The same media found but the position unmatched to the 
-		     * old offer, so let's put this media in the right place, 
-		     * and keep the order of the rest.
-		     */
-		    pj_array_insert(new_offer->media,		 /* array    */
-				    sizeof(new_offer->media[0]), /* elmt size*/
-				    ni,				 /* count    */
-				    oi,				 /* pos      */
-				    &nm);			 /* new elmt */
-		}
-		found = PJ_TRUE;
-		break;
+    if ((flags & PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE) == 0) {
+       /* Generating the new offer, in the case media lines doesn't match the
+        * active SDP (e.g. current/active SDP's have m=audio and m=video lines,
+        * and the new offer only has m=audio line), the negotiator will fix 
+        * the new offer by reordering and adding the missing media line with 
+        * port number set to zero.
+        */
+        for (oi = 0; oi < old_offer->media_count; ++oi) {
+	    pjmedia_sdp_media *om;
+	    pjmedia_sdp_media *nm;
+	    unsigned ni; /* new offer media index */
+	    pj_bool_t found = PJ_FALSE;
+
+	    om = old_offer->media[oi];
+	    for (ni = oi; ni < new_offer->media_count; ++ni) {
+	        nm = new_offer->media[ni];
+	        if (pj_strcmp(&nm->desc.media, &om->desc.media) == 0) {
+		    if (ni != oi) {
+		        /* The same media found but the position unmatched to
+                         * the old offer, so let's put this media in the right
+                         * place, and keep the order of the rest.
+		         */
+		        pj_array_insert(
+                            new_offer->media,		 /* array    */
+			    sizeof(new_offer->media[0]), /* elmt size*/
+			    ni,				 /* count    */
+		            oi,				 /* pos      */
+			    &nm);			 /* new elmt */
+		    }
+		    found = PJ_TRUE;
+		    break;
+	        }
 	    }
-	}
-	if (!found) {
-	    pjmedia_sdp_media *m;
-
-	    m = sdp_media_clone_deactivate(pool, om, om, local);
+	    if (!found) {
+	        pjmedia_sdp_media *m;
+
+	        m = sdp_media_clone_deactivate(pool, om, om, local);
+
+	        pj_array_insert(new_offer->media, sizeof(new_offer->media[0]),
+			        new_offer->media_count++, oi, &m);
+	    }
+        }
+    } else {
+        /* If media type change is allowed, the negotiator only needs to fix 
+         * the new offer by adding the missing media line(s) with port number
+         * set to zero.
+         */
+        for (oi = new_offer->media_count; oi < old_offer->media_count; ++oi) {
+            pjmedia_sdp_media *m;
+
+	    m = sdp_media_clone_deactivate(pool, old_offer->media[oi],
+                                           old_offer->media[oi], local);
 
 	    pj_array_insert(new_offer->media, sizeof(new_offer->media[0]),
-			    new_offer->media_count++, oi, &m);
-	}
+	                    new_offer->media_count++, oi, &m);
+
+        }
     }
 
