Index: /pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 3836)
+++ /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 3837)
@@ -621,4 +621,16 @@
 
 /**
+ * This specifies if the SDP negotiator should rewrite answer payload
+ * type numbers to use the same payload type numbers as the remote offer
+ * for all matched codecs.
+ *
+ * Default is 1 (yes)
+ */
+#ifndef PJMEDIA_SDP_NEG_ANSWER_SYMMETRIC_PT
+#   define PJMEDIA_SDP_NEG_ANSWER_SYMMETRIC_PT		1
+#endif
+
+
+/**
  * Support for sending and decoding RTCP port in SDP (RFC 3605).
  * Default is equal to PJMEDIA_ADVERTISE_RTCP setting.
Index: /pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 3836)
+++ /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 3837)
@@ -111,4 +111,5 @@
     pjmedia_codec_param *param;	    /**< Optional codec param.		    */
     unsigned		tx_pt;	    /**< Outgoing codec paylaod type.	    */
+    unsigned		rx_pt;	    /**< Incoming codec paylaod type.	    */
     unsigned		tx_maxptime;/**< Outgoing codec max ptime.	    */
     int		        tx_event_pt;/**< Outgoing pt for telephone-events.  */
Index: /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 3836)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 3837)
@@ -1121,4 +1121,80 @@
 }
 
+
+/* Internal function to rewrite the format string in SDP attribute rtpmap
+ * and fmtp.
+ */
+PJ_INLINE(void) rewrite_pt(pj_pool_t *pool, pj_str_t *attr_val,
+			   const pj_str_t *old_pt, const pj_str_t *new_pt)
+{
+    int len_diff = new_pt->slen - old_pt->slen;
+
+    /* Note that attribute value should be null-terminated. */
+    if (len_diff > 0) {
+	pj_str_t new_val;
+	new_val.ptr = (char*)pj_pool_alloc(pool, attr_val->slen+len_diff+1);
+	new_val.slen = attr_val->slen + len_diff;
+	pj_memcpy(new_val.ptr + len_diff, attr_val->ptr, attr_val->slen + 1);
+	*attr_val = new_val;
+    } else if (len_diff < 0) {
+	pj_memmove(attr_val->ptr, attr_val->ptr - len_diff,
+		   attr_val->slen + len_diff + 1);
+    }
+    pj_memcpy(attr_val->ptr, new_pt->ptr, new_pt->slen);
+}
+
+
+/* Internal function to apply symmetric PT for the local answer. */
+static void apply_answer_symmetric_pt(pj_pool_t *pool,
+				      pjmedia_sdp_media *answer,
+				      unsigned pt_cnt,
+				      const pj_str_t pt_offer[],
+				      const pj_str_t pt_answer[])
+{
+    pjmedia_sdp_attr *a_tmp[PJMEDIA_MAX_SDP_ATTR];
+    unsigned i, a_tmp_cnt = 0;
+
+    /* Rewrite the payload types in the answer if different to
+     * the ones in the offer.
+     */
+    for (i = 0; i < pt_cnt; ++i) {
+	pjmedia_sdp_attr *a;
+
+	/* Skip if the PTs are the same already, e.g: static PT. */
+	if (pj_strcmp(&pt_answer[i], &pt_offer[i]) == 0)
+	    continue;
+
+	/* Rewrite payload type in the answer to match to the offer */
+	pj_strdup(pool, &answer->desc.fmt[i], &pt_offer[i]);
+
+	/* Also update payload type in rtpmap */
+	a = pjmedia_sdp_media_find_attr2(answer, "rtpmap", &pt_answer[i]);
+	if (a) {
+	    rewrite_pt(pool, &a->value, &pt_answer[i], &pt_offer[i]);
+	    /* Temporarily remove the attribute in case the new payload
+	     * type is being used by another format in the media.
+	     */
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	    a_tmp[a_tmp_cnt++] = a;
+	}
+
+	/* Also update payload type in fmtp */
+	a = pjmedia_sdp_media_find_attr2(answer, "fmtp", &pt_answer[i]);
+	if (a) {
+	    rewrite_pt(pool, &a->value, &pt_answer[i], &pt_offer[i]);
+	    /* Temporarily remove the attribute in case the new payload
+	     * type is being used by another format in the media.
+	     */
+	    pjmedia_sdp_media_remove_attr(answer, a);
+	    a_tmp[a_tmp_cnt++] = a;
+	}
+    }
+
+    /* Return back 'rtpmap' and 'fmtp' attributes */
+    for (i = 0; i < a_tmp_cnt; ++i)
+	pjmedia_sdp_media_add_attr(answer, a_tmp[i]);
+}
+
+
 /* Try to match offer with answer. */
 static pj_status_t match_offer(pj_pool_t *pool,
@@ -1138,4 +1214,5 @@
     unsigned pt_answer_count = 0;
     pj_str_t pt_answer[PJMEDIA_MAX_SDP_FMT];
+    pj_str_t pt_offer[PJMEDIA_MAX_SDP_FMT];
     pjmedia_sdp_media *answer;
     const pjmedia_sdp_media *master, *slave;
@@ -1202,4 +1279,5 @@
 		    if (p == pt && pj_isdigit(*slave->desc.fmt[j].ptr)) {
 			found_matching_codec = 1;
+			pt_offer[pt_answer_count] = slave->desc.fmt[j];
 			pt_answer[pt_answer_count++] = slave->desc.fmt[j];
 			break;
@@ -1301,4 +1379,8 @@
 			    }
 
+			    pt_offer[pt_answer_count] = 
+						prefer_remote_codec_order?
+						offer->desc.fmt[i]:
+						offer->desc.fmt[j];
 			    pt_answer[pt_answer_count++] = 
 						prefer_remote_codec_order? 
@@ -1326,4 +1408,7 @@
 		    /* Match */
 		    found_matching_other = 1;
+		    pt_offer[pt_answer_count] = prefer_remote_codec_order?
+						offer->desc.fmt[i]:
+						offer->desc.fmt[j];
 		    pt_answer[pt_answer_count++] = prefer_remote_codec_order? 
 						   preanswer->desc.fmt[j]:
@@ -1390,4 +1475,9 @@
     }
     answer->desc.fmt_count = pt_answer_count;
