Index: /pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 5787)
+++ /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 5788)
@@ -99,4 +99,5 @@
 					 sin_family is zero, the RTP address
 					 will be calculated from RTP.	    */
+    pj_bool_t		rtcp_mux;   /**< Use RTP and RTCP multiplexing.     */
 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
     pj_bool_t		rtcp_xr_enabled;
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 5787)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 5788)
@@ -258,5 +258,12 @@
      * transport SRTP.
      */
-    PJMEDIA_TPMED_NO_TRANSPORT_CHECKING = 1
+    PJMEDIA_TPMED_NO_TRANSPORT_CHECKING = 1,
+
+    /**
+     * When this flag is specified, the transport will allow multiplexing
+     * RTP and RTCP, i.e. if the remote agrees, RTCP will be sent using
+     * the same socket for RTP.
+     */
+    PJMEDIA_TPMED_RTCP_MUX = 2
 
 } pjmedia_tranport_media_option;
Index: /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h	(revision 5787)
+++ /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h	(revision 5788)
@@ -156,4 +156,5 @@
 					 sin_family is zero, the RTP address
 					 will be calculated from RTP.	    */
+    pj_bool_t		rtcp_mux;   /**< Use RTP and RTCP multiplexing.     */
     unsigned		tx_pt;	    /**< Outgoing codec paylaod type.	    */
     unsigned		rx_pt;	    /**< Incoming codec paylaod type.	    */
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5788)
@@ -272,4 +272,7 @@
 }
 
+static void on_rx_rtcp( void *data,
+                        void *pkt,
+                        pj_ssize_t bytes_read);
 
 static pj_status_t send_rtcp(pjmedia_stream *stream,
@@ -1716,4 +1719,10 @@
 	stream->rtcp.stat.rx.discard++;
 	return;
+    }
+    
+    /* Check if multiplexing is allowed and the payload indicates RTCP. */
+    if (stream->si.rtcp_mux && hdr->pt >= 64 && hdr->pt <= 95) {
+    	on_rx_rtcp(stream, pkt, bytes_read);
+    	return;
     }
 
@@ -2504,6 +2513,9 @@
     pj_sockaddr_cp(&att_param.rem_addr, &info->rem_addr);
     pj_sockaddr_cp(&stream->rem_rtp_addr, &info->rem_addr);
-    if (pj_sockaddr_has_addr(&info->rem_rtcp.addr))
+    if (stream->si.rtcp_mux) {
+	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_addr);    	
+    } else if (pj_sockaddr_has_addr(&info->rem_rtcp.addr)) {
 	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);
+    }
     att_param.addr_len = pj_sockaddr_get_len(&info->rem_addr);
     att_param.rtp_cb2 = &on_rx_rtp;
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c	(revision 5788)
@@ -526,4 +526,10 @@
     }
 
+    /* Check if "rtcp-mux" is present in the SDP. */
+    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
+    				  "rtcp-mux", NULL);
+    if (attr)
+    	si->rtcp_mux = PJ_TRUE;
+
     /* If "rtcp" attribute is present in the SDP, set the RTCP address
      * from that attribute. Otherwise, calculate from RTP address.
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 5788)
@@ -82,4 +82,6 @@
     pj_sockaddr		 rtcp_src_addr;	/**< Actual source RTCP address.    */
     unsigned		 rtcp_src_cnt;  /**< How many pkt from this addr.   */
+    pj_bool_t		 enable_rtcp_mux;/**< Enable RTP& RTCP multiplexing?*/
+    pj_bool_t		 use_rtcp_mux;	/**< Use RTP & RTCP multiplexing?   */
 
     unsigned		 tx_drop_pct;	/**< Percent of tx pkts to drop.    */
@@ -194,4 +196,5 @@
 static const pj_str_t STR_IP6		= { "IP6", 3 };
 static const pj_str_t STR_RTCP		= { "rtcp", 4 };
+static const pj_str_t STR_RTCP_MUX	= { "rtcp-mux", 8 };
 static const pj_str_t STR_BANDW_RR	= { "RR", 2 };
 static const pj_str_t STR_BANDW_RS	= { "RS", 2 };
@@ -505,5 +508,6 @@
 					 unsigned media_index,
 					 unsigned comp_cnt,
