Index: /pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 5747)
+++ /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 5748)
@@ -177,4 +177,9 @@
  */
 #define PJMEDIA_SDP_EINBANDW	    (PJMEDIA_ERRNO_START+37)    /* 220037 */
+/**
+ * @hideinitializer
+ * Invalid SDP "ssrc" attribute.
+ */
+#define PJMEDIA_SDP_EINSSRC	    (PJMEDIA_ERRNO_START+38)    /* 220038 */
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/rtp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/rtp.h	(revision 5747)
+++ /pjproject/trunk/pjmedia/include/pjmedia/rtp.h	(revision 5748)
@@ -190,4 +190,5 @@
     pj_uint16_t		    out_pt;	/**< Default outgoing payload type. */
     pj_uint32_t		    out_extseq; /**< Outgoing extended seq #.	    */
+    pj_bool_t		    has_peer_ssrc;/**< Has peer SSRC?		    */
     pj_uint32_t		    peer_ssrc;  /**< Peer SSRC.			    */
     pj_uint32_t		    received;   /**< Number of received packets.    */
@@ -249,7 +250,9 @@
 					 bit #1: sender SSRC
 					 bit #2: sequence
-					 bit #3: timestamp		    */
+					 bit #3: timestamp
+					 bit #4: peer SSRC		    */
     int		     default_pt;    /**< Default payload type.		    */
     pj_uint32_t	     sender_ssrc;   /**< Sender SSRC.			    */
+    pj_uint32_t	     peer_ssrc;     /**< Peer SSRC.			    */
     pj_uint16_t	     seq;	    /**< Sequence.			    */
     pj_uint32_t	     ts;	    /**< Timestamp.			    */
Index: /pjproject/trunk/pjmedia/include/pjmedia/sdp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 5747)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 5748)
@@ -332,4 +332,41 @@
 PJ_DECL(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_rtcp(pj_pool_t *pool,
 							const pj_sockaddr *a);
+
+
+/**
+ * This structure describes SDP \a ssrc attribute.
+ */
+typedef struct pjmedia_sdp_ssrc_attr
+{
+    pj_uint32_t	ssrc;	    /**< RTP SSRC.	*/
+    pj_str_t	cname; 	    /**< RTCP CNAME.	*/
+} pjmedia_sdp_ssrc_attr;
+
+
+/**
+ * Parse a generic SDP attribute to get SDP ssrc attribute values.
+ *
+ * @param attr		Generic attribute to be converted to ssrc, which
+ *			name must be "ssrc".
+ * @param ssrc		SDP ssrc attribute to be initialized.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_sdp_attr_get_ssrc(const pjmedia_sdp_attr *attr,
+					       pjmedia_sdp_ssrc_attr *rtcp);
+
+
+/**
+ * Create a=ssrc attribute.
+ *
+ * @param pool		Pool to create the attribute.
+ * @param ssrc		SSRC identifier.
+ * @param cname		CNAME.
+ *
+ * @return		SDP SSRC attribute.
+ */
+PJ_DECL(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_ssrc(pj_pool_t *pool,
+							pj_uint32_t ssrc,
+							const pj_str_t *cname);
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 5747)
+++ /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 5748)
@@ -117,4 +117,8 @@
     int			rx_event_pt;/**< Incoming pt for telephone-events.  */
     pj_uint32_t		ssrc;	    /**< RTP SSRC.			    */
+    pj_str_t		cname; 	    /**< RTCP CNAME.			    */
+    pj_bool_t		has_rem_ssrc;/**<Has remote RTP SSRC?		    */
+    pj_uint32_t		rem_ssrc;   /**< Remote RTP SSRC.		    */
+    pj_str_t		rem_cname;  /**< Remote RTCP CNAME.		    */
     pj_uint32_t		rtp_ts;	    /**< Initial RTP timestamp.		    */
     pj_uint16_t		rtp_seq;    /**< Initial RTP sequence number.	    */
Index: /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h	(revision 5747)
+++ /pjproject/trunk/pjmedia/include/pjmedia/vid_stream.h	(revision 5748)
@@ -159,4 +159,8 @@
     unsigned		rx_pt;	    /**< Incoming codec paylaod type.	    */
     pj_uint32_t		ssrc;	    /**< RTP SSRC.			    */
+    pj_str_t		cname; 	    /**< RTCP CNAME.			    */
+    pj_bool_t		has_rem_ssrc;/**<Has remote RTP SSRC?		    */
+    pj_uint32_t		rem_ssrc;   /**< Remote RTP SSRC.		    */
+    pj_str_t		rem_cname;  /**< Remote RTCP CNAME.		    */
     pj_uint32_t		rtp_ts;	    /**< Initial RTP timestamp.		    */
     pj_uint16_t		rtp_seq;    /**< Initial RTP sequence number.	    */
