Index: pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 5783)
+++ 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;
 	}
     }