-					 pj_bool_t restart_session)
+					 pj_bool_t restart_session,
+					 pj_bool_t rtcp_mux)
 {
     enum { 
@@ -759,5 +763,13 @@
         }
     }
-    
+
+    /* Add a=rtcp-mux attribute */
+    if (rtcp_mux) {
+	pjmedia_sdp_attr *attr;
+
+	attr = PJ_POOL_ZALLOC_T(sdp_pool, pjmedia_sdp_attr);
+    	attr->name = STR_RTCP_MUX;
+    	m->attr[m->attr_count++] = attr;
+    }
 
     return PJ_SUCCESS;
@@ -895,5 +907,6 @@
     /* Encode ICE in SDP */
     status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 
-				   tp_ice->comp_cnt, PJ_FALSE);
+				   tp_ice->comp_cnt, PJ_FALSE,
+				   tp_ice->enable_rtcp_mux);
     if (status != PJ_SUCCESS) {
 	set_no_ice(tp_ice, "Error encoding SDP answer", status);
@@ -923,4 +936,13 @@
 
     rem_m = rem_sdp->media[media_index];
+
+    /* Check if remote wants RTCP mux */
+    if (tp_ice->enable_rtcp_mux) {
+        pjmedia_sdp_attr *attr;
+
+	attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
+				     &STR_RTCP_MUX, NULL);
+	tp_ice->use_rtcp_mux = (attr? PJ_TRUE: PJ_FALSE);
+    }
 
     /* Get the "ice-ufrag" and "ice-pwd" attributes */
@@ -1064,5 +1086,7 @@
 
     /* Check matched component count and ice_mismatch */
-    if (comp1_found && (tp_ice->comp_cnt==1 || !has_rtcp)) {
+    if (comp1_found &&
+        (tp_ice->comp_cnt==1 || !has_rtcp || tp_ice->use_rtcp_mux))
+    {
 	sdp_state->match_comp_cnt = 1;
 	sdp_state->ice_mismatch = PJ_FALSE;
@@ -1123,4 +1147,58 @@
 }
 
+/* Encode information in SDP if ICE is not used */
+static pj_status_t encode_no_ice_in_sdp( struct transport_ice *tp_ice,
+					 pj_pool_t *pool,
+					 pjmedia_sdp_session *sdp_local,
+					 const pjmedia_sdp_session *rem_sdp,
+					 unsigned media_index)
+{
+    if (tp_ice->enable_rtcp_mux) {
+        pjmedia_sdp_media *m = sdp_local->media[media_index];
+        pjmedia_sdp_attr *attr;
+        pj_bool_t add_rtcp_mux = PJ_TRUE;
+
+	if (rem_sdp)
+	    add_rtcp_mux = tp_ice->use_rtcp_mux;
+	else {
+	    /* For subsequent offer, set it to false first since
+	     * we are still waiting for remote answer.
+	     */
+	    tp_ice->use_rtcp_mux = PJ_FALSE;
+	}
+
+        /* Remove RTCP attribute because for subsequent offers/answers,
+         * the address (obtained from transport_get_info() ) may be
+         * incorrect if we are not yet confirmed to use RTCP mux
+         * (because we are still waiting for remote answer) or
+         * if remote rejects it.
+         */
+        pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "rtcp");
+	
+	if (!tp_ice->use_rtcp_mux && tp_ice->comp_cnt > 1) {
+	    pj_ice_sess_cand cand;
+	    pj_status_t status;
+	    
+	    status = pj_ice_strans_get_def_cand(tp_ice->ice_st, 2, &cand);
+	    if (status == PJ_SUCCESS) {
+	   	/* Add RTCP attribute if the remote doesn't offer or
+	    	 * rejects it.
+	    	 */
+	    	attr = pjmedia_sdp_attr_create_rtcp(pool, &cand.addr);	
+	    	if (attr)
+	            pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
+	    }
+	}
+
+	/* Add a=rtcp-mux attribute. */
+	if (add_rtcp_mux) {
+	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+    	    attr->name = STR_RTCP_MUX;
+    	    m->attr[m->attr_count++] = attr;
+	}
+    }
+    return PJ_SUCCESS;
+}
+
 
 /* Verify incoming offer and create initial answer */
@@ -1151,4 +1229,6 @@
     if (tp_ice->rem_offer_state.match_comp_cnt==0) {
 	set_no_ice(tp_ice, "No ICE found in SDP offer", PJ_SUCCESS);
+	encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
+			     media_index);
 	return PJ_SUCCESS;
     }