Index: /pjproject/trunk/pjmedia/src/pjmedia/errno.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 5748)
@@ -65,7 +65,8 @@
     PJ_BUILD_ERR( PJMEDIA_SDP_EINPT,	    "Invalid SDP payload type in media line" ),
     PJ_BUILD_ERR( PJMEDIA_SDP_EINFMTP,	    "Invalid SDP fmtp attribute" ),
-    PJ_BUILD_ERR( PJMEDIA_SDP_EINRTCP,	    "Invalid SDP rtcp attribyte" ),
+    PJ_BUILD_ERR( PJMEDIA_SDP_EINRTCP,	    "Invalid SDP rtcp attribute" ),
     PJ_BUILD_ERR( PJMEDIA_SDP_EINPROTO,	    "Invalid SDP media transport protocol" ),
     PJ_BUILD_ERR( PJMEDIA_SDP_EINBANDW,	    "Invalid SDP bandwidth info line" ),
+    PJ_BUILD_ERR( PJMEDIA_SDP_EINSSRC,	    "Invalid SDP ssrc attribute" ),
 
     /* SDP negotiator errors. */
Index: /pjproject/trunk/pjmedia/src/pjmedia/rtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/rtp.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/rtp.c	(revision 5748)
@@ -109,4 +109,8 @@
     if (settings.flags & 8)
 	ses->out_hdr.ts = pj_htonl(settings.ts);
+    if (settings.flags & 16) {
+        ses->has_peer_ssrc = PJ_TRUE;
+	ses->peer_ssrc = settings.peer_ssrc;
+    }
 
     return PJ_SUCCESS;
@@ -238,5 +242,6 @@
 
     /* Check SSRC. */
-    if (ses->peer_ssrc == 0) ses->peer_ssrc = pj_ntohl(hdr->ssrc);
+    if (!ses->has_peer_ssrc && ses->peer_ssrc == 0)
+        ses->peer_ssrc = pj_ntohl(hdr->ssrc);
 
     if (pj_ntohl(hdr->ssrc) != ses->peer_ssrc) {
Index: /pjproject/trunk/pjmedia/src/pjmedia/sdp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 5748)
@@ -471,4 +471,86 @@
 	return NULL;
     }
+
+    return attr;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_ssrc(const pjmedia_sdp_attr *attr,
+					      pjmedia_sdp_ssrc_attr *ssrc)
+{
+    pj_scanner scanner;
+    pj_str_t token;
+    pj_status_t status = -1;
+    PJ_USE_EXCEPTION;
+
+    PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "ssrc")==0, PJ_EINVALIDOP);
+
+    if (attr->value.slen == 0)
+        return PJMEDIA_SDP_EINATTR;
+
+    init_sdp_parser();
+
+    /* ssrc BNF:
+     *  a=ssrc:<ssrc-id> <attribute>
+     *	a=ssrc:<ssrc-id> <attribute>:<value>
+     */
+
+    /* The buffer passed to the scanner is not guaranteed to be NULL
+     * terminated, but should be safe. See ticket #2063.
+     */
+    pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen,
+		 PJ_SCAN_AUTOSKIP_WS, &on_scanner_error);
+
+    /* Init */
+    pj_bzero(ssrc, sizeof(*ssrc));
+
+    /* Parse */
+    PJ_TRY {
+        pj_str_t attr;
+
+	/* Get the ssrc */
+	pj_scan_get(&scanner, &cs_digit, &token);
+	ssrc->ssrc = pj_strtoul(&token);
+
+    	pj_scan_get_char(&scanner);
+	pj_scan_get(&scanner, &cs_token, &attr);
+	
+	/* Get cname attribute, if any */
+	if (!pj_scan_is_eof(&scanner) &&
+	    pj_scan_get_char(&scanner) == ':' &&
+	    pj_strcmp2(&attr, "cname"))
+	{
+	    pj_scan_get(&scanner, &cs_token, &ssrc->cname);
+	}
+
+	status = PJ_SUCCESS;
+
+    }
+    PJ_CATCH_ANY {
+	status = PJMEDIA_SDP_EINSSRC;
+    }
+    PJ_END;
+
+    pj_scan_fini(&scanner);
+    return status;
+}
+
+
+PJ_DEF(pjmedia_sdp_attr*) pjmedia_sdp_attr_create_ssrc( pj_pool_t *pool,
+							pj_uint32_t ssrc,
+							const pj_str_t *cname)
+{
+    pjmedia_sdp_attr *attr;
+
+    if (cname->slen == 0)
+        return NULL;
+
+    attr = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_attr);
+    attr->name = pj_str("ssrc");
+    attr->value.ptr = (char*) pj_pool_alloc(pool, cname->slen+7 /* " cname:"*/
+    						  + 10 /* 32-bit integer */);
+    attr->value.slen = pj_ansi_snprintf(attr->value.ptr, cname->slen+17,
+    					"%d cname:%.*s", ssrc,
+			   	   	(int)cname->slen, cname->ptr);
 
     return attr;
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 5748)
@@ -2023,13 +2023,12 @@
 
     /* Create RTP and RTCP sessions: */
