/** * RTP/RTCP session thread for stream sockets (framed RTP) */ void *rtp_stream_thread (void *opaque) { #ifndef WIN32 demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; int fd = sys->fd; for (;;) { /* There is no reordering on stream sockets, so no timeout. */ ssize_t val; uint16_t frame_len; if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2) break; block_t *block = block_Alloc (ntohs (frame_len)); if (unlikely(block == NULL)) break; block_cleanup_push (block); val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL); vlc_cleanup_pop (); if (val != (ssize_t)block->i_buffer) { block_Release (block); break; } int canc = vlc_savecancel (); rtp_process (demux, block); rtp_dequeue_force (demux, sys->session); vlc_restorecancel (canc); } #else (void) opaque; #endif return NULL; }
/** * Gets a datagram from the network. * @param fd datagram file descriptor * @return a block or NULL on fatal error (socket dead) */ static block_t *rtp_dgram_recv (vlc_object_t *obj, int fd) { block_t *block = block_Alloc (0xffff); ssize_t len; block_cleanup_push (block); do { len = net_Read (obj, fd, NULL, block->p_buffer, block->i_buffer, false); if (((len <= 0) && fd_dead (fd)) || !vlc_object_alive (obj)) { /* POLLHUP -> permanent (DCCP) socket error */ block_Release (block); block = NULL; break; } } while (len == -1); vlc_cleanup_pop (); return block ? block_Realloc (block, 0, len) : NULL; }
/** * Gets a framed RTP packet. * @param fd stream file descriptor * @return a block or NULL in case of fatal error */ static block_t *rtp_stream_recv (vlc_object_t *obj, int fd) { ssize_t len = 0; uint8_t hdr[2]; /* frame header */ /* Receives the RTP frame header */ do { ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false); if (val <= 0) return NULL; len += val; } while (len < 2); block_t *block = block_Alloc (GetWBE (hdr)); /* Receives the RTP packet */ for (ssize_t i = 0; i < len;) { ssize_t val; block_cleanup_push (block); val = net_Read (obj, fd, NULL, block->p_buffer + i, block->i_buffer - i, false); vlc_cleanup_pop (); if (val <= 0) { block_Release (block); return NULL; } i += val; } return block; }
/***************************************************************************** * ThreadWrite: Write a packet on the network at the good time. *****************************************************************************/ static void* ThreadWrite( void *data ) { sout_access_out_t *p_access = data; sout_access_out_sys_t *p_sys = p_access->p_sys; mtime_t i_date_last = -1; const unsigned i_group = var_GetInteger( p_access, SOUT_CFG_PREFIX "group" ); mtime_t i_to_send = i_group; unsigned i_dropped_packets = 0; for (;;) { block_t *p_pk = block_FifoGet( p_sys->p_fifo ); mtime_t i_date, i_sent; i_date = p_sys->i_caching + p_pk->i_dts; if( i_date_last > 0 ) { if( i_date - i_date_last > 2000000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, hole (%"PRId64" > 2s) -> drop", i_date - i_date_last ); block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; i_dropped_packets++; continue; } else if( i_date - i_date_last < -1000 ) { if( !i_dropped_packets ) msg_Dbg( p_access, "mmh, packets in the past (%"PRId64")", i_date_last - i_date ); } } block_cleanup_push( p_pk ); i_to_send--; if( !i_to_send || (p_pk->i_flags & BLOCK_FLAG_CLOCK) ) { mwait( i_date ); i_to_send = i_group; } if ( send( p_sys->i_handle, p_pk->p_buffer, p_pk->i_buffer, 0 ) == -1 ) msg_Warn( p_access, "send error: %s", vlc_strerror_c(errno) ); vlc_cleanup_pop(); if( i_dropped_packets ) { msg_Dbg( p_access, "dropped %i packets", i_dropped_packets ); i_dropped_packets = 0; } #if 1 i_sent = mdate(); if ( i_sent > i_date + 20000 ) { msg_Dbg( p_access, "packet has been sent too late (%"PRId64 ")", i_sent - i_date ); } #endif block_FifoPut( p_sys->p_empty_blocks, p_pk ); i_date_last = i_date; } return NULL; }
/** * RTP/RTCP session thread for datagram sockets */ void *rtp_dgram_thread (void *opaque) { demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; mtime_t deadline = VLC_TS_INVALID; int rtp_fd = sys->fd; struct iovec iov = { .iov_len = DEFAULT_MRU, }; struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; struct pollfd ufd[1]; ufd[0].fd = rtp_fd; ufd[0].events = POLLIN; for (;;) { int n = poll (ufd, 1, rtp_timeout (deadline)); if (n == -1) continue; int canc = vlc_savecancel (); if (n == 0) goto dequeue; if (ufd[0].revents) { n--; if (unlikely(ufd[0].revents & POLLHUP)) break; /* RTP socket dead (DCCP only) */ block_t *block = block_Alloc (iov.iov_len); if (unlikely(block == NULL)) { if (iov.iov_len == DEFAULT_MRU) break; /* we are totallly screwed */ iov.iov_len = DEFAULT_MRU; continue; /* retry with shrunk MRU */ } iov.iov_base = block->p_buffer; #ifdef __linux__ msg.msg_flags = MSG_TRUNC; #else msg.msg_flags = 0; #endif ssize_t len = recvmsg (rtp_fd, &msg, 0); if (len != -1) { #ifdef MSG_TRUNC if (msg.msg_flags & MSG_TRUNC) { msg_Err(demux, "%zd bytes packet truncated (MRU was %zu)", len, iov.iov_len); block->i_flags |= BLOCK_FLAG_CORRUPTED; iov.iov_len = len; } else #endif block->i_buffer = len; rtp_process (demux, block); } else { msg_Warn (demux, "RTP network error: %s", vlc_strerror_c(errno)); block_Release (block); } } dequeue: if (!rtp_dequeue (demux, sys->session, &deadline)) deadline = VLC_TS_INVALID; vlc_restorecancel (canc); } return NULL; } /** * RTP/RTCP session thread for stream sockets (framed RTP) */ void *rtp_stream_thread (void *opaque) { #ifndef _WIN32 demux_t *demux = opaque; demux_sys_t *sys = demux->p_sys; int fd = sys->fd; for (;;) { /* There is no reordering on stream sockets, so no timeout. */ ssize_t val; uint16_t frame_len; if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2) break; block_t *block = block_Alloc (ntohs (frame_len)); if (unlikely(block == NULL)) break; block_cleanup_push (block); val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL); vlc_cleanup_pop (); if (val != (ssize_t)block->i_buffer) { block_Release (block); break; } int canc = vlc_savecancel (); rtp_process (demux, block); rtp_dequeue_force (demux, sys->session); vlc_restorecancel (canc); } #else (void) opaque; #endif return NULL; }