@@ -1164,5 +1244,5 @@
     status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index, 
 				   tp_ice->rem_offer_state.match_comp_cnt,
-				   PJ_FALSE);
+				   PJ_FALSE, tp_ice->use_rtcp_mux);
     if (status != PJ_SUCCESS) {
 	set_no_ice(tp_ice, "Error encoding SDP answer", status);
@@ -1184,4 +1264,5 @@
     if (pj_ice_strans_has_sess(tp_ice->ice_st) == PJ_FALSE) {
 	/* We don't have ICE */
+	encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, NULL, media_index);
 	return PJ_SUCCESS;
     }
@@ -1189,5 +1270,5 @@
     comp_cnt = pj_ice_strans_get_running_comp_cnt(tp_ice->ice_st);
     return encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
-				 comp_cnt, PJ_FALSE);
+				 comp_cnt, PJ_FALSE, tp_ice->enable_rtcp_mux);
 }
 
@@ -1218,4 +1299,6 @@
 	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
 	    /* Remote no longer offers ICE */
+	    encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
+			     	 media_index);
 	    return PJ_SUCCESS;
 	}
@@ -1228,5 +1311,6 @@
 	status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
 				       tp_ice->rem_offer_state.match_comp_cnt,
-				       tp_ice->rem_offer_state.ice_restart);
+				       tp_ice->rem_offer_state.ice_restart,
+				       tp_ice->use_rtcp_mux);
 	if (status != PJ_SUCCESS)
 	    return status;
@@ -1241,4 +1325,6 @@
 	if (tp_ice->rem_offer_state.match_comp_cnt == 0) {
 	    /* Remote does not support ICE */
+	    encode_no_ice_in_sdp(tp_ice, sdp_pool, loc_sdp, rem_sdp,
+			     	 media_index);
 	    return PJ_SUCCESS;
 	}
@@ -1262,5 +1348,6 @@
 	status = encode_session_in_sdp(tp_ice, sdp_pool, loc_sdp, media_index,
 				       tp_ice->rem_offer_state.match_comp_cnt,
-				       tp_ice->rem_offer_state.ice_restart);
+				       tp_ice->rem_offer_state.ice_restart,
+				       tp_ice->use_rtcp_mux);
 	if (status != PJ_SUCCESS)
 	    return status;
@@ -1291,4 +1378,5 @@
 
     tp_ice->media_option = options;
+    tp_ice->enable_rtcp_mux = ((options & PJMEDIA_TPMED_RTCP_MUX) != 0);
     tp_ice->oa_role = ROLE_NONE;
     tp_ice->initial_sdp = PJ_TRUE;
@@ -1402,5 +1490,6 @@
 	}
 
-	cand_cnt++;
+	if (!tp_ice->use_rtcp_mux || cand[cand_cnt].comp_id < 2)
+	    cand_cnt++;
     }
 
@@ -1655,5 +1744,7 @@
 
     /* Get RTCP default address */