-
-    if (param->rtp_seq_ts_set == 0) {
-	status = pjmedia_rtp_session_init(&channel->rtp, pt, param->ssrc);
-    } else {
+    {
 	pjmedia_rtp_session_setting settings;
 
-	settings.flags = (pj_uint8_t)((param->rtp_seq_ts_set << 2) | 3);
+	settings.flags = (pj_uint8_t)((param->rtp_seq_ts_set << 2) |
+				      (param->has_rem_ssrc << 4) | 3);
 	settings.default_pt = pt;
 	settings.sender_ssrc = param->ssrc;
+	settings.peer_ssrc = param->rem_ssrc;
 	settings.seq = param->rtp_seq;
 	settings.ts = param->rtp_ts;
@@ -2125,14 +2124,16 @@
 #endif
 
-    /* Build random RTCP CNAME. CNAME has user@host format */
-    stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
-    pj_create_random_string(p, 5);
-    p += 5;
-    *p++ = '@'; *p++ = 'p'; *p++ = 'j';
-    pj_create_random_string(p, 6);
-    p += 6;
-    *p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
-    stream->cname.slen = p - stream->cname.ptr;
-
+    stream->cname = info->cname;
+    if (stream->cname.slen == 0) {
+	/* Build random RTCP CNAME. CNAME has user@host format */
+    	stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
+    	pj_create_random_string(p, 5);
+    	p += 5;
+    	*p++ = '@'; *p++ = 'p'; *p++ = 'j';
+    	pj_create_random_string(p, 6);
+    	p += 6;
+    	*p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
+    	stream->cname.slen = p - stream->cname.ptr;
+    }
 
     /* Create mutex to protect jitter buffer: */
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream_info.c	(revision 5748)
@@ -367,4 +367,5 @@
     int rem_af, local_af;
     pj_sockaddr local_addr;
+    unsigned i;
     pj_status_t status;
 
@@ -555,4 +556,21 @@
     }
 
+    /* Check if "ssrc" attribute is present in the SDP. */
+    for (i = 0; i < rem_m->attr_count; i++) {
+	if (pj_strcmp2(&rem_m->attr[i]->name, "ssrc") == 0) {
+	    pjmedia_sdp_ssrc_attr ssrc;
+
+	    status = pjmedia_sdp_attr_get_ssrc(
+	    		(const pjmedia_sdp_attr *)rem_m->attr[i], &ssrc);
+	    if (status == PJ_SUCCESS) {
+	        si->has_rem_ssrc = PJ_TRUE;
+	    	si->rem_ssrc = ssrc.ssrc;
+	    	if (ssrc.cname.slen > 0) {
+	    	    pj_strdup(pool, &si->rem_cname, &ssrc.cname);
+	    	    break;
+	    	}
+	    }
+	}
+    }
 
     /* Get the payload number for receive channel. */
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 5748)
@@ -1361,12 +1361,12 @@
 
     /* Create RTP and RTCP sessions: */
