Index: /pjproject/trunk/pjmedia/include/pjmedia/sdp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 1809)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 1810)
@@ -494,4 +494,28 @@
 
 
+/**
+ * Compare two media transports for compatibility.
+ *
+ * @param t1	    The first media transport to compare.
+ * @param t2	    The second media transport to compare.
+ *
+ * @return	    PJ_SUCCESS when both media transports are compatible,
+ *		    otherwise returns PJMEDIA_SDP_ETPORTNOTEQUAL.
+ */
+PJ_DECL(pj_status_t) pjmedia_sdp_transport_cmp(const pj_str_t *t1,
+					       const pj_str_t *t2);
+
+
+/**
+ * Deactivate SDP media.
+ *
+ * @param m	    The SDP media to deactivate.
+ *
+ * @return	    PJ_SUCCESS when SDP media successfully deactivated,
+ *		    otherwise appropriate status code returned.
+ */
+PJ_DECL(pj_status_t) pjmedia_sdp_media_deactivate(pj_pool_t *pool,
+						  pjmedia_sdp_media *m);
+
 
 /* **************************************************************************
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 1809)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 1810)
@@ -213,4 +213,19 @@
 typedef struct pjmedia_transport pjmedia_transport;
 
+/**
+ * This enumeration specifies the general behaviour of media processing
+ */
+typedef enum pjmedia_tranport_media_option
+{
+    /**
+     * When this flag is specified, the transport will not perform media
+     * transport validation, this is useful when transport is stacked with
+     * other transport, for example when transport UDP is stacked under
+     * transport SRTP, media transport validation only need to be done by 
+     * transport SRTP.
+     */
+    PJMEDIA_TPMED_NO_TRANSPORT_CHECKING = 1
+
+} pjmedia_tranport_media_option;
 
 /**
@@ -293,4 +308,5 @@
     pj_status_t (*media_create)(pjmedia_transport *tp,
 				pj_pool_t *pool,
+				unsigned options,
 				pjmedia_sdp_session *sdp_local,
 				const pjmedia_sdp_session *sdp_remote,
@@ -509,4 +525,5 @@
  * @param tp		The media transport.
  * @param pool		The memory pool.
+ * @param option	Option flags, from #pjmedia_tranport_media_option
  * @param sdp_local	Local SDP.
  * @param sdp_remote	Remote SDP.
@@ -517,9 +534,10 @@
 PJ_INLINE(pj_status_t) pjmedia_transport_media_create(pjmedia_transport *tp,
 				    pj_pool_t *pool,
+				    unsigned options,
 				    pjmedia_sdp_session *sdp_local,
 				    const pjmedia_sdp_session *sdp_remote,
 				    unsigned media_index)
 {
-    return (*tp->op->media_create)(tp, pool, sdp_local, sdp_remote, 
+    return (*tp->op->media_create)(tp, pool, options, sdp_local, sdp_remote, 
 				   media_index);
 }
@@ -541,4 +559,5 @@
  * @param tp		The media transport.
  * @param pool		The memory pool.
+ * @param option	The media transport option.
  * @param sdp_local	Local SDP.
  * @param sdp_remote	Remote SDP.
Index: /pjproject/trunk/pjmedia/src/pjmedia/sdp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 1810)
@@ -1282,3 +1282,36 @@
 }
 
-
+PJ_DEF(pj_status_t) pjmedia_sdp_transport_cmp( const pj_str_t *t1,
+					       const pj_str_t *t2)
+{
+    static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 };
+    static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
+
+    /* Exactly equal? */
+    if (pj_stricmp(t1, t2) == 0)
+	return PJ_SUCCESS;
+
+    /* Compatible? */
+    if ((!pj_stricmp(t1, &ID_RTP_AVP) || !pj_stricmp(t1, &ID_RTP_SAVP)) &&
+        (!pj_stricmp(t2, &ID_RTP_AVP) || !pj_stricmp(t2, &ID_RTP_SAVP)))
+	return PJ_SUCCESS;
+
+    return PJMEDIA_SDP_ETPORTNOTEQUAL;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_media_deactivate(pj_pool_t *pool,
+						 pjmedia_sdp_media *m)
+{
+    pjmedia_sdp_attr *attr;
+    static const pj_str_t ID_INACTIVE = { "inactive", 8 };
+
+    attr = pjmedia_sdp_attr_create(pool, ID_INACTIVE.ptr, NULL);
+    if (NULL == attr)
+	return PJ_ENOMEM;
+
+    m->attr[m->attr_count++] = attr;
+    m->desc.port = 0;
+
+    return PJ_SUCCESS;
+}
Index: /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 1810)
@@ -480,12 +480,16 @@
 
 
-    /* Chec that transport in the answer match our offer. */
-
-    if (pj_strcmp(&answer->desc.transport, 
-		  &offer->desc.transport)!=0) 
+    /* Check that transport in the answer match our offer. */
+
+    /* At this point, transport type must be compatible, 
+     * the transport instance will do more validation later.
+     */
+    if (pjmedia_sdp_transport_cmp(&answer->desc.transport, 
+				  &offer->desc.transport) 
+	!= PJ_SUCCESS)
     {
-	/* The transport in the answer is different than the offer! */
 	return PJMEDIA_SDPNEG_EINVANSTP;
     }