-    if (tp_ice->comp_cnt > 1) {
+    if (tp_ice->use_rtcp_mux) {
+	pj_sockaddr_cp(&info->sock_info.rtcp_addr_name, &cand.addr);
+    } else if (tp_ice->comp_cnt > 1) {
 	status = pj_ice_strans_get_def_cand(tp_ice->ice_st, 2, &cand);
 	if (status != PJ_SUCCESS)
@@ -1750,4 +1841,9 @@
     tp_ice->rtcp_cb = att_param->rtcp_cb;
 
+    /* Check again if we are multiplexing RTP & RTCP. */
+    tp_ice->use_rtcp_mux = (pj_sockaddr_has_addr(&att_param->rem_addr) &&
+    			    pj_sockaddr_cmp(&att_param->rem_addr,
+					    &att_param->rem_rtcp) == 0);
+
     pj_memcpy(&tp_ice->remote_rtp, &att_param->rem_addr, att_param->addr_len);
     pj_memcpy(&tp_ice->remote_rtcp, &att_param->rem_rtcp, att_param->addr_len);
@@ -1815,10 +1911,12 @@
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    if (tp_ice->comp_cnt > 1) {
+
+    if (tp_ice->comp_cnt > 1 || tp_ice->use_rtcp_mux) {
+        unsigned comp_id = (tp_ice->use_rtcp_mux? 1: 2);
 	if (addr == NULL) {
 	    addr = &tp_ice->remote_rtcp;
 	    addr_len = pj_sockaddr_get_len(addr);
-	}
-	return pj_ice_strans_sendto(tp_ice->ice_st, 2, pkt, size, 
+	}	  
+	return pj_ice_strans_sendto(tp_ice->ice_st, comp_id, pkt, size,
 				    addr, addr_len);
     } else {
@@ -1889,8 +1987,10 @@
 					sizeof(addr_text), 3)));
 
-	    /* Also update remote RTCP address if actual RTCP source
-	     * address is not heard yet.
-	     */
-	    if (!pj_sockaddr_has_addr(&tp_ice->rtcp_src_addr)) {
+	    if (tp_ice->use_rtcp_mux) {
+	    	pj_sockaddr_cp(&tp_ice->remote_rtcp, &tp_ice->remote_rtp);
+	    } else if (!pj_sockaddr_has_addr(&tp_ice->rtcp_src_addr)) {
+	        /* Also update remote RTCP address if actual RTCP source
+	         * address is not heard yet.
+	         */
 		pj_uint16_t port;
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5788)
@@ -234,4 +234,5 @@
     pjmedia_srtp_setting setting;
     unsigned		 media_option;
+    pj_bool_t		 use_rtcp_mux;	    /**< Use RTP& RTCP multiplexing?*/
 
     /* SRTP policy */
@@ -1138,4 +1139,8 @@
     }
 
+    /* Check if we are multiplexing RTP & RTCP. */
+    srtp->use_rtcp_mux = (pj_sockaddr_has_addr(&param->rem_addr) &&
+    			  pj_sockaddr_cmp(&param->rem_addr,
+    					  &param->rem_rtcp) == 0);
     srtp->member_tp_attached = PJ_TRUE;
     return PJ_SUCCESS;
@@ -1347,5 +1352,18 @@
 	return;
     }
+
+    /* Check if multiplexing is allowed and the payload indicates RTCP. */
+    if (srtp->use_rtcp_mux) {
+    	pjmedia_rtp_hdr *hdr = (pjmedia_rtp_hdr *)pkt;
+  
+	if (hdr->pt >= 64 && hdr->pt <= 95) {   
+	    pj_lock_release(srtp->mutex);
+	    srtp_rtcp_cb(srtp, pkt, size);
+    	    return;
+    	}
+    }
+    
     err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len);
