diff options
-rw-r--r-- | pjmedia/include/pjmedia/config.h | 10 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/errno.h | 7 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/sdp.h | 26 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/stream.h | 3 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/transport.h | 9 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/endpoint.c | 18 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/errno.c | 1 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/sdp.c | 243 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/session.c | 38 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/stream.c | 2 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/transport_udp.c | 84 | ||||
-rw-r--r-- | pjsip-apps/src/samples/siprtp.c | 1 | ||||
-rw-r--r-- | pjsip-apps/src/samples/siprtp_report.c | 8 | ||||
-rw-r--r-- | pjsip-apps/src/samples/streamutil.c | 8 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 8 |
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, |