-    if (info->rtp_seq_ts_set == 0) {
-	status = pjmedia_rtp_session_init(&channel->rtp, pt, info->ssrc);
-    } else {
+    {
 	pjmedia_rtp_session_setting settings;
 
-	settings.flags = (pj_uint8_t)((info->rtp_seq_ts_set << 2) | 3);
+	settings.flags = (pj_uint8_t)((info->rtp_seq_ts_set << 2) |
+				      (info->has_rem_ssrc << 4) | 3);
 	settings.default_pt = pt;
 	settings.sender_ssrc = info->ssrc;
+	settings.peer_ssrc = info->rem_ssrc;
 	settings.seq = info->rtp_seq;
 	settings.ts = info->rtp_ts;
@@ -1497,14 +1497,16 @@
     stream->num_keyframe = info->sk_cfg.count;
 
-    /* Build random RTCP CNAME. CNAME has user@host format */
-    stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
-    pj_create_random_string(p, 5);
-    p += 5;
-    *p++ = '@'; *p++ = 'p'; *p++ = 'j';
-    pj_create_random_string(p, 6);
-    p += 6;
-    *p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
-    stream->cname.slen = p - stream->cname.ptr;
-
+    stream->cname = info->cname;
+    if (stream->cname.slen == 0) {
+	/* Build random RTCP CNAME. CNAME has user@host format */
+    	stream->cname.ptr = p = (char*) pj_pool_alloc(pool, 20);
+    	pj_create_random_string(p, 5);
+    	p += 5;
+    	*p++ = '@'; *p++ = 'p'; *p++ = 'j';
+    	pj_create_random_string(p, 6);
+    	p += 6;
+    	*p++ = '.'; *p++ = 'o'; *p++ = 'r'; *p++ = 'g';
+    	stream->cname.slen = p - stream->cname.ptr;
+    }
 
     /* Create mutex to protect jitter buffer: */
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c	(revision 5747)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream_info.c	(revision 5748)
@@ -196,4 +196,5 @@
     int rem_af, local_af;
     pj_sockaddr local_addr;
+    unsigned i;
     pj_status_t status;
 
@@ -378,4 +379,22 @@
     }
 
+    /* Check if "ssrc" attribute is present in the SDP. */
+    for (i = 0; i < rem_m->attr_count; i++) {
+	if (pj_strcmp2(&rem_m->attr[i]->name, "ssrc") == 0) {
+	    pjmedia_sdp_ssrc_attr ssrc;
+
+	    status = pjmedia_sdp_attr_get_ssrc(
+	    		(const pjmedia_sdp_attr *)rem_m->attr[i], &ssrc);
+	    if (status == PJ_SUCCESS) {
+	        si->has_rem_ssrc = PJ_TRUE;
+	    	si->rem_ssrc = ssrc.ssrc;
+	    	if (ssrc.cname.slen > 0) {
+	    	    pj_strdup(pool, &si->rem_cname, &ssrc.cname);
+	    	    break;
+	    	}
+	    }
+	}
+    }
+
     /* Get codec info and param */
     status = get_video_codec_info_param(si, pool, NULL, local_m, rem_m);
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5747)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5748)
@@ -139,4 +139,6 @@
     pj_bool_t		 local_hold;/**< Flag for call-hold by local.	    */
     void		*hold_msg;  /**< Outgoing hold tx_data.		    */
+    pj_str_t		 cname;	    /**< RTCP CNAME.			    */
+    char		 cname_buf[16];/**< cname buffer.		    */
 
     unsigned		 med_cnt;   /**< Number of media in SDP.	    */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 5747)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 5748)
@@ -604,6 +604,7 @@
 	si->jb_max = pjsua_var.media_cfg.jb_max;
 
-	/* Set SSRC */
+	/* Set SSRC and CNAME */
 	si->ssrc = call_med->ssrc;
+	si->cname = call->cname;
 
 	/* Set RTP timestamp & sequence, normally these value are intialized
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 5747)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 5748)
@@ -138,4 +138,6 @@
     call->index = id;
     call->last_text.ptr = call->last_text_buf_;
+    call->cname.ptr = call->cname_buf;
+    call->cname.slen = sizeof(call->cname_buf);
     for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) {
 	pjsua_call_media *call_med = &call->media[i];
@@ -793,4 +795,7 @@
     call->acc_id = acc_id;
     call->call_hold_type = acc->cfg.call_hold_type;
+
+    /* Generate per-session RTCP CNAME, according to RFC 7022. */
+    pj_create_random_string(call->cname_buf, call->cname.slen);
 
     /* Apply call setting */
@@ -1223,4 +1228,7 @@
 
     call = &pjsua_var.calls[call_id];
+
+    /* Generate per-session RTCP CNAME, according to RFC 7022. */
+    pj_create_random_string(call->cname_buf, call->cname.slen);
 
     /* Mark call start time. */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5747)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5748)
@@ -2415,4 +2415,9 @@
 	if (status != PJ_SUCCESS)
 	    return status;
+
+    	/* Add ssrc and cname attribute */
+    	m->attr[m->attr_count++] = pjmedia_sdp_attr_create_ssrc(pool,
+    								call_med->ssrc,
+    								&call->cname);
 
 	sdp->media[sdp->media_count++] = m;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5747)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5748)
@@ -910,6 +910,7 @@
 	si->jb_max = pjsua_var.media_cfg.jb_max;
 
-	/* Set SSRC */
+	/* Set SSRC and CNAME */
 	si->ssrc = call_med->ssrc;
+	si->cname = call->cname;
 
 	/* Set RTP timestamp & sequence, normally these value are intialized