+    
     if (srtp->probation_cnt > 0 &&
 	(err == srtp_err_status_replay_old ||
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5788)
@@ -986,5 +986,11 @@
 	    pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
 	    ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
-	    if (pj_sockaddr_has_addr(&ds->rem_rtcp)) {
+	    if (pj_sockaddr_cmp(&info.sock_info.rtp_addr_name,
+	    			&info.sock_info.rtcp_addr_name) == 0)
+	    {
+	    	/* Using RTP & RTCP multiplexing */
+	    	pj_sockaddr_cp(&ds->rem_rtcp, &ds->rem_addr);
+	    	pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+	    } else if (pj_sockaddr_has_addr(&ds->rem_rtcp)) {
 		pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
 	    } else {
@@ -1187,19 +1193,33 @@
     {
 	pjmedia_transport_attach_param ap;
+	pjmedia_transport_info info;
+
 	pj_bzero(&ap, sizeof(ap));
 	ap.user_data = ds->srtp;
+	pjmedia_transport_get_info(ds->srtp->member_tp, &info);
 
 	if (sdp_remote)
 	    get_rem_addrs(ds, sdp_remote, media_index);
 
-	if (pj_sockaddr_has_addr(&ds->rem_addr))
+	if (pj_sockaddr_has_addr(&ds->rem_addr)) {
 	    pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
-	else
+	} else if (pj_sockaddr_has_addr(&info.sock_info.rtp_addr_name)) {
+	    pj_sockaddr_cp(&ap.rem_addr, &info.sock_info.rtp_addr_name);
+	} else {
 	    pj_sockaddr_init(pj_AF_INET(), &ap.rem_addr, 0, 0);
-
-	if (pj_sockaddr_has_addr(&ds->rem_rtcp))
+	}
+
+	if (pj_sockaddr_cmp(&info.sock_info.rtp_addr_name,
+	    		    &info.sock_info.rtcp_addr_name) == 0)
+	{
+	    /* Using RTP & RTCP multiplexing */
+	    pj_sockaddr_cp(&ap.rem_rtcp, &ap.rem_addr);
+	} else if (pj_sockaddr_has_addr(&ds->rem_rtcp)) {
 	    pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
-	else
+	} else if (pj_sockaddr_has_addr(&info.sock_info.rtcp_addr_name)) {
+	    pj_sockaddr_cp(&ap.rem_rtcp, &info.sock_info.rtcp_addr_name);
+	} else {
 	    pj_sockaddr_init(pj_AF_INET(), &ap.rem_rtcp, 0, 0);
+	}
 
 	ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5788)
@@ -83,4 +83,6 @@
     char		rtp_pkt[RTP_LEN];/**< Incoming RTP packet buffer    */
 
+    pj_bool_t		enable_rtcp_mux;/**< Enable RTP & RTCP multiplexing?*/
+    pj_bool_t		use_rtcp_mux;	/**< Use RTP & RTCP multiplexing?   */
     pj_sock_t		rtcp_sock;	/**< RTCP socket		    */
     pj_sockaddr		rtcp_addr_name;	/**< Published RTCP address.	    */
@@ -179,4 +181,5 @@
 };
 
+static const pj_str_t STR_RTCP_MUX	= { "rtcp-mux", 8 };
 
 /**
@@ -398,5 +401,5 @@
     if (status != PJ_EPENDING)
 	goto on_error;
-#endif    
+#endif	
 
     tp->ioqueue = ioqueue;
@@ -535,8 +538,11 @@
 					sizeof(addr_text), 3)));
 
-	    /* Also update remote RTCP address if actual RTCP source
-	     * address is not heard yet.
-	     */
-	    if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) {
+	    if (udp->use_rtcp_mux) {
+	    	pj_sockaddr_cp(&udp->rem_rtcp_addr, &udp->rem_rtp_addr);
+	    	pj_sockaddr_cp(&udp->rtcp_src_addr, &udp->rem_rtcp_addr);
+	    } else if (!pj_sockaddr_has_addr(&udp->rtcp_src_addr)) {
+	        /* Also update remote RTCP address if actual RTCP source
+	         * address is not heard yet.
+	         */
 		pj_uint16_t port;
 
@@ -666,5 +672,7 @@
     info->sock_info.rtp_addr_name = udp->rtp_addr_name;
     info->sock_info.rtcp_sock = udp->rtcp_sock;
-    info->sock_info.rtcp_addr_name = udp->rtcp_addr_name;
+    info->sock_info.rtcp_addr_name = (udp->use_rtcp_mux?
+    				      udp->rtp_addr_name:
+    				      udp->rtcp_addr_name);
 
     /* Get remote address originating RTP & RTCP. */
@@ -709,4 +717,8 @@
     /* Must not be "attached" to existing application */
     //PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP);
+
+    /* Check again if we are multiplexing RTP & RTCP. */
+    udp->use_rtcp_mux = (pj_sockaddr_has_addr(rem_addr) &&
+			 pj_sockaddr_cmp(rem_addr, rem_rtcp) == 0);
 
     /* Lock the ioqueue keys to make sure that callbacks are
@@ -978,5 +990,6 @@
 
     sent = size;
-    status = pj_ioqueue_sendto( udp->rtcp_key, &udp->rtcp_write_op,
+    status = pj_ioqueue_sendto( (udp->use_rtcp_mux? udp->rtp_key:
+    				 udp->rtcp_key), &udp->rtcp_write_op,
 				pkt, &sent, 0, addr, addr_len);
 
@@ -998,4 +1011,5 @@
     PJ_ASSERT_RETURN(tp && pool, PJ_EINVAL);
     udp->media_options = options;
+    udp->enable_rtcp_mux = ((options & PJMEDIA_TPMED_RTCP_MUX) != 0);
 
     PJ_UNUSED_ARG(sdp_remote);
@@ -1026,4 +1040,47 @@
 	    pjmedia_sdp_media_deactivate(pool, m_loc);
 	    return PJMEDIA_SDP_EINPROTO;
+	}
+    }
+    
+    if (udp->enable_rtcp_mux) {
+        pjmedia_sdp_media *m = sdp_local->media[media_index];
+        pjmedia_sdp_attr *attr;
+        pj_bool_t add_rtcp_mux = PJ_TRUE;
+
+	udp->use_rtcp_mux = PJ_FALSE;
+
+	/* Check if remote wants RTCP mux */
+	if (rem_sdp) {
+	    pjmedia_sdp_media *rem_m = rem_sdp->media[media_index];
+	    
+	    attr = pjmedia_sdp_attr_find(rem_m->attr_count, rem_m->attr, 
+				         &STR_RTCP_MUX, NULL);
+	    udp->use_rtcp_mux = (attr? PJ_TRUE: PJ_FALSE);
+	    add_rtcp_mux = udp->use_rtcp_mux;
+	}
+
+        /* Remove RTCP attribute because for subsequent offers/answers,
+         * the address (obtained from transport_get_info() ) may be
+         * incorrect if we are not yet confirmed to use RTCP mux
+         * (because we are still waiting for remote answer) or
+         * if remote rejects it.
+         */
+        pjmedia_sdp_attr_remove_all(&m->attr_count, m->attr, "rtcp");
+	
+	if (!udp->use_rtcp_mux) {
+	   /* Add RTCP attribute if the remote doesn't offer or
+	    * rejects it.
+	    */
+	    attr = pjmedia_sdp_attr_create_rtcp(pool,
+					        &udp->rtcp_addr_name);	
+	    if (attr)
+	        pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
+	}
+
+	/* Add a=rtcp-mux attribute. */
+	if (add_rtcp_mux) {
+	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
+    	    attr->name = STR_RTCP_MUX;
+    	    m->attr[m->attr_count++] = attr;
 	}
     }
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5788)
@@ -219,4 +219,7 @@
 			     pj_bool_t with_bye);
 