+
 
     /* Check if remote has rejected our offer */
Index: /pjproject/trunk/pjmedia/src/pjmedia/session.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 1810)
@@ -191,11 +191,11 @@
     /* Transport protocol */
 
-    /* Transport type must be equal */
-    if (pj_stricmp(&rem_m->desc.transport, 
-		   &local_m->desc.transport) != 0) 
-    {
-	si->type = PJMEDIA_TYPE_UNKNOWN;
+    /* At this point, transport type must be compatible, 
+     * the transport instance will do more validation later.
+     */
+    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport, 
+				       &local_m->desc.transport);
+    if (status != PJ_SUCCESS)
 	return PJMEDIA_SDPNEG_EINVANSTP;
-    }
 
     if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1810)
@@ -25,4 +25,6 @@
 #define THIS_FILE   "transport_ice.c"
 
+static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 };
+
 struct transport_ice
 {
@@ -30,4 +32,5 @@
     pj_ice_strans	*ice_st;
     pjmedia_ice_cb	 cb;
+    unsigned		 media_option;
 
     pj_time_val		 start_ice;
@@ -75,4 +78,5 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				       pj_pool_t *pool,
+				       unsigned options,
 				       pjmedia_sdp_session *sdp_local,
 				       const pjmedia_sdp_session *sdp_remote,
@@ -259,4 +263,5 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				       pj_pool_t *pool,
+				       unsigned options,
 				       pjmedia_sdp_session *sdp_local,
 				       const pjmedia_sdp_session *sdp_remote,
@@ -270,4 +275,22 @@
     unsigned i, cand_cnt;
     pj_status_t status;
+
+    tp_ice->media_option = options;
+
+    /* Validate media transport */
+    /* By now, this transport only support RTP/AVP transport */
+    if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) {
+	pjmedia_sdp_media *m_rem, *m_loc;
+
+	m_rem = sdp_remote? sdp_remote->media[media_index] : NULL;
+	m_loc = sdp_local->media[media_index];
+
+	if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) ||
+	   (m_rem && pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)))
+	{
+	    pjmedia_sdp_media_deactivate(pool, m_loc);
+	    return PJMEDIA_SDP_EINPROTO;
+	}
+    }
 
     /* Init ICE */
@@ -500,10 +523,24 @@
     pj_status_t status;
 
-    PJ_UNUSED_ARG(sdp_local);
-
     PJ_ASSERT_RETURN(tp && pool && sdp_remote, PJ_EINVAL);
     PJ_ASSERT_RETURN(media_index < sdp_remote->media_count, PJ_EINVAL);
 
     sdp_med = sdp_remote->media[media_index];
+
+    /* Validate media transport */
+    /* By now, this transport only support RTP/AVP transport */
+    if ((tp_ice->media_option & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) {
+	pjmedia_sdp_media *m_rem, *m_loc;
+
+	m_rem = sdp_remote->media[media_index];
+	m_loc = sdp_local->media[media_index];
+
+	if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) ||
+	   (pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)))
+	{
+	    pjmedia_sdp_media_deactivate(pool, m_loc);
+	    return PJMEDIA_SDP_EINPROTO;
+	}
+    }
 
     /* Get the SDP connection for the media stream.
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 1810)
@@ -36,9 +36,5 @@
 #define MAX_BUFFER_LEN	1500
 #define MAX_KEY_LEN	32
-#define DEACTIVATE_MEDIA(pool, m) {\
-	    attr = pjmedia_sdp_attr_create(pool, ID_INACTIVE.ptr, NULL); \
-	    m->attr[m->attr_count++] = attr; \
-	    m->desc.port = 0; \
-	}
+#define DEACTIVATE_MEDIA(pool, m) pjmedia_sdp_media_deactivate(pool, m)
 
 static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 };
@@ -84,6 +80,7 @@
     pj_lock_t		*mutex;
     char		 tx_buffer[MAX_BUFFER_LEN];
-
     pjmedia_srtp_setting setting;
+    unsigned		 media_option;
+
     /* SRTP policy */
     pj_bool_t		 session_inited;
@@ -151,4 +148,5 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				       pj_pool_t *pool,
+				       unsigned options,
 				       pjmedia_sdp_session *sdp_local,
 				       const pjmedia_sdp_session *sdp_remote,
@@ -925,4 +923,5 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				          pj_pool_t *pool,
+					  unsigned options,
 				          pjmedia_sdp_session *sdp_local,
 				          const pjmedia_sdp_session *sdp_remote,
@@ -938,6 +937,10 @@
     pj_str_t attr_value;
     int i, j;
+    unsigned member_tp_option;
 
     PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);
+    
+    srtp->media_option = options;
+    member_tp_option = options | PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;
 
     pj_bzero(&srtp->rx_policy, sizeof(srtp->tx_policy));
