summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/include/pjmedia/config.h10
-rw-r--r--pjmedia/include/pjmedia/errno.h7
-rw-r--r--pjmedia/include/pjmedia/sdp.h26
-rw-r--r--pjmedia/include/pjmedia/stream.h3
-rw-r--r--pjmedia/include/pjmedia/transport.h9
-rw-r--r--pjmedia/src/pjmedia/endpoint.c18
-rw-r--r--pjmedia/src/pjmedia/errno.c1
-rw-r--r--pjmedia/src/pjmedia/sdp.c243
-rw-r--r--pjmedia/src/pjmedia/session.c38
-rw-r--r--pjmedia/src/pjmedia/stream.c2
-rw-r--r--pjmedia/src/pjmedia/transport_udp.c84
-rw-r--r--pjsip-apps/src/samples/siprtp.c1
-rw-r--r--pjsip-apps/src/samples/siprtp_report.c8
-rw-r--r--pjsip-apps/src/samples/streamutil.c8
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c8
15 files changed, 320 insertions, 146 deletions
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 4533c0f4..f4bfeae4 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -155,6 +155,16 @@
/**
+ * Support for sending and decoding RTCP port in SDP (RFC 3605).
+ * Default is yes.
+ */
+#ifndef PJMEDIA_HAS_RTCP_IN_SDP
+# define PJMEDIA_HAS_RTCP_IN_SDP 1
+#endif
+
+
+
+/**
* @}
*/
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index a78ed131..c9c6bae2 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -140,9 +140,14 @@ PJ_BEGIN_DECL
#define PJMEDIA_SDP_EINPT (PJMEDIA_ERRNO_START+33) /* 220033 */
/**
* @hideinitializer
- * Invalid fmtp attribute.
+ * Invalid SDP "fmtp" attribute.
*/
#define PJMEDIA_SDP_EINFMTP (PJMEDIA_ERRNO_START+34) /* 220034 */
+/**
+ * @hideinitializer
+ * Invalid SDP "rtcp" attribute.
+ */
+#define PJMEDIA_SDP_EINRTCP (PJMEDIA_ERRNO_START+35) /* 220035 */
/************************************************************
diff --git a/pjmedia/include/pjmedia/sdp.h b/pjmedia/include/pjmedia/sdp.h
index 2bc43bb2..08a11203 100644
--- a/pjmedia/include/pjmedia/sdp.h
+++ b/pjmedia/include/pjmedia/sdp.h
@@ -293,6 +293,32 @@ PJ_DECL(pj_status_t) pjmedia_sdp_attr_get_fmtp(const pjmedia_sdp_attr *attr,
pjmedia_sdp_fmtp *fmtp);
+/**
+ * This structure describes SDP \a rtcp attribute.
+ */
+typedef struct pjmedia_sdp_rtcp_attr
+{
+ unsigned port; /**< RTCP port number. */
+ pj_str_t net_type; /**< Optional network type. */
+ pj_str_t addr_type; /**< Optional address type. */
+ pj_str_t addr; /**< Optional address. */
+} pjmedia_sdp_rtcp_attr;
+
+
+/**
+ * Parse a generic SDP attribute to get SDP rtcp attribute values.
+ *
+ * @param attr Generic attribute to be converted to rtcp, which
+ * name must be "rtcp".
+ * @param rtcp SDP rtcp attribute to be initialized.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_sdp_attr_get_rtcp(const pjmedia_sdp_attr *attr,
+ pjmedia_sdp_rtcp_attr *rtcp);
+
+
+
/* **************************************************************************
* SDP CONNECTION INFO
****************************************************************************
diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h
index c487d8c2..7a02b72a 100644
--- a/pjmedia/include/pjmedia/stream.h
+++ b/pjmedia/include/pjmedia/stream.h
@@ -91,6 +91,9 @@ struct pjmedia_stream_info
pjmedia_type type; /**< Media type (audio, video) */
pjmedia_dir dir; /**< Media direction. */
pj_sockaddr_in rem_addr; /**< Remote RTP address */
+ pj_sockaddr_in rem_rtcp; /**< Optional remote RTCP address. If
+ sin_family is zero, the RTP address
+ will be calculated from RTP. */
pjmedia_codec_info fmt; /**< Incoming codec format info. */
pjmedia_codec_param *param; /**< Optional codec param. */
unsigned tx_pt; /**< Outgoing codec paylaod type. */
diff --git a/pjmedia/include/pjmedia/transport.h b/pjmedia/include/pjmedia/transport.h
index f1d38a90..d50db4be 100644
--- a/pjmedia/include/pjmedia/transport.h
+++ b/pjmedia/include/pjmedia/transport.h
@@ -73,6 +73,7 @@ struct pjmedia_transport_op
pj_status_t (*attach)(pjmedia_transport *tp,
void *user_data,
const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
unsigned addr_len,
void (*rtp_cb)(void *user_data,
const void *pkt,
@@ -154,6 +155,10 @@ struct pjmedia_transport
* @param user_data Arbitrary user data to be set when the callbacks are
* called.
* @param rem_addr Remote RTP address to send RTP packet to.
+ * @param rem_rtcp Optional remote RTCP address. If the argument is NULL
+ * or if the address is zero, the RTCP address will be
+ * calculated from the RTP address (which is RTP port
+ * plus one).
* @param addr_len Length of the remote address.
* @param rtp_cb Callback to be called when RTP packet is received on
* the transport.
@@ -165,6 +170,7 @@ struct pjmedia_transport
PJ_INLINE(pj_status_t) pjmedia_transport_attach(pjmedia_transport *tp,
void *user_data,
const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
unsigned addr_len,
void (*rtp_cb)(void *user_data,
const void *pkt,
@@ -173,7 +179,8 @@ PJ_INLINE(pj_status_t) pjmedia_transport_attach(pjmedia_transport *tp,
const void*pkt,
pj_ssize_t))
{
- return tp->op->attach(tp, user_data, rem_addr, addr_len, rtp_cb, rtcp_cb);
+ return tp->op->attach(tp, user_data, rem_addr, rem_rtcp, addr_len,
+ rtp_cb, rtcp_cb);
}
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index becdb164..24730f65 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -327,10 +327,26 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
m->desc.port_count = 1;
pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
- /* Add format and rtpmap for each codec. */
+ /* Init media line and attribute list. */
m->desc.fmt_count = 0;
m->attr_count = 0;
+ /* Add "rtcp" attribute */
+#if 1
+ {
+ attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));
+ attr->name = pj_str("rtcp");
+ attr->value.ptr = pj_pool_alloc(pool, 80);
+ attr->value.slen =
+ pj_ansi_snprintf(attr->value.ptr, 80,
+ ":%u IN IP4 %s",
+ pj_ntohs(sock_info[0].rtp_addr_name.sin_port),
+ pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));
+ pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
+ }
+#endif
+
+ /* Add format and rtpmap for each codec */
for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
pjmedia_codec_info *codec_info;
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index 4016fecb..3d62e067 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -55,6 +55,7 @@ static const struct
PJ_BUILD_ERR( PJMEDIA_SDP_ENOFMT, "No SDP payload format in the media line" ),
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" ),
/* 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 6a677b6c..48f091d1 100644
--- a/pjmedia/src/pjmedia/sdp.c
+++ b/pjmedia/src/pjmedia/sdp.c
@@ -59,7 +59,7 @@ 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,
parse_context *ctx);
-
+static void on_scanner_error(pj_scanner *scanner);
/*
* Scanner character specification.
@@ -241,79 +241,70 @@ PJ_DEF(pj_status_t) pjmedia_sdp_attr_remove( unsigned *count,
PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtpmap( const pjmedia_sdp_attr *attr,
pjmedia_sdp_rtpmap *rtpmap)
{
- const char *p = attr->value.ptr;
- const char *end = attr->value.ptr + attr->value.slen;
+ pj_scanner scanner;
pj_str_t token;
+ pj_status_t status = -1;
+ PJ_USE_EXCEPTION;
PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtpmap")==0, PJ_EINVALIDOP);
+ pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen,
+ PJ_SCAN_AUTOSKIP_WS, &on_scanner_error);
+
/* rtpmap sample:
* a=rtpmap:98 L16/16000/2.
*/
- /* Eat the first ':' */
- if (*p != ':') return PJMEDIA_SDP_EINRTPMAP;
-
- /* Get ':' */
- ++p;
-
- /* Get payload type. */
- token.ptr = (char*)p;
- while (pj_isdigit(*p) && p!=end)
- ++p;
- token.slen = p - token.ptr;
- if (token.slen == 0)
- return PJMEDIA_SDP_EINRTPMAP;
+ /* Init */
+ rtpmap->pt.slen = rtpmap->param.slen = rtpmap->enc_name.slen = 0;
- rtpmap->pt = token;
+ /* Parse */
+ PJ_TRY {
+ /* Eat the first ':' */
+ if (pj_scan_get_char(&scanner) != ':') {
+ status = PJMEDIA_SDP_EINRTPMAP;
+ goto on_return;
+ }
- /* Expecting space after payload type. */
- if (*p != ' ') return PJMEDIA_SDP_EINRTPMAP;
- /* Get space. */
- ++p;
+ /* Get payload type. */
+ pj_scan_get(&scanner, &cs_token, &rtpmap->pt);
- /* Get encoding name. */
- token.ptr = (char*)p;
- while (*p != '/' && p != end)
- ++p;
- token.slen = p - token.ptr;
- if (token.slen == 0)
- return PJMEDIA_SDP_EINRTPMAP;
- rtpmap->enc_name = token;
- /* Expecting '/' after encoding name. */
- if (*p != '/') return PJMEDIA_SDP_EINRTPMAP;
+ /* Get encoding name. */
+ pj_scan_get(&scanner, &cs_token, &rtpmap->enc_name);
- /* Get '/' */
- ++p;
+ /* Expecting '/' after encoding name. */
+ if (pj_scan_get_char(&scanner) != '/') {
+ status = PJMEDIA_SDP_EINRTPMAP;
+ goto on_return;
+ }
- /* Get the clock rate. */
- token.ptr = (char*)p;
- while (p != end && pj_isdigit(*p))
- ++p;
- token.slen = p - token.ptr;
- if (token.slen == 0)
- return PJMEDIA_SDP_EINRTPMAP;
- rtpmap->clock_rate = pj_strtoul(&token);
+ /* Get the clock rate. */
+ pj_scan_get(&scanner, &cs_token, &token);
+ rtpmap->clock_rate = pj_strtoul(&token);
- /* Expecting either '/' or EOF */
- if (p != end && *p != '/')
- return PJMEDIA_SDP_EINRTPMAP;
+ /* Expecting either '/' or EOF */
+ if (*scanner.curptr == '/') {
+ pj_scan_get_char(&scanner);
+ rtpmap->param.ptr = scanner.curptr;
+ rtpmap->param.slen = scanner.end - scanner.curptr;
+ } else {
+ rtpmap->param.slen = 0;
+ }
- if (p != end) {
- ++p;
- token.ptr = (char*)p;
- token.slen = end-p;
- rtpmap->param = token;
- } else {
- rtpmap->param.ptr = NULL;
- rtpmap->param.slen = 0;
+ status = PJ_SUCCESS;
+ }
+ PJ_CATCH(SYNTAX_ERROR) {
+ status = PJMEDIA_SDP_EINRTPMAP;
}
+ PJ_END;
- return PJ_SUCCESS;
+on_return:
+ pj_scan_fini(&scanner);
+ return status;
}
PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr,
@@ -358,6 +349,70 @@ PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_fmtp( const pjmedia_sdp_attr *attr,
return PJ_SUCCESS;
}
+
+PJ_DEF(pj_status_t) pjmedia_sdp_attr_get_rtcp(const pjmedia_sdp_attr *attr,
+ pjmedia_sdp_rtcp_attr *rtcp)
+{
+ pj_scanner scanner;
+ pj_str_t token;
+ pj_status_t status = -1;
+ PJ_USE_EXCEPTION;
+
+ PJ_ASSERT_RETURN(pj_strcmp2(&attr->name, "rtcp")==0, PJ_EINVALIDOP);
+
+ /* fmtp BNF:
+ * a=rtcp:<port> [nettype addrtype address]
+ */
+
+ pj_scan_init(&scanner, (char*)attr->value.ptr, attr->value.slen,
+ PJ_SCAN_AUTOSKIP_WS, &on_scanner_error);
+
+ /* Init */
+ rtcp->net_type.slen = rtcp->addr_type.slen = rtcp->addr.slen = 0;
+
+ /* Parse */
+ PJ_TRY {
+
+ /* Get the first ":" */
+ if (pj_scan_get_char(&scanner) != ':')
+ {
+ status = PJMEDIA_SDP_EINRTCP;
+ goto on_return;
+ }
+
+ /* Get the port */
+ pj_scan_get(&scanner, &cs_token, &token);
+ rtcp->port = pj_strtoul(&token);
+
+ /* Have address? */
+ if (!pj_scan_is_eof(&scanner)) {
+
+ /* Get network type */
+ pj_scan_get(&scanner, &cs_token, &rtcp->net_type);
+
+ /* Get address type */
+ pj_scan_get(&scanner, &cs_token, &rtcp->addr_type);
+
+ /* Get the address */
+ pj_scan_get(&scanner, &cs_token, &rtcp->addr);
+
+ }
+
+ status = PJ_SUCCESS;
+
+ }
+ PJ_CATCH(SYNTAX_ERROR) {
+ status = PJMEDIA_SDP_EINRTCP;
+ }
+ PJ_END;
+
+on_return:
+ pj_scan_fini(&scanner);
+ return status;
+}
+
+
+
PJ_DEF(pj_status_t) pjmedia_sdp_attr_to_rtpmap(pj_pool_t *pool,
const pjmedia_sdp_attr *attr,
pjmedia_sdp_rtpmap **p_rtpmap)
@@ -376,8 +431,8 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
pjmedia_sdp_attr **p_attr)
{
pjmedia_sdp_attr *attr;
- char tempbuf[64], *p, *endbuf;
- int i;
+ char tempbuf[64];
+ int len;
/* Check arguments. */
PJ_ASSERT_RETURN(pool && rtpmap && p_attr, PJ_EINVAL);
@@ -386,12 +441,6 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
PJ_ASSERT_RETURN(rtpmap->enc_name.slen && rtpmap->clock_rate,
PJMEDIA_SDP_EINRTPMAP);
- /* Check size. */
- i = rtpmap->enc_name.slen + rtpmap->param.slen + 32;
- if (i >= sizeof(tempbuf)-1) {
- pj_assert(!"rtpmap attribute is too long");
- return PJMEDIA_SDP_ERTPMAPTOOLONG;
- }
attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));
PJ_ASSERT_RETURN(attr != NULL, PJ_ENOMEM);
@@ -399,37 +448,22 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
attr->name.ptr = "rtpmap";
attr->name.slen = 6;
- p = tempbuf;
- endbuf = tempbuf+sizeof(tempbuf);
-
- /* Add colon */
- *p++ = ':';
-
- /* Add payload type. */
- pj_memcpy(p, rtpmap->pt.ptr, rtpmap->pt.slen);
- p += rtpmap->pt.slen;
- *p++ = ' ';
-
- /* Add encoding name. */
- for (i=0; i<rtpmap->enc_name.slen; ++i)
- p[i] = rtpmap->enc_name.ptr[i];
- p += rtpmap->enc_name.slen;
- *p++ = '/';
-
- /* Add clock rate. */
- p += pj_utoa(rtpmap->clock_rate, p);
-
- /* Add parameter if necessary. */
- if (rtpmap->param.slen > 0) {
- *p++ = '/';
- for (i=0; i<rtpmap->param.slen; ++i)
- p[i] = rtpmap->param.ptr[i];
- p += rtpmap->param.slen;
- }
-
- *p = '\0';
+ /* Format: ":pt enc_name/clock_rate[/param]" */
+ len = pj_ansi_snprintf(tempbuf, sizeof(tempbuf),
+ ":%.*s %.*s/%u%s%.*s",
+ (int)rtpmap->pt.slen,
+ rtpmap->pt.ptr,
+ (int)rtpmap->enc_name.slen,
+ rtpmap->enc_name.ptr,
+ rtpmap->clock_rate,
+ (rtpmap->param.slen ? "/" : ""),
+ rtpmap->param.slen,
+ rtpmap->param.ptr);
+
+ if (len < 1 || len > sizeof(tempbuf))
+ return PJMEDIA_SDP_ERTPMAPTOOLONG;
- attr->value.slen = p-tempbuf;
+ attr->value.slen = len;
attr->value.ptr = pj_pool_alloc(pool, attr->value.slen);
pj_memcpy(attr->value.ptr, tempbuf, attr->value.slen);
@@ -440,27 +474,22 @@ PJ_DEF(pj_status_t) pjmedia_sdp_rtpmap_to_attr(pj_pool_t *pool,
static int print_connection_info( pjmedia_sdp_conn *c, char *buf, int len)
{
- char *p = buf;
+ int printed;
- if (len < 8+c->net_type.slen+c->addr_type.slen+c->addr.slen) {
+ printed = pj_ansi_snprintf(buf, len, "c=%.*s %.*s %.*s\r\n",
+ (int)c->net_type.slen,
+ c->net_type.ptr,
+ (int)c->addr_type.slen,
+ c->addr_type.ptr,
+ (int)c->addr.slen,
+ c->addr.ptr);
+ if (printed < 1 || printed > len)
return -1;
- }
- *p++ = 'c';
- *p++ = '=';
- pj_memcpy(p, c->net_type.ptr, c->net_type.slen);
- p += c->net_type.slen;
- *p++ = ' ';
- pj_memcpy(p, c->addr_type.ptr, c->addr_type.slen);
- p += c->addr_type.slen;
- *p++ = ' ';
- pj_memcpy(p, c->addr.ptr, c->addr.slen);
- p += c->addr.slen;
- *p++ = '\r';
- *p++ = '\n';
- return p-buf;
+ return printed;
}
+
PJ_DEF(pjmedia_sdp_conn*) pjmedia_sdp_conn_clone (pj_pool_t *pool,
const pjmedia_sdp_conn *rhs)
{
diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c
index 9073bef1..fa8650e0 100644
--- a/pjmedia/src/pjmedia/session.c
+++ b/pjmedia/src/pjmedia/session.c
@@ -78,7 +78,6 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
unsigned i, pt;
pj_status_t status;
-
/* Validate arguments: */
PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);
@@ -155,15 +154,42 @@ PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
/* Set remote address: */
-
- si->rem_addr.sin_family = PJ_AF_INET;
- si->rem_addr.sin_port = pj_htons(rem_m->desc.port);
- if (pj_inet_aton(&rem_conn->addr, &si->rem_addr.sin_addr) == 0) {
-
+ status = pj_sockaddr_in_init(&si->rem_addr, &rem_conn->addr,
+ rem_m->desc.port);
+ if (status != PJ_SUCCESS) {
/* Invalid IP address. */
return PJMEDIA_EINVALIDIP;
}
+ /* If "rtcp" attribute is present in the SDP, set the RTCP address
+ * from that attribute. Otherwise, calculate from RTP address.
+ */
+ attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
+ "rtcp", NULL);
+ if (attr) {
+ pjmedia_sdp_rtcp_attr rtcp;
+ status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);
+ if (status == PJ_SUCCESS) {
+ if (rtcp.addr.slen) {
+ status = pj_sockaddr_in_init(&si->rem_rtcp, &rtcp.addr,
+ (pj_uint16_t)rtcp.port);
+ } else {
+ pj_sockaddr_in_init(&si->rem_rtcp, NULL,
+ (pj_uint16_t)rtcp.port);
+ si->rem_rtcp.sin_addr.s_addr = si->rem_addr.sin_addr.s_addr;
+ }
+ }
+ }
+
+ if (si->rem_rtcp.sin_addr.s_addr == 0) {
+ int rtcp_port;
+
+ pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr_in));
+ rtcp_port = pj_ntohs(si->rem_addr.sin_port) + 1;
+ si->rem_rtcp.sin_port = pj_htons((pj_uint16_t)rtcp_port);
+ }
+
+
/* And codec must be numeric! */
if (!pj_isdigit(*local_m->desc.fmt[0].ptr) ||
!pj_isdigit(*rem_m->desc.fmt[0].ptr))
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 9c8d3fbb..c65d6ce2 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -1067,7 +1067,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
/* Only attach transport when stream is ready. */
- status = (*tp->op->attach)(tp, stream, &info->rem_addr,
+ status = (*tp->op->attach)(tp, stream, &info->rem_addr, &info->rem_rtcp,
sizeof(info->rem_addr), &on_rx_rtp,
&on_rx_rtcp);
if (status != PJ_SUCCESS)
diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c
index b6b2e4f2..99d6d0aa 100644
--- a/pjmedia/src/pjmedia/transport_udp.c
+++ b/pjmedia/src/pjmedia/transport_udp.c
@@ -71,6 +71,8 @@ struct transport_udp
pj_sock_t rtcp_sock; /**< RTCP socket */
pj_sockaddr_in rtcp_addr_name; /**< Published RTCP address. */
+ pj_sockaddr_in rtcp_src_addr; /**< Actual source RTCP address. */
+ int rtcp_addr_len; /**< Length of RTCP src address. */
pj_ioqueue_key_t *rtcp_key; /**< RTCP socket key in ioqueue */
pj_ioqueue_op_key_t rtcp_read_op; /**< Pending read operation */
pj_ioqueue_op_key_t rtcp_write_op; /**< Pending write operation */
@@ -89,6 +91,7 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
static pj_status_t transport_attach( pjmedia_transport *tp,
void *user_data,
const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
unsigned addr_len,
void (*rtp_cb)(void*,
const void*,
@@ -275,8 +278,10 @@ PJ_DEF(pj_status_t) pjmedia_transport_udp_attach( pjmedia_endpt *endpt,
/* Kick of pending RTCP read from the ioqueue */
size = sizeof(tp->rtcp_pkt);
- status = pj_ioqueue_recv(tp->rtcp_key, &tp->rtcp_read_op,
- tp->rtcp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC);
+ tp->rtcp_addr_len = sizeof(tp->rtcp_src_addr);
+ status = pj_ioqueue_recvfrom( tp->rtcp_key, &tp->rtcp_read_op,
+ tp->rtcp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC,
+ &tp->rtcp_src_addr, &tp->rtcp_addr_len);
if (status != PJ_EPENDING)
goto on_error;
@@ -384,18 +389,9 @@ static void on_rx_rtp( pj_ioqueue_key_t *key,
if (udp->rtp_src_cnt >= PJMEDIA_RTP_NAT_PROBATION_CNT) {
- pj_uint16_t port;
-
/* Set remote RTP address to source address */
udp->rem_rtp_addr = udp->rtp_src_addr;
- /* Also update remote RTCP address */
- pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr,
- sizeof(pj_sockaddr_in));
- port = (pj_uint16_t)
- (pj_ntohs(udp->rem_rtp_addr.sin_port)+1);
- udp->rem_rtcp_addr.sin_port = pj_htons(port);
-
/* Reset counter */
udp->rtp_src_cnt = 0;
@@ -403,6 +399,28 @@ static void on_rx_rtp( pj_ioqueue_key_t *key,
"Remote RTP address switched to %s:%d",
pj_inet_ntoa(udp->rtp_src_addr.sin_addr),
pj_ntohs(udp->rtp_src_addr.sin_port)));
+
+ /* Also update remote RTCP address if actual RTCP source
+ * address is not heard yet.
+ */
+ if (udp->rtcp_src_addr.sin_addr.s_addr == 0) {
+ pj_uint16_t port;
+
+ pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr,
+ sizeof(pj_sockaddr_in));
+ port = (pj_uint16_t)
+ (pj_ntohs(udp->rem_rtp_addr.sin_port)+1);
+ udp->rem_rtcp_addr.sin_port = pj_htons(port);
+
+ pj_memcpy(&udp->rtcp_src_addr, &udp->rem_rtcp_addr,
+ sizeof(pj_sockaddr_in));
+
+ PJ_LOG(4,(udp->base.name,
+ "Remote RTCP address switched to %s:%d",
+ pj_inet_ntoa(udp->rtcp_src_addr.sin_addr),
+ pj_ntohs(udp->rtcp_src_addr.sin_port)));
+
+ }
}
}
}
@@ -440,9 +458,30 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
if (udp->attached && cb)
(*cb)(user_data, udp->rtcp_pkt, bytes_read);
+ /* Check if RTCP source address is the same as the configured
+ * remote address, and switch the address when they are
+ * different.
+ */
+ if ((udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0 &&
+ ((udp->rem_rtcp_addr.sin_addr.s_addr !=
+ udp->rtcp_src_addr.sin_addr.s_addr) ||
+ (udp->rem_rtcp_addr.sin_port !=
+ udp->rtcp_src_addr.sin_port)))
+ {
+ pj_memcpy(&udp->rem_rtcp_addr, &udp->rtcp_src_addr,
+ sizeof(pj_sockaddr_in));
+ PJ_LOG(4,(udp->base.name,
+ "Remote RTCP address switched to %s:%d",
+ pj_inet_ntoa(udp->rtcp_src_addr.sin_addr),
+ pj_ntohs(udp->rtcp_src_addr.sin_port)));
+ }
+
bytes_read = sizeof(udp->rtcp_pkt);
- status = pj_ioqueue_recv(udp->rtcp_key, &udp->rtcp_read_op,
- udp->rtcp_pkt, &bytes_read, 0);
+ udp->rtcp_addr_len = sizeof(udp->rtcp_src_addr);
+ status = pj_ioqueue_recvfrom(udp->rtcp_key, &udp->rtcp_read_op,
+ udp->rtcp_pkt, &bytes_read, 0,
+ &udp->rtcp_src_addr,
+ &udp->rtcp_addr_len);
} while (status == PJ_SUCCESS);
}
@@ -452,6 +491,7 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
static pj_status_t transport_attach( pjmedia_transport *tp,
void *user_data,
const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
unsigned addr_len,
void (*rtp_cb)(void*,
const void*,
@@ -461,6 +501,7 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
pj_ssize_t))
{
struct transport_udp *udp = (struct transport_udp*) tp;
+ const pj_sockaddr_in *rtcp_addr;
/* Validate arguments */
PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
@@ -473,10 +514,19 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
/* Copy remote RTP address */
pj_memcpy(&udp->rem_rtp_addr, rem_addr, sizeof(pj_sockaddr_in));
- /* Guess RTCP address from RTP address */
- pj_memcpy(&udp->rem_rtcp_addr, rem_addr, sizeof(pj_sockaddr_in));
- udp->rem_rtcp_addr.sin_port = (pj_uint16_t) pj_htons((pj_uint16_t)(
- pj_ntohs(udp->rem_rtp_addr.sin_port)+1));
+ /* Copy remote RTP address, if one is specified. */
+ rtcp_addr = rem_rtcp;
+ if (rtcp_addr && rtcp_addr->sin_addr.s_addr != 0) {
+ pj_memcpy(&udp->rem_rtcp_addr, rem_rtcp, sizeof(pj_sockaddr_in));
+
+ } else {
+ int rtcp_port;
+
+ /* Otherwise guess the RTCP address from the RTP address */
+ pj_memcpy(&udp->rem_rtcp_addr, rem_addr, sizeof(pj_sockaddr_in));
+ rtcp_port = pj_ntohs(udp->rem_rtp_addr.sin_port) + 1;
+ udp->rem_rtcp_addr.sin_port = pj_htons((pj_uint16_t)rtcp_port);
+ }
/* Save the callbacks */
udp->rtp_cb = rtp_cb;
diff --git a/pjsip-apps/src/samples/siprtp.c b/pjsip-apps/src/samples/siprtp.c
index d8d48e11..8e761ba2 100644
--- a/pjsip-apps/src/samples/siprtp.c
+++ b/pjsip-apps/src/samples/siprtp.c
@@ -1284,6 +1284,7 @@ static void call_on_media_update( pjsip_inv_session *inv,
/* Attach media to transport */
status = pjmedia_transport_attach(audio->transport, audio,
&audio->si.rem_addr,
+ &audio->si.rem_rtcp,
sizeof(pj_sockaddr_in),
&on_rx_rtp,
&on_rx_rtcp);
diff --git a/pjsip-apps/src/samples/siprtp_report.c b/pjsip-apps/src/samples/siprtp_report.c
index 83c4f11d..eed5fc06 100644
--- a/pjsip-apps/src/samples/siprtp_report.c
+++ b/pjsip-apps/src/samples/siprtp_report.c
@@ -161,9 +161,9 @@ static void print_call(int call_index)
audio->rtcp.stat.rx.loss,
audio->rtcp.stat.rx.loss * 100.0 / (audio->rtcp.stat.rx.pkt + audio->rtcp.stat.rx.loss),
audio->rtcp.stat.rx.dup,
- audio->rtcp.stat.rx.dup * 100.0 / (audio->rtcp.stat.rx.pkt + audio->rtcp.stat.rx.dup),
+ audio->rtcp.stat.rx.dup * 100.0 / (audio->rtcp.stat.rx.pkt + audio->rtcp.stat.rx.loss),
audio->rtcp.stat.rx.reorder,
- audio->rtcp.stat.rx.reorder * 100.0 / (audio->rtcp.stat.rx.pkt + audio->rtcp.stat.rx.reorder),
+ audio->rtcp.stat.rx.reorder * 100.0 / (audio->rtcp.stat.rx.pkt + audio->rtcp.stat.rx.loss),
"",
audio->rtcp.stat.rx.loss_period.min / 1000.0,
audio->rtcp.stat.rx.loss_period.avg / 1000.0,
@@ -204,9 +204,9 @@ static void print_call(int call_index)
audio->rtcp.stat.tx.loss,
audio->rtcp.stat.tx.loss * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
audio->rtcp.stat.tx.dup,
- audio->rtcp.stat.tx.dup * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.dup),
+ audio->rtcp.stat.tx.dup * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
audio->rtcp.stat.tx.reorder,
- audio->rtcp.stat.tx.reorder * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.reorder),
+ audio->rtcp.stat.tx.reorder * 100.0 / (audio->rtcp.stat.tx.pkt + audio->rtcp.stat.tx.loss),
"",
audio->rtcp.stat.tx.loss_period.min / 1000.0,
audio->rtcp.stat.tx.loss_period.avg / 1000.0,
diff --git a/pjsip-apps/src/samples/streamutil.c b/pjsip-apps/src/samples/streamutil.c
index 20544276..5b46ff54 100644
--- a/pjsip-apps/src/samples/streamutil.c
+++ b/pjsip-apps/src/samples/streamutil.c
@@ -606,9 +606,9 @@ static void print_stream_stat(pjmedia_stream *stream)
stat.rx.loss,
stat.rx.loss * 100.0 / (stat.rx.pkt + stat.rx.loss),
stat.rx.dup,
- stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.dup),
+ stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.loss),
stat.rx.reorder,
- stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.reorder),
+ stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.loss),
"",
stat.rx.loss_period.min / 1000.0,
stat.rx.loss_period.avg / 1000.0,
@@ -649,9 +649,9 @@ static void print_stream_stat(pjmedia_stream *stream)
stat.tx.loss,
stat.tx.loss * 100.0 / (stat.tx.pkt + stat.tx.loss),
stat.tx.dup,
- stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.dup),
+ stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.loss),
stat.tx.reorder,
- stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.reorder),
+ stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.loss),
"",
stat.tx.loss_period.min / 1000.0,
stat.tx.loss_period.avg / 1000.0,
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 9e411044..a40dceb9 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -1304,9 +1304,9 @@ static void dump_media_session(const char *indent,
stat.rx.loss,
stat.rx.loss * 100.0 / (stat.rx.pkt + stat.rx.loss),
stat.rx.dup,
- stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.dup),
+ stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.loss),
stat.rx.reorder,
- stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.reorder),
+ stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.loss),
indent, indent,
stat.rx.loss_period.min / 1000.0,
stat.rx.loss_period.avg / 1000.0,
@@ -1363,9 +1363,9 @@ static void dump_media_session(const char *indent,
stat.tx.loss,
stat.tx.loss * 100.0 / (stat.tx.pkt + stat.tx.loss),
stat.tx.dup,
- stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.dup),
+ stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.loss),
stat.tx.reorder,
- stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.reorder),
+ stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.loss),
indent, indent,
stat.tx.loss_period.min / 1000.0,