+static void on_rx_rtcp( void *data,
+                        void *pkt, 
+                        pj_ssize_t bytes_read);
 
 #if TRACE_JB
@@ -650,4 +653,10 @@
 	stream->rtcp.stat.rx.discard++;
 	return;
+    }
+
+    /* Check if multiplexing is allowed and the payload indicates RTCP. */
+    if (stream->info.rtcp_mux && hdr->pt >= 64 && hdr->pt <= 95) {
+    	on_rx_rtcp(stream, pkt, bytes_read);
+    	return;
     }
 
@@ -1737,6 +1746,9 @@
     pj_sockaddr_cp(&att_param.rem_addr, &info->rem_addr);
     pj_sockaddr_cp(&stream->rem_rtp_addr, &info->rem_addr);
-    if (pj_sockaddr_has_addr(&info->rem_rtcp.addr))
-	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);    
+    if (info->rtcp_mux) {
+	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_addr);    	
+    } else if (pj_sockaddr_has_addr(&info->rem_rtcp.addr)) {
+	pj_sockaddr_cp(&att_param.rem_rtcp, &info->rem_rtcp);
+    }    
     att_param.addr_len = pj_sockaddr_get_len(&info->rem_addr);
     att_param.rtp_cb2 = &on_rx_rtp;
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c	(revision 5787)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c	(revision 5788)
@@ -349,4 +349,10 @@
     }
 
