diff options
Diffstat (limited to 'pjmedia/src/pjmedia/stream.c')
-rw-r--r-- | pjmedia/src/pjmedia/stream.c | 385 |
1 files changed, 176 insertions, 209 deletions
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index b5354cd1..983f0445 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -155,6 +155,9 @@ struct pjmedia_stream pj_uint32_t rtcp_interval; /**< Interval, in timestamp. */ pj_bool_t initial_rr; /**< Initial RTCP RR sent */ pj_bool_t rtcp_sdes_bye_disabled;/**< Send RTCP SDES/BYE?*/ + void *out_rtcp_pkt; /**< Outgoing RTCP packet. */ + unsigned out_rtcp_pkt_size; + /**< Outgoing RTCP packet size. */ /* RFC 2833 DTMF transmission queue: */ int tx_event_pt; /**< Outgoing pt for dtmf. */ @@ -245,6 +248,12 @@ static void stream_perror(const char *sender, const char *title, } +static pj_status_t send_rtcp(pjmedia_stream *stream, + pj_bool_t with_sdes, + pj_bool_t with_bye, + pj_bool_t with_xr); + + #if TRACE_JB PJ_INLINE(int) trace_jb_print_timestamp(char **buf, pj_ssize_t len) @@ -425,8 +434,7 @@ static void send_keep_alive_packet(pjmedia_stream *stream) pkt_len); /* Send RTCP */ - pjmedia_rtcp_build_rtcp(&stream->rtcp, &pkt, &pkt_len); - pjmedia_transport_send_rtcp(stream->transport, pkt, pkt_len); + send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE); #elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER @@ -913,146 +921,159 @@ static void create_dtmf_payload(pjmedia_stream *stream, } -/** - * check_tx_rtcp() - * - * This function is can be called by either put_frame() or get_frame(), - * to transmit periodic RTCP SR/RR report. - */ -static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp) +static pj_status_t send_rtcp(pjmedia_stream *stream, + pj_bool_t with_sdes, + pj_bool_t with_bye, + pj_bool_t with_xr) { - /* Note that timestamp may represent local or remote timestamp, - * depending on whether this function is called from put_frame() - * or get_frame(). - */ - + void *sr_rr_pkt; + pj_uint8_t *pkt; + int len, max_len; + pj_status_t status; - if (stream->rtcp_last_tx == 0) { - - stream->rtcp_last_tx = timestamp; + /* Build RTCP RR/SR packet */ + pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len); - } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) { - - void *rtcp_pkt; - int len; +#if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0) + with_xr = PJ_FALSE; +#endif - pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len); + if (with_sdes || with_bye || with_xr) { + pkt = (pj_uint8_t*) stream->out_rtcp_pkt; + pj_memcpy(pkt, sr_rr_pkt, len); + max_len = stream->out_rtcp_pkt_size; + } else { + pkt = sr_rr_pkt; + max_len = len; + } - pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); + /* Build RTCP SDES packet */ + if (with_sdes) { + pjmedia_rtcp_sdes sdes; + pj_size_t sdes_len; - stream->rtcp_last_tx = timestamp; + pj_bzero(&sdes, sizeof(sdes)); + sdes.cname = stream->cname; + sdes_len = max_len - len; + status = pjmedia_rtcp_build_rtcp_sdes(&stream->rtcp, pkt+len, + &sdes_len, &sdes); + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error generating RTCP SDES")); + } else { + len += sdes_len; + } } + /* Build RTCP XR packet */ #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) - if (stream->rtcp.xr_enabled) { - - if (stream->rtcp_xr_last_tx == 0) { - - stream->rtcp_xr_last_tx = timestamp; - - } else if (timestamp - stream->rtcp_xr_last_tx >= - stream->rtcp_xr_interval) - { - int i; - pjmedia_jb_state jb_state; - void *rtcp_pkt; - int len; + if (with_xr) { + int i; + pjmedia_jb_state jb_state; + void *xr_pkt; + int xr_len; - /* Update RTCP XR with current JB states */ - pjmedia_jbuf_get_state(stream->jb, &jb_state); + /* Update RTCP XR with current JB states */ + pjmedia_jbuf_get_state(stream->jb, &jb_state); - i = jb_state.avg_delay; - pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, - PJMEDIA_RTCP_XR_INFO_JB_NOM, - i); + i = jb_state.avg_delay; + status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, + PJMEDIA_RTCP_XR_INFO_JB_NOM, i); + pj_assert(status == PJ_SUCCESS); - i = jb_state.max_delay; - pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, - PJMEDIA_RTCP_XR_INFO_JB_MAX, - i); + i = jb_state.max_delay; + status = pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, + PJMEDIA_RTCP_XR_INFO_JB_MAX, i); + pj_assert(status == PJ_SUCCESS); - /* Build RTCP XR packet */ - pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, - &rtcp_pkt, &len); + pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, + &xr_pkt, &xr_len); - /* Send the RTCP XR to remote address */ - pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); + if (xr_len + len <= max_len) { + pj_memcpy(pkt+len, xr_pkt, xr_len); + len += xr_len; /* Send the RTCP XR to third-party destination if specified */ if (stream->rtcp_xr_dest_len) { pjmedia_transport_send_rtcp2(stream->transport, &stream->rtcp_xr_dest, stream->rtcp_xr_dest_len, - rtcp_pkt, len); + xr_pkt, xr_len); } - /* Update last tx RTCP XR */ - stream->rtcp_xr_last_tx = timestamp; + } else { + PJ_PERROR(4,(stream->port.info.name.ptr, PJ_ETOOBIG, + "Error generating RTCP-XR")); } } #endif -} -/* Build RTCP SDES packet */ -static unsigned create_rtcp_sdes(pjmedia_stream *stream, pj_uint8_t *pkt, - unsigned max_len) -{ - pjmedia_rtcp_common hdr; - pj_uint8_t *p = pkt; - - /* SDES header */ - hdr.version = 2; - hdr.p = 0; - hdr.count = 1; - hdr.pt = 202; - hdr.length = 2 + (4+stream->cname.slen+3)/4 - 1; - if (max_len < (hdr.length << 2)) { - pj_assert(!"Not enough buffer for SDES packet"); - return 0; - } - hdr.length = pj_htons((pj_uint16_t)hdr.length); - hdr.ssrc = stream->enc->rtp.out_hdr.ssrc; - pj_memcpy(p, &hdr, sizeof(hdr)); - p += sizeof(hdr); - - /* CNAME item */ - *p++ = 1; - *p++ = (pj_uint8_t)stream->cname.slen; - pj_memcpy(p, stream->cname.ptr, stream->cname.slen); - p += stream->cname.slen; - - /* END */ - *p++ = '\0'; - *p++ = '\0'; - - /* Pad to 32bit */ - while ((p-pkt) % 4) - *p++ = '\0'; - - return (p - pkt); + /* Build RTCP BYE packet */ + if (with_bye) { + pj_size_t bye_len; + + bye_len = max_len - len; + status = pjmedia_rtcp_build_rtcp_bye(&stream->rtcp, pkt+len, + &bye_len, NULL); + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error generating RTCP BYE")); + } else { + len += bye_len; + } + } + + /* Send! */ + status = pjmedia_transport_send_rtcp(stream->transport, pkt, len); + + return status; } -/* Build RTCP BYE packet */ -static unsigned create_rtcp_bye(pjmedia_stream *stream, pj_uint8_t *pkt, - unsigned max_len) +/** + * check_tx_rtcp() + * + * This function is can be called by either put_frame() or get_frame(), + * to transmit periodic RTCP SR/RR report. + */ +static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp) { - pjmedia_rtcp_common hdr; - - /* BYE header */ - hdr.version = 2; - hdr.p = 0; - hdr.count = 1; - hdr.pt = 203; - hdr.length = 1; - if (max_len < (hdr.length << 2)) { - pj_assert(!"Not enough buffer for SDES packet"); - return 0; - } - hdr.length = pj_htons((pj_uint16_t)hdr.length); - hdr.ssrc = stream->enc->rtp.out_hdr.ssrc; - pj_memcpy(pkt, &hdr, sizeof(hdr)); - - return sizeof(hdr); + /* Note that timestamp may represent local or remote timestamp, + * depending on whether this function is called from put_frame() + * or get_frame(). + */ + + if (stream->rtcp_last_tx == 0) { + + stream->rtcp_last_tx = timestamp; + + } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) { + pj_bool_t with_xr = PJ_FALSE; + pj_status_t status; + +#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) + if (stream->rtcp.xr_enabled) { + if (stream->rtcp_xr_last_tx == 0) { + stream->rtcp_xr_last_tx = timestamp; + } else if (timestamp - stream->rtcp_xr_last_tx >= + stream->rtcp_xr_interval) + { + with_xr = PJ_TRUE; + + /* Update last tx RTCP XR */ + stream->rtcp_xr_last_tx = timestamp; + } + } +#endif + + status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, PJ_FALSE, + with_xr); + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error sending RTCP")); + } + + stream->rtcp_last_tx = timestamp; + } } @@ -1348,8 +1369,13 @@ static pj_status_t put_frame_imp( pjmedia_port *port, stream->is_streaming = PJ_TRUE; /* Send the RTP packet to the transport. */ - pjmedia_transport_send_rtp(stream->transport, channel->out_pkt, - frame_out.size + sizeof(pjmedia_rtp_hdr)); + status = pjmedia_transport_send_rtp(stream->transport, channel->out_pkt, + frame_out.size + + sizeof(pjmedia_rtp_hdr)); + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error sending RTP")); + } /* Update stat */ pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size); @@ -1819,32 +1845,14 @@ on_return: /* Send RTCP RR and SDES after we receive some RTP packets */ if (stream->rtcp.received >= 10 && !stream->initial_rr) { - void *sr_rr_pkt; - pj_uint8_t *pkt; - int len; - - /* Build RR or SR */ - pjmedia_rtcp_build_rtcp(&stream->rtcp, &sr_rr_pkt, &len); - - if (!stream->rtcp_sdes_bye_disabled) { - pkt = (pj_uint8_t*) stream->enc->out_pkt; - pj_memcpy(pkt, sr_rr_pkt, len); - pkt += len; - - /* Append SDES */ - len = create_rtcp_sdes(stream, (pj_uint8_t*)pkt, - stream->enc->out_pkt_size - len); - if (len > 0) { - pkt += len; - len = ((pj_uint8_t*)pkt) - ((pj_uint8_t*)stream->enc->out_pkt); - pjmedia_transport_send_rtcp(stream->transport, - stream->enc->out_pkt, len); - } - } else { - pjmedia_transport_send_rtcp(stream->transport, sr_rr_pkt, len); - } - - stream->initial_rr = PJ_TRUE; + status = send_rtcp(stream, !stream->rtcp_sdes_bye_disabled, + PJ_FALSE, PJ_FALSE); + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error sending initial RTCP RR")); + } else { + stream->initial_rr = PJ_TRUE; + } } } @@ -1882,7 +1890,6 @@ static pj_status_t create_channel( pj_pool_t *pool, { pjmedia_channel *channel; pj_status_t status; - unsigned min_out_pkt_size; /* Allocate memory for channel descriptor */ @@ -1914,15 +1921,6 @@ static pj_status_t create_channel( pj_pool_t *pool, return PJ_ENOTSUP; } - /* It should big enough to hold (minimally) RTCP SR with an SDES. */ - min_out_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) + - sizeof(pjmedia_rtcp_common) + - (4 + stream->cname.slen) + - 32; - - if (channel->out_pkt_size < min_out_pkt_size) - channel->out_pkt_size = min_out_pkt_size; - channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size); PJ_ASSERT_RETURN(channel->out_pkt != NULL, PJ_ENOMEM); @@ -2265,7 +2263,30 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, #endif pjmedia_rtcp_init2(&stream->rtcp, &rtcp_setting); + + if (info->rtp_seq_ts_set) { + stream->rtcp.stat.rtp_tx_last_seq = info->rtp_seq; + stream->rtcp.stat.rtp_tx_last_ts = info->rtp_ts; + } + } + + /* Allocate outgoing RTCP buffer, should be enough to hold SR/RR, SDES, + * BYE, and XR. + */ + stream->out_rtcp_pkt_size = sizeof(pjmedia_rtcp_sr_pkt) + + sizeof(pjmedia_rtcp_common) + + (4 + stream->cname.slen) + + 32; +#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) + if (info->rtcp_xr_enabled) { + stream->out_rtcp_pkt_size += sizeof(pjmedia_rtcp_xr_pkt); } +#endif + + if (stream->out_rtcp_pkt_size > PJMEDIA_MAX_MTU) + stream->out_rtcp_pkt_size = PJMEDIA_MAX_MTU; + + stream->out_rtcp_pkt = pj_pool_alloc(pool, stream->out_rtcp_pkt_size); /* Only attach transport when stream is ready. */ status = pjmedia_transport_attach(tp, stream, &info->rem_addr, @@ -2391,47 +2412,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream ) { PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); -#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0) - /* Send RTCP XR on stream destroy */ - if (stream->rtcp.xr_enabled) { - int i; - pjmedia_jb_state jb_state; - void *rtcp_pkt; - int len; - - /* Update RTCP XR with current JB states */ - pjmedia_jbuf_get_state(stream->jb, &jb_state); - - i = jb_state.avg_delay; - pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, - PJMEDIA_RTCP_XR_INFO_JB_NOM, - i); - - i = jb_state.max_delay; - pjmedia_rtcp_xr_update_info(&stream->rtcp.xr_session, - PJMEDIA_RTCP_XR_INFO_JB_MAX, - i); - - /* Build RTCP XR packet */ - pjmedia_rtcp_build_rtcp_xr(&stream->rtcp.xr_session, 0, - &rtcp_pkt, &len); - - /* Send the RTCP XR to remote address */ - pjmedia_transport_send_rtcp(stream->transport, rtcp_pkt, len); - - /* Send the RTCP XR to third-party destination if specified */ - if (stream->rtcp_xr_dest_len) { - pjmedia_transport_send_rtcp2(stream->transport, - &stream->rtcp_xr_dest, - stream->rtcp_xr_dest_len, - rtcp_pkt, len); - } - } -#endif - - /* Send RTCP BYE */ + /* Send RTCP BYE (also SDES & XR) */ if (!stream->rtcp_sdes_bye_disabled) { - pjmedia_stream_send_rtcp_bye(stream); + send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE); } /* Detach from transport @@ -2799,18 +2782,9 @@ PJ_DEF(pj_status_t) pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream, PJ_DEF(pj_status_t) pjmedia_stream_send_rtcp_sdes( pjmedia_stream *stream ) { - unsigned len; - PJ_ASSERT_RETURN(stream, PJ_EINVAL); - len = create_rtcp_sdes(stream, (pj_uint8_t*)stream->enc->out_pkt, - stream->enc->out_pkt_size); - if (len != 0) { - return pjmedia_transport_send_rtcp(stream->transport, - stream->enc->out_pkt, len); - } - - return PJ_SUCCESS; + return send_rtcp(stream, PJ_TRUE, PJ_FALSE, PJ_FALSE); } /* @@ -2822,14 +2796,7 @@ pjmedia_stream_send_rtcp_bye( pjmedia_stream *stream ) PJ_ASSERT_RETURN(stream, PJ_EINVAL); if (stream->enc && stream->transport) { - unsigned len; - - len = create_rtcp_bye(stream, (pj_uint8_t*)stream->enc->out_pkt, - stream->enc->out_pkt_size); - if (len != 0) { - return pjmedia_transport_send_rtcp(stream->transport, - stream->enc->out_pkt, len); - } + return send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_FALSE); } return PJ_SUCCESS; |