Index: /pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 3944)
+++ /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 3945)
@@ -172,4 +172,9 @@
  */
 #define PJMEDIA_SDP_EINPROTO	    (PJMEDIA_ERRNO_START+36)    /* 220036 */
+/**
+ * @hideinitializer
+ * Invalid SDP bandwidth info (b=) line.
+ */
+#define PJMEDIA_SDP_EINBANDW	    (PJMEDIA_ERRNO_START+37)    /* 220037 */
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/sdp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 3944)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 3945)
@@ -615,6 +615,9 @@
     } origin;
 
-    pj_str_t	     name;	    /**< Subject line (s=)		*/
-    pjmedia_sdp_conn *conn;	    /**< Connection line (c=)		*/
+    pj_str_t	       name;	    /**< Subject line (s=)		*/
+    pjmedia_sdp_conn  *conn;	    /**< Connection line (c=)		*/
+    unsigned	       bandw_count; /**< Number of bandwidth info (b=)	*/
+    pjmedia_sdp_bandw *bandw[PJMEDIA_MAX_SDP_BANDW];
+				    /**< Bandwidth info array (b=)	*/
     
     /** Session time (t= line)	*/
Index: /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 3944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 3945)
@@ -373,4 +373,5 @@
     pjmedia_sdp_attr *attr;
     unsigned i;
+    unsigned max_bitrate = 0;
     pj_status_t status;
 
@@ -494,4 +495,8 @@
 	    m->attr[m->attr_count++] = attr;
 	}
+
+	/* Find maximum bitrate in this media */
+	if (max_bitrate < codec_param.info.max_bps)
+	    max_bitrate = codec_param.info.max_bps;
     }
 
@@ -520,4 +525,17 @@
 #endif
 
+    /* Put bandwidth info in media level using bandwidth modifier "TIAS"
+     * (RFC3890).
+     */
+    if (max_bitrate) {
+	const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
+	pjmedia_sdp_bandw *b;
+	    
+	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
+	b->modifier = STR_BANDW_MODIFIER;
+	b->value = max_bitrate;
+	m->bandw[m->bandw_count++] = b;
+    }
+
     *p_m = m;
     return PJ_SUCCESS;
@@ -542,4 +560,5 @@
     pjmedia_sdp_attr *attr;
     unsigned cnt, i;
+    unsigned max_bitrate = 0;
     pj_status_t status;
 
@@ -569,4 +588,5 @@
 	pjmedia_vid_codec_param codec_param;
 	pj_str_t *fmt;
+	pjmedia_video_format_detail *vfd;
 
 	pj_bzero(&rtpmap, sizeof(rtpmap));
@@ -661,4 +681,23 @@
 	    m->attr[m->attr_count++] = attr;
 	}
+    
+	/* Find maximum bitrate in this media */
+	vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
+						     PJ_TRUE);
+	if (vfd && max_bitrate < vfd->max_bps)
+	    max_bitrate = vfd->max_bps;
+    }
+
+    /* Put bandwidth info in media level using bandwidth modifier "TIAS"
+     * (RFC3890).
+     */
+    if (max_bitrate) {
+	const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
+	pjmedia_sdp_bandw *b;
+	    
+	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
+	b->modifier = STR_BANDW_MODIFIER;
+	b->value = max_bitrate;
+	m->bandw[m->bandw_count++] = b;
     }
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/errno.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 3944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 3945)
@@ -67,4 +67,5 @@
     PJ_BUILD_ERR( PJMEDIA_SDP_EINRTCP,	    "Invalid SDP rtcp attribyte" ),
     PJ_BUILD_ERR( PJMEDIA_SDP_EINPROTO,	    "Invalid SDP media transport protocol" ),
+    PJ_BUILD_ERR( PJMEDIA_SDP_EINBANDW,	    "Invalid SDP bandwidth info line" ),
 
     /* SDP negotiator errors. */
Index: /pjproject/trunk/pjmedia/src/pjmedia/sdp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 3944)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sdp.c	(revision 3945)
@@ -60,4 +60,6 @@
 static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn,
 				  parse_context *ctx);
+static void parse_bandwidth_info(pj_scanner *scanner, pjmedia_sdp_bandw *bandw,
+				  parse_context *ctx);
 static pjmedia_sdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner,
 				    parse_context *ctx);
@@ -811,4 +813,12 @@
     }
 
+    /* print optional bandwidth info. */
+    for (i=0; i<ses->bandw_count; ++i) {
+	printed = print_bandw(ses->bandw[i], p, end-p);
+	if (printed < 1) {
+	    return -1;
+	}
+	p += printed;
+    }
 
     /* Time */
@@ -987,4 +997,26 @@
     pj_scan_get_until_chr(scanner, "/ \t\r\n", &conn->addr);
     PJ_TODO(PARSE_SDP_CONN_ADDRESS_SUBFIELDS);
+
+    /* We've got what we're looking for, skip anything until newline */
+    pj_scan_skip_line(scanner);
+}
+
+static void parse_bandwidth_info(pj_scanner *scanner, pjmedia_sdp_bandw *bandw,
+				  parse_context *ctx)
+{
+    pj_str_t str;
+
+    ctx->last_error = PJMEDIA_SDP_EINBANDW;
+
+    /* b= */
+    pj_scan_advance_n(scanner, 2, SKIP_WS);
+
+    /* modifier */
+    pj_scan_get_until_ch(scanner, ':', &bandw->modifier);
+    pj_scan_get_char(scanner);
+
+    /* value */
+    pj_scan_get_until_chr(scanner, " \t\r\n", &str);
+    bandw->value = pj_strtoul(&str);
 
     /* We've got what we're looking for, skip anything until newline */
@@ -1181,4 +1213,5 @@
     pjmedia_sdp_attr *attr;
     pjmedia_sdp_conn *conn;
+    pjmedia_sdp_bandw *bandw;
     pj_str_t dummy;
     int cur_name = 254;
@@ -1254,4 +1287,13 @@
 		    }
 		    break;
+		case 'b':
+		    bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw);
+		    parse_bandwidth_info(&scanner, bandw, &ctx);
+		    if (media) {
+			media->bandw[media->bandw_count++] = bandw;
+		    } else {
+			session->bandw[session->bandw_count++] = bandw;
+		    }
+		    break;
 		default:
 		    if (cur_name >= 'a' && cur_name <= 'z')
@@ -1333,4 +1375,10 @@
     }
 
+    /* Duplicate bandwidth info */
+    sess->bandw_count = rhs->bandw_count;
+    for (i=0; i<rhs->bandw_count; ++i) {
+	sess->bandw[i] = pjmedia_sdp_bandw_clone(pool, rhs->bandw[i]);
+    }
+
     /* Clone time line. */
     sess->time.start = rhs->time.start;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3944)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3945)
@@ -1939,4 +1939,5 @@
     pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
     unsigned mi;
+    unsigned tot_bandw_tias = 0;
     pj_status_t status;
 
@@ -2012,4 +2013,5 @@
 	pjmedia_sdp_media *m = NULL;
 	pjmedia_transport_info tpinfo;
+	unsigned i;
 
 	if (rem_sdp && mi >= rem_sdp->media_count) {
@@ -2109,4 +2111,15 @@
 	    sdp->conn = pjmedia_sdp_conn_clone(pool, m->conn);
 	}
+
+	
+	/* Find media bandwidth info */
+	for (i = 0; i < m->bandw_count; ++i) {
+	    const pj_str_t STR_BANDW_MODIFIER_TIAS = { "TIAS", 4 };
+	    if (!pj_stricmp(&m->bandw[i]->modifier, &STR_BANDW_MODIFIER_TIAS))
+	    {
+		tot_bandw_tias += m->bandw[i]->value;
+		break;
+	    }
+	}
     }
 
@@ -2133,4 +2146,24 @@
 	pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a);
 
+    }
+
+
+    /* Add bandwidth info in session level using bandwidth modifier "AS". */
+    if (tot_bandw_tias) {
+	unsigned bandw;
+	const pj_str_t STR_BANDW_MODIFIER_AS = { "AS", 2 };
+	pjmedia_sdp_bandw *b;
+
+	/* AS bandwidth = RTP bitrate + RTCP bitrate.
+	 * RTP bitrate  = payload bitrate (total TIAS) + overheads (~16kbps).
+	 * RTCP bitrate = est. 5% of RTP bitrate.
+	 * Note that AS bandwidth is in kbps.
+	 */
+	bandw = tot_bandw_tias + 16000;
+	bandw += bandw * 5 / 100;
+	b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
+	b->modifier = STR_BANDW_MODIFIER_AS;
+	b->value = bandw / 1000;
+	sdp->bandw[sdp->bandw_count++] = b;
     }
 