+    /* Check if "rtcp-mux" is present in the SDP. */
+    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
+    				  "rtcp-mux", NULL);
+    if (attr)
+    	si->rtcp_mux = PJ_TRUE;
+
     /* If "rtcp" attribute is present in the SDP, set the RTCP address
      * from that attribute. Otherwise, calculate from RTP address.
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 5787)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 5788)
@@ -192,4 +192,5 @@
     puts  ("  --turn-user         TURN username");
     puts  ("  --turn-passwd       TURN password");
+    puts  ("  --rtcp-mux          Enable RTP & RTCP multiplexing (default: no)");
 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
     puts  ("  --srtp-keying       SRTP keying method for outgoing SDP offer.");
@@ -360,5 +361,6 @@
 	   OPT_USE_ICE, OPT_ICE_REGULAR, OPT_USE_SRTP, OPT_SRTP_SECURE,
 	   OPT_USE_TURN, OPT_ICE_MAX_HOSTS, OPT_ICE_NO_RTCP, OPT_TURN_SRV,
-	   OPT_TURN_TCP, OPT_TURN_USER, OPT_TURN_PASSWD, OPT_SRTP_KEYING,
+	   OPT_TURN_TCP, OPT_TURN_USER, OPT_TURN_PASSWD, OPT_RTCP_MUX,
+	   OPT_SRTP_KEYING,
 	   OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC,
 	   OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
@@ -453,4 +455,5 @@
 	{ "turn-user",	1, 0, OPT_TURN_USER},
 	{ "turn-passwd",1, 0, OPT_TURN_PASSWD},
+	{ "rtcp-mux",	0, 0, OPT_RTCP_MUX},
 
 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
@@ -1022,4 +1025,8 @@
 	    break;
 
+	case OPT_RTCP_MUX:
+	    cur_acc->enable_rtcp_mux = PJ_TRUE;
+	    break;
+
 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
 	case OPT_USE_SRTP:
@@ -1761,4 +1768,7 @@
 	pj_strcat2(result, line);
     }
+
+    if (acc_cfg->enable_rtcp_mux)
+	pj_strcat2(result, "--rtcp-mux\n");
 }
 
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5787)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5788)
@@ -3908,4 +3908,9 @@
     pjsua_ip_change_acc_cfg ip_change_cfg;
 
+    /**
+     * Enable RTP and RTCP multiplexing.
+     */
+    pj_bool_t		enable_rtcp_mux;
+
 } pjsua_acc_config;
 
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5787)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5788)
@@ -84,4 +84,5 @@
     pjsua_med_tp_st	 tp_st;     /**< Media transport state		    */
     pj_bool_t            use_custom_med_tp;/**< Use custom media transport? */
+    pj_bool_t		 enable_rtcp_mux;/**< Enable RTP& RTCP multiplexing?*/
     pj_sockaddr		 rtp_addr;  /**< Current RTP source address
 					    (used to update ICE default
Index: /pjproject/trunk/pjsip/include/pjsua2/account.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5787)
+++ /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5788)
@@ -850,4 +850,9 @@
     pjsua_ipv6_use	ipv6Use;
 
+    /**
+     * Enable RTP and RTCP multiplexing.
+     */
+    pj_bool_t		rtcpMuxEnabled;
+
 public:
     /**
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 5787)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 5788)
@@ -1339,4 +1339,5 @@
     acc->cfg.nat64_opt = cfg->nat64_opt;
     acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
+    acc->cfg.enable_rtcp_mux = cfg->enable_rtcp_mux;
 
     /* STUN and Media customization */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 5787)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 5788)
@@ -4389,5 +4389,7 @@
         pjmedia_transport_media_stop(call_med->tp);
         pjmedia_transport_media_create(call_med->tp, call->inv->pool_prov,
-                                       0, NULL, mi);
+                                       (call_med->enable_rtcp_mux?
+            			    	PJMEDIA_TPMED_RTCP_MUX: 0),
+            			       NULL, mi);
 
         PJ_LOG(4, (THIS_FILE, "Restarting ICE for media %d", mi));
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5787)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5788)
@@ -579,5 +579,6 @@
     pj_sockaddr_cp(&skinfo->rtcp_addr_name, &mapped_addr[1]);
 
-    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",
+    PJ_LOG(4,(THIS_FILE, "RTP%s socket reachable at %s",
+	      (call_med->enable_rtcp_mux? " & RTCP": ""),
 	      pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
 				sizeof(addr_buf), 3)));
