/***************************************************************************** * RetxHandle: handle a retx query *****************************************************************************/ static void RetxHandle(void) { ssize_t i_size = RETX_HEADER_SIZE - p_retx_block->i_size; uint8_t *p_buffer = p_retx_block->p_data + p_retx_block->i_size; sockaddr_t sout; socklen_t i_len = sizeof(sout); i_size = recvfrom( i_retx_fd, p_buffer, i_size, 0, &sout.so, &i_len ); if ( i_size < 0 && errno != EAGAIN && errno != EINTR ) { msg_Err( NULL, "unrecoverable read error, dying (%s)", strerror(errno) ); exit(EXIT_FAILURE); } if ( i_size <= 0 ) return; p_retx_block->i_size += i_size; if ( p_retx_block->i_size != RETX_HEADER_SIZE ) { if ( b_retx_tcp ) return; msg_Err( NULL, "invalid retx packet received, dying" ); exit(EXIT_FAILURE); } if ( !retx_check(p_retx_block->p_data) ) { msg_Err( NULL, "invalid retx packet, dying" ); exit(EXIT_FAILURE); } uint16_t i_seqnum = retx_get_seqnum(p_retx_block->p_data); uint16_t i_num = retx_get_num(p_retx_block->p_data); block_t *p_block = p_retx_first; p_retx_block->i_size = 0; while ( p_block != NULL ) { if ( rtp_get_seqnum(p_block->p_data) == i_seqnum ) break; p_block = p_block->p_next; } if ( p_block == NULL ) { msg_Warn( NULL, "unable to find packet %hu for retx", i_seqnum ); return; } while ( i_num && p_block != NULL ) { SendBlock( i_retx_fd, i_len ? &sout.so : NULL, i_len, p_block ); p_block = p_block->p_next; i_num--; } if ( i_num ) msg_Warn( NULL, "unable to find %hu packets after %hu", i_num, i_seqnum ); }
/** @internal @This handles data. * * @param upipe description structure of the pipe * @param uref uref structure * @param upump_p reference to pump that generated the buffer */ static inline void upipe_rtpd_input(struct upipe *upipe, struct uref *uref, struct upump **upump_p) { struct upipe_rtpd *upipe_rtpd = upipe_rtpd_from_upipe(upipe); uint8_t rtp_buffer[RTP_HEADER_SIZE]; const uint8_t *rtp_header = uref_block_peek(uref, 0, RTP_HEADER_SIZE, rtp_buffer); if (unlikely(rtp_header == NULL)) { upipe_warn(upipe, "invalid buffer received"); uref_free(uref); return; } bool valid = rtp_check_hdr(rtp_header); bool extension = rtp_check_extension(rtp_header); uint8_t cc = rtp_get_cc(rtp_header); uint8_t type = rtp_get_type(rtp_header); uint16_t seqnum = rtp_get_seqnum(rtp_header); ptrdiff_t extension_offset = rtp_extension((uint8_t *)rtp_header) - rtp_header; uref_block_peek_unmap(uref, 0, rtp_buffer, rtp_header); if (unlikely(!valid)) { upipe_warn(upipe, "invalid RTP header"); uref_free(uref); return; } size_t offset = RTP_HEADER_SIZE + 4 * cc; if (extension) { rtp_header = uref_block_peek(uref, extension_offset, RTP_EXTENSION_SIZE, rtp_buffer); if (unlikely(rtp_header == NULL)) { upipe_warn(upipe, "invalid buffer received"); uref_free(uref); return; } offset += 4 * (1 + rtpx_get_length(rtp_header)); uref_block_peek_unmap(uref, extension_offset, rtp_buffer, rtp_header); } if (unlikely(upipe_rtpd->expected_seqnum != -1 && seqnum != upipe_rtpd->expected_seqnum)) { upipe_warn_va(upipe, "potentially lost %d RTP packets", (seqnum + UINT16_MAX + 1 - upipe_rtpd->expected_seqnum) & UINT16_MAX); uref_flow_set_discontinuity(uref); } upipe_rtpd->expected_seqnum = seqnum + 1; upipe_rtpd->expected_seqnum &= UINT16_MAX; if (unlikely(type != upipe_rtpd->type)) { assert(upipe_rtpd->flow_def_input != NULL); struct uref *flow_def = uref_dup(upipe_rtpd->flow_def_input); if (unlikely(flow_def == NULL)) { uref_free(uref); upipe_throw_fatal(upipe, UBASE_ERR_ALLOC); return; } switch (type) { case RTP_TYPE_TS: uref_flow_set_def(flow_def, "block.mpegtsaligned."); break; default: break; } upipe_rtpd->type = type; upipe_rtpd_store_flow_def(upipe, flow_def); } uref_block_resize(uref, offset, -1); upipe_rtpd_output(upipe, uref, upump_p); }
/***************************************************************************** * udp_Read *****************************************************************************/ block_t *udp_Read( mtime_t i_poll_timeout ) { struct pollfd pfd[2]; int i_ret, i_nb_fd = 1; pfd[0].fd = i_handle; pfd[0].events = POLLIN; if ( i_comm_fd != -1 ) { pfd[1].fd = i_comm_fd; pfd[1].events = POLLIN; i_nb_fd++; } i_ret = poll( pfd, i_nb_fd, (i_poll_timeout + 999) / 1000 ); i_wallclock = mdate(); if ( i_ret < 0 ) { if( errno != EINTR ) msg_Err( NULL, "couldn't poll from socket (%s)", strerror(errno) ); return NULL; } if ( pfd[0].revents ) { struct iovec p_iov[i_block_cnt + 1]; block_t *p_ts, **pp_current = &p_ts; int i_iov, i_block; ssize_t i_len; uint8_t p_rtp_hdr[RTP_HEADER_SIZE]; if ( !i_last_packet ) { switch (i_print_type) { case PRINT_XML: printf("<STATUS type=\"lock\" status=\"1\"/>\n"); break; default: printf("frontend has acquired lock\n" ); } } i_last_packet = i_wallclock; if ( !b_udp ) { /* FIXME : this is wrong if RTP header > 12 bytes */ p_iov[0].iov_base = p_rtp_hdr; p_iov[0].iov_len = RTP_HEADER_SIZE; i_iov = 1; } else i_iov = 0; for ( i_block = 0; i_block < i_block_cnt; i_block++ ) { *pp_current = block_New(); p_iov[i_iov].iov_base = (*pp_current)->p_ts; p_iov[i_iov].iov_len = TS_SIZE; pp_current = &(*pp_current)->p_next; i_iov++; } pp_current = &p_ts; if ( (i_len = readv( i_handle, p_iov, i_iov )) < 0 ) { msg_Err( NULL, "couldn't read from network (%s)", strerror(errno) ); goto err; } if ( !b_udp ) { uint8_t pi_new_ssrc[4]; if ( !rtp_check_hdr(p_rtp_hdr) ) msg_Warn( NULL, "invalid RTP packet received" ); if ( rtp_get_type(p_rtp_hdr) != RTP_TYPE_TS ) msg_Warn( NULL, "non-TS RTP packet received" ); rtp_get_ssrc(p_rtp_hdr, pi_new_ssrc); if ( !memcmp( pi_ssrc, pi_new_ssrc, 4 * sizeof(uint8_t) ) ) { if ( rtp_get_seqnum(p_rtp_hdr) != i_seqnum ) msg_Warn( NULL, "RTP discontinuity" ); } else { struct in_addr addr; memcpy( &addr.s_addr, pi_new_ssrc, 4 * sizeof(uint8_t) ); msg_Dbg( NULL, "new RTP source: %s", inet_ntoa( addr ) ); memcpy( pi_ssrc, pi_new_ssrc, 4 * sizeof(uint8_t) ); switch (i_print_type) { case PRINT_XML: printf("<STATUS type=\"source\" source=\"%s\"/>\n", inet_ntoa( addr )); break; default: printf("new RTP source: %s\n", inet_ntoa( addr ) ); } } i_seqnum = rtp_get_seqnum(p_rtp_hdr) + 1; i_len -= RTP_HEADER_SIZE; } i_len /= TS_SIZE; while ( i_len && *pp_current ) { pp_current = &(*pp_current)->p_next; i_len--; } i_wallclock = mdate(); err: block_DeleteChain( *pp_current ); *pp_current = NULL; return p_ts; } else if ( i_last_packet && i_last_packet + UDP_LOCK_TIMEOUT < i_wallclock ) { switch (i_print_type) { case PRINT_XML: printf("<STATUS type=\"lock\" status=\"0\"/>\n"); break; default: printf("frontend has lost lock\n" ); } i_last_packet = 0; } if ( i_comm_fd != -1 && pfd[1].revents ) comm_Read(); return NULL; }
static void PacketRecv( block_t *p_block, uint64_t i_date ) { uint64_t i_scaled_timestamp; if ( !rtp_check_hdr( p_block->p_data ) ) { msg_Warn( NULL, "non-RTP packet received" ); free( p_block ); return; } BuildTimestamp( rtp_get_timestamp( p_block->p_data ) ); switch ( rtp_get_type( p_block->p_data ) ) { case RTP_TYPE_TS: /* 90 kHz */ i_scaled_timestamp = i_last_timestamp * 300; break; default: /* assume milliseconds */ i_scaled_timestamp = i_last_timestamp * 27000; break; } if ( i_date ) clock_NewRef( i_scaled_timestamp, i_date ); p_block->i_date = clock_ToWall( i_scaled_timestamp ) + i_buffer_length; p_block->i_seqnum = rtp_get_seqnum( p_block->p_data ); /* Insert the block at the correct position */ if ( p_last == NULL ) { p_first = p_last = p_block; p_block->p_prev = p_block->p_next = NULL; } else { block_t *p_prev = p_last; while ( p_prev != NULL && ((UINT16_MAX * 3 / 2 + (int32_t)p_prev->i_seqnum - (int32_t)p_block->i_seqnum) % UINT16_MAX - UINT16_MAX / 2) > 0 ) p_prev = p_prev->p_prev; if ( p_prev == NULL ) { p_block->p_next = p_first; p_first->p_prev = p_block; p_block->p_prev = NULL; p_first = p_block; } else { p_block->p_prev = p_prev; p_block->p_next = p_prev->p_next; p_prev->p_next = p_block; if ( p_block->p_next != NULL ) p_block->p_next->p_prev = p_block; else p_last = p_block; } } }