summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/include/pjmedia/errno.h5
-rw-r--r--pjmedia/include/pjmedia/sdp.h7
-rw-r--r--pjmedia/src/pjmedia/endpoint.c39
-rw-r--r--pjmedia/src/pjmedia/errno.c1
-rw-r--r--pjmedia/src/pjmedia/sdp.c48
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c33
6 files changed, 131 insertions, 2 deletions
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index 3c27e35f..063e5437 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -171,6 +171,11 @@ PJ_BEGIN_DECL
* Invalid SDP media transport protocol.
*/
#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 */
/************************************************************
diff --git a/pjmedia/include/pjmedia/sdp.h b/pjmedia/include/pjmedia/sdp.h
index cd89b847..c3f67823 100644
--- a/pjmedia/include/pjmedia/sdp.h
+++ b/pjmedia/include/pjmedia/sdp.h
@@ -614,8 +614,11 @@ struct pjmedia_sdp_session
pj_str_t addr; /**< The address. */
} 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) */
struct
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index 535e0c5c..b9ebe69a 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -372,6 +372,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
pjmedia_sdp_media *m;
pjmedia_sdp_attr *attr;
unsigned i;
+ unsigned max_bitrate = 0;
pj_status_t status;
PJ_UNUSED_ARG(options);
@@ -493,6 +494,10 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
attr->value = pj_strdup3(pool, buf);
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;
}
#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
@@ -519,6 +524,19 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
}
#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;
}
@@ -541,6 +559,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
pjmedia_sdp_attr *attr;
unsigned cnt, i;
+ unsigned max_bitrate = 0;
pj_status_t status;
PJ_UNUSED_ARG(options);
@@ -568,6 +587,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
pjmedia_sdp_rtpmap rtpmap;
pjmedia_vid_codec_param codec_param;
pj_str_t *fmt;
+ pjmedia_video_format_detail *vfd;
pj_bzero(&rtpmap, sizeof(rtpmap));
@@ -660,6 +680,25 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
attr->value = pj_strdup3(pool, buf);
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;
}
*p_m = m;
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index 788f7431..7a8538eb 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -66,6 +66,7 @@ static const struct
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_EINPROTO, "Invalid SDP media transport protocol" ),
+ PJ_BUILD_ERR( PJMEDIA_SDP_EINBANDW, "Invalid SDP bandwidth info line" ),
/* SDP negotiator errors. */
PJ_BUILD_ERR( PJMEDIA_SDPNEG_EINSTATE, "Invalid SDP negotiator state for operation" ),
diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c
index 417a3dfe..629500c7 100644
--- a/pjmedia/src/pjmedia/sdp.c
+++ b/pjmedia/src/pjmedia/sdp.c
@@ -59,6 +59,8 @@ static void parse_generic_line(pj_scanner *scanner, pj_str_t *str,
parse_context *ctx);
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);
static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med,
@@ -810,6 +812,14 @@ static int print_session(const pjmedia_sdp_session *ses,
p += printed;
}
+ /* 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 */
if ((end-p) < 24) {
@@ -991,6 +1001,28 @@ static void parse_connection_info(pj_scanner *scanner, pjmedia_sdp_conn *conn,
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 */
+ pj_scan_skip_line(scanner);
+}
+
static void parse_media(pj_scanner *scanner, pjmedia_sdp_media *med,
parse_context *ctx)
{
@@ -1180,6 +1212,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool,
pjmedia_sdp_media *media = NULL;
pjmedia_sdp_attr *attr;
pjmedia_sdp_conn *conn;
+ pjmedia_sdp_bandw *bandw;
pj_str_t dummy;
int cur_name = 254;
parse_context ctx;
@@ -1253,6 +1286,15 @@ PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool,
pj_scan_get_char(&scanner);
}
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')
parse_generic_line(&scanner, &dummy, &ctx);
@@ -1332,6 +1374,12 @@ PJ_DEF(pjmedia_sdp_session*) pjmedia_sdp_session_clone( pj_pool_t *pool,
PJ_ASSERT_RETURN(sess->conn != NULL, NULL);
}
+ /* 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;
sess->time.stop = rhs->time.stop;
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 66cecf58..917dadcb 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -1938,6 +1938,7 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
pjsua_call *call = &pjsua_var.calls[call_id];
pjmedia_sdp_neg_state sdp_neg_state = PJMEDIA_SDP_NEG_STATE_NULL;
unsigned mi;
+ unsigned tot_bandw_tias = 0;
pj_status_t status;
if (pjsua_get_state() != PJSUA_STATE_RUNNING)
@@ -2011,6 +2012,7 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
pjsua_call_media *call_med = &call->media[mi];
pjmedia_sdp_media *m = NULL;
pjmedia_transport_info tpinfo;
+ unsigned i;
if (rem_sdp && mi >= rem_sdp->media_count) {
/* Remote might have removed some media lines. */
@@ -2108,6 +2110,17 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
if (sdp->conn == NULL) {
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;
+ }
+ }
}
/* Add NAT info in the SDP */
@@ -2135,6 +2148,26 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
}
+ /* 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;
+ }
+
+
#if DISABLED_FOR_TICKET_1185 && defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/* Check if SRTP is in optional mode and configured to use duplicated
* media, i.e: secured and unsecured version, in the SDP offer.