@@ -1832,7 +1833,9 @@
 
             if (call_med->tp) {
+            	unsigned options = (call_med->enable_rtcp_mux?
+            			    PJMEDIA_TPMED_RTCP_MUX: 0);
                 status = pjmedia_transport_media_create(
                              call_med->tp, tmp_pool,
-                             0, call->async_call.rem_sdp, mi);
+                             options, call->async_call.rem_sdp, mi);
             }
 	    if (status != PJ_SUCCESS) {
@@ -2154,4 +2157,6 @@
 
 	if (enabled) {
+	    call_med->enable_rtcp_mux = acc->cfg.enable_rtcp_mux;
+
 	    status = pjsua_call_media_init(call_med, media_type,
 	                                   &acc->cfg.rtp_cfg,
@@ -2790,4 +2795,6 @@
 	 * internally by ICE and does not need to cause media restart.
 	 */
+	if (old_si->rtcp_mux != new_si->rtcp_mux)
+	    return PJ_TRUE;
 	if (!is_ice_running(call_med->tp) &&
 	    pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
@@ -2852,4 +2859,6 @@
 	 * internally by ICE and does not need to cause media restart.
 	 */
+	if (old_si->rtcp_mux != new_si->rtcp_mux)
+	    return PJ_TRUE;
 	if (!is_ice_running(call_med->tp) &&
 	    pj_sockaddr_cmp(&old_si->rem_addr, &new_si->rem_addr))
@@ -3027,4 +3036,11 @@
 			     call_id, mi));
 		goto on_check_med_status;
+	    }
+
+	    /* Check if remote wants RTP and RTCP multiplexing,
+	     * but we don't enable it.
+	     */
+	    if (si->rtcp_mux && !call_med->enable_rtcp_mux) {
+	        si->rtcp_mux = PJ_FALSE;
 	    }
 
@@ -3071,4 +3087,6 @@
 
 		if (call->inv->following_fork) {
+		    unsigned options = (call_med->enable_rtcp_mux?
+            			        PJMEDIA_TPMED_RTCP_MUX: 0);
 		    /* Normally media transport will automatically restart
 		     * itself (if needed, based on info from the SDP) in
@@ -3088,5 +3106,5 @@
 		    status = pjmedia_transport_media_create(call_med->tp,
 							    tmp_pool,
-							    0, NULL, mi);
+							    options, NULL, mi);
 		    if (status != PJ_SUCCESS) {
 			PJ_PERROR(1,(THIS_FILE, status,
@@ -3205,4 +3223,11 @@
 	    }
 
+	    /* Check if remote wants RTP and RTCP multiplexing,
+	     * but we don't enable it.
+	     */
+	    if (si->rtcp_mux && !call_med->enable_rtcp_mux) {
+	        si->rtcp_mux = PJ_FALSE;
+	    }
+
 	    /* Check if this media is changed */
 	    stream_info.type = PJMEDIA_TYPE_VIDEO;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5787)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5788)
@@ -1720,4 +1720,5 @@
     pjmedia_sdp_media *sdp_m;
     pjmedia_transport_info tpinfo;
+    unsigned options;
     pj_status_t status;
 
@@ -1758,5 +1759,6 @@
 
     /* Init transport media */
-    status = pjmedia_transport_media_create(call_med->tp, pool, 0,
+    options = (call_med->enable_rtcp_mux? PJMEDIA_TPMED_RTCP_MUX: 0);
+    status = pjmedia_transport_media_create(call_med->tp, pool, options,
 					    NULL, call_med->idx);
     if (status != PJ_SUCCESS)
@@ -1909,6 +1911,9 @@
 	/* Init transport media */
 	if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
-	    status = pjmedia_transport_media_create(call_med->tp, pool, 0,
-						    NULL, call_med->idx);
+	    unsigned options = (call_med->enable_rtcp_mux?
+            			PJMEDIA_TPMED_RTCP_MUX: 0);
+	    status = pjmedia_transport_media_create(call_med->tp, pool,
+						    options, NULL,
+						    call_med->idx);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
Index: /pjproject/trunk/pjsip/src/pjsua2/account.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5787)
+++ /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5788)
@@ -359,4 +359,5 @@
     NODE_READ_NUM_T   ( this_node, pjsua_ipv6_use, ipv6Use);
     NODE_READ_OBJ     ( this_node, transportConfig);
+    NODE_READ_BOOL    ( this_node, rtcpMuxEnabled);
 }
 
@@ -372,4 +373,5 @@
     NODE_WRITE_NUM_T   ( this_node, pjsua_ipv6_use, ipv6Use);
     NODE_WRITE_OBJ     ( this_node, transportConfig);
+    NODE_WRITE_BOOL    ( this_node, rtcpMuxEnabled);
 }
 
@@ -560,4 +562,5 @@
     ret.srtp_opt		= mediaConfig.srtpOpt.toPj();
     ret.ipv6_media_use		= mediaConfig.ipv6Use;
+    ret.enable_rtcp_mux		= mediaConfig.rtcpMuxEnabled;
 
     // AccountVideoConfig
@@ -735,4 +738,5 @@
     mediaConfig.srtpOpt.fromPj(prm.srtp_opt);
     mediaConfig.ipv6Use		= prm.ipv6_media_use;
+    mediaConfig.rtcpMuxEnabled	= prm.enable_rtcp_mux;
 
     // AccountVideoConfig