+
+#if PJMEDIA_SDP_NEG_ANSWER_SYMMETRIC_PT
+    apply_answer_symmetric_pt(pool, answer, pt_answer_count,
+			      pt_offer, pt_answer);
+#endif
 
     /* Update media direction. */
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 3836)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 3837)
@@ -2221,5 +2221,5 @@
 
     status = create_channel( pool, stream, PJMEDIA_DIR_DECODING, 
-			     info->fmt.pt, info, &stream->dec);
+			     info->rx_pt, info, &stream->dec);
     if (status != PJ_SUCCESS)
 	goto err_cleanup;
@@ -2835,4 +2835,7 @@
 	return PJMEDIA_EINVALIDPT;
 
+    /* Get payload type for receiving direction */
+    si->rx_pt = pt;
+
     /* Get codec info.
      * For static payload types, get the info from codec manager.
@@ -2894,4 +2897,7 @@
 
     } else {
+	pjmedia_codec_id codec_id;
+	pj_str_t codec_id_st;
+	const pjmedia_codec_info *p_info;
 
 	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 
@@ -2908,5 +2914,5 @@
 	si->fmt.type = si->type;
 	si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
-	pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
+	si->fmt.encoding_name = rtpmap->enc_name;
 	si->fmt.clock_rate = rtpmap->clock_rate;
 
@@ -2919,4 +2925,21 @@
 	    si->fmt.channel_cnt = 1;
 	}
+
+	/* Normalize the codec info from codec manager. Note that the
+	 * payload type will be resetted to its default (it might have
+	 * been rewritten by the SDP negotiator to match to the remote
+	 * offer), this is intentional as currently some components may
+	 * prefer (or even require) the default PT in codec info.
+	 */
+	pjmedia_codec_info_to_id(&si->fmt, codec_id, sizeof(codec_id));
+
+	i = 1;
+	codec_id_st = pj_str(codec_id);
+	status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,
+						     &i, &p_info, NULL);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));
 
 	/* Determine payload type for outgoing channel, by finding
@@ -2966,5 +2989,5 @@
 
     /* Get local fmtp for our decoder. */
-    pjmedia_stream_info_parse_fmtp(pool, local_m, si->fmt.pt,
+    pjmedia_stream_info_parse_fmtp(pool, local_m, si->rx_pt,
 				   &si->param->setting.dec_fmtp);
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 3836)
+++ /pjproject/trunk/pjmedia/src/pjmedia/vid_stream.c	(revision 3837)
@@ -1783,20 +1783,25 @@
     pt = pj_strtoul(&local_m->desc.fmt[0]);
 
-    /* Get codec info. */
-    status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    si->codec_info = *p_info;
-
     /* Get payload type for receiving direction */
     si->rx_pt = pt;
 
-    /* Get payload type for transmitting direction */
+    /* Get codec info and payload type for transmitting direction. */
     if (pt < 96) {
-	/* For static payload type, pt's are symetric */
+	/* For static payload types, get the codec info from codec manager. */
+	status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	si->codec_info = *p_info;
+
+	/* Get payload type for transmitting direction.
+	 * For static payload type, pt's are symetric.
+	 */
 	si->tx_pt = pt;
-
     } else {
+	const pjmedia_sdp_attr *attr;
+	pjmedia_sdp_rtpmap *rtpmap;
+	pjmedia_codec_id codec_id;
+	pj_str_t codec_id_st;
 	unsigned i;
 
@@ -1819,4 +1824,26 @@
 	if (si->tx_pt == 0xFFFF)
 	    return PJMEDIA_EMISSINGRTPMAP;
+
+	/* For dynamic payload types, get codec name from the rtpmap */
+	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 
+					   &local_m->desc.fmt[0]);
+	if (attr == NULL)
+	    return PJMEDIA_EMISSINGRTPMAP;
+
+	status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Then get the codec info from the codec manager */
+	pj_ansi_snprintf(codec_id, sizeof(codec_id), "%.*s/", 
+			 rtpmap->enc_name.slen, rtpmap->enc_name.ptr);
+	codec_id_st = pj_str(codec_id);
+	i = 1;
+	status = pjmedia_vid_codec_mgr_find_codecs_by_id(mgr, &codec_id_st,
+							 &i, &p_info, NULL);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	si->codec_info = *p_info;
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c	(revision 3836)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c	(revision 3837)
@@ -308,5 +308,5 @@
 			     info.fmt.clock_rate / 1000);
 	    pj_ansi_snprintf(rx_info, sizeof(rx_info), "pt=%d,",
-			     info.fmt.pt);
+			     info.rx_pt);
 	    pj_ansi_snprintf(tx_info, sizeof(tx_info), "pt=%d, ptime=%d,",
 			     info.tx_pt,