@@ -1131,8 +1134,10 @@
 BYPASS_SRTP:
     srtp->bypass_srtp = PJ_TRUE;
+    member_tp_option &= ~PJMEDIA_TPMED_NO_TRANSPORT_CHECKING;
 
 PROPAGATE_MEDIA_CREATE:
-    return pjmedia_transport_media_create(srtp->real_tp, pool, sdp_local, 
-					   sdp_remote, media_index);
+    return pjmedia_transport_media_create(srtp->real_tp, pool, 
+			    member_tp_option,
+			    sdp_local, sdp_remote, media_index);
 }
 
@@ -1148,5 +1153,4 @@
     pjmedia_sdp_media *m_rem, *m_loc;
     pj_status_t status;
-    pjmedia_sdp_attr *attr;
     int i;
 
@@ -1172,8 +1176,12 @@
 	    goto BYPASS_SRTP;
 	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
-	    if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
-		DEACTIVATE_MEDIA(pool, m_loc);
-		return PJMEDIA_SDP_EINPROTO;
-	    }
+	    // Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
+	    // the answer must be processed through in optional mode.
+	    // Please note that at this point transport type is ensured to be 
+	    // RTP/AVP or RTP/SAVP, see transport_media_create()
+	    //if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
+		//DEACTIVATE_MEDIA(pool, m_loc);
+		//return PJMEDIA_SDP_EINPROTO;
+	    //}
 	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
 	    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) {
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 1809)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 1810)
@@ -36,4 +36,6 @@
 #define MAX_PENDING 4
 
+static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 };
+
 /* Pending write buffer */
 typedef struct pending_write
@@ -50,4 +52,5 @@
     pj_pool_t	       *pool;		/**< Memory pool		    */
     unsigned		options;	/**< Transport options.		    */
+    unsigned		media_options;	/**< Transport media options.	    */
     void	       *user_data;	/**< Only valid when attached	    */
     pj_bool_t		attached;	/**< Has attachment?		    */
@@ -121,4 +124,5 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				       pj_pool_t *pool,
+				       unsigned options,
 				       pjmedia_sdp_session *sdp_local,
 				       const pjmedia_sdp_session *sdp_remote,
@@ -765,13 +769,29 @@
 static pj_status_t transport_media_create(pjmedia_transport *tp,
 				  pj_pool_t *pool,
+				  unsigned options,
 				  pjmedia_sdp_session *sdp_local,
 				  const pjmedia_sdp_session *sdp_remote,
 				  unsigned media_index)
 {
-    PJ_UNUSED_ARG(tp);
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(sdp_local);
-    PJ_UNUSED_ARG(sdp_remote);
-    PJ_UNUSED_ARG(media_index);
+    struct transport_udp *udp = (struct transport_udp*)tp;
+
+    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);
+    udp->media_options = options;
+
+    /* Validate media transport */
+    /* By now, this transport only support RTP/AVP transport */
+    if ((udp->media_options & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) {
+	pjmedia_sdp_media *m_rem, *m_loc;
+
+	m_rem = sdp_remote? sdp_remote->media[media_index] : NULL;
+	m_loc = sdp_local->media[media_index];
+
+	if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) ||
+	   (m_rem && pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)))
+	{
+	    pjmedia_sdp_media_deactivate(pool, m_loc);
+	    return PJMEDIA_SDP_EINPROTO;
+	}
+    }
 
     return PJ_SUCCESS;
@@ -784,9 +804,23 @@
 				  unsigned media_index)
 {
-    PJ_UNUSED_ARG(tp);
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(sdp_local);
-    PJ_UNUSED_ARG(sdp_remote);
-    PJ_UNUSED_ARG(media_index);
+    struct transport_udp *udp = (struct transport_udp*)tp;
+
+    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);
+
+    /* Validate media transport */
+    /* By now, this transport only support RTP/AVP transport */
+    if ((udp->media_options & PJMEDIA_TPMED_NO_TRANSPORT_CHECKING) == 0) {
+	pjmedia_sdp_media *m_rem, *m_loc;
+
+	m_rem = sdp_remote->media[media_index];
+	m_loc = sdp_local->media[media_index];
+
+	if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP) ||
+	    pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP))
+	{
+	    pjmedia_sdp_media_deactivate(pool, m_loc);
+	    return PJMEDIA_SDP_EINPROTO;
+	}
+    }
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1809)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1810)
@@ -2485,5 +2485,5 @@
 	    inv->state != PJSIP_INV_STATE_CONFIRMED) 
 	{
-	    //call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
+	    call_disconnect(inv, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
 	}
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1809)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1810)
@@ -860,5 +860,5 @@
 
     /* Give the SDP to media transport */
-    status = pjmedia_transport_media_create(call->med_tp, pool, 
+    status = pjmedia_transport_media_create(call->med_tp, pool, 0,
 					    sdp, rem_sdp, MEDIA_IDX);
     if (status != PJ_SUCCESS) {
