summaryrefslogtreecommitdiff
path: root/pjmedia/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-06-29 14:45:17 +0000
committerBenny Prijono <bennylp@teluu.com>2006-06-29 14:45:17 +0000
commit44b3f0a399d641273df8a4b240514e710a905c31 (patch)
tree048ab55ba9d1856c6d6df1252aa4ad3a86b37862 /pjmedia/src
parentf5ac454bfdeea60297c45f6bc46349db25ab2e29 (diff)
Improvements in PJMEDIA to support RFC 3605 (RTCP attribute in SDP) and other changes to improve RTCP communication behind NAT. Also fixed bug related to RTCP reporting changes in revision 565
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@568 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src')
-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
6 files changed, 254 insertions, 132 deletions
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;