Example #1
0
/*****************************************************************************
 * 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 );
}
Example #2
0
/** @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);
}
Example #3
0
/*****************************************************************************
 * 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;
}
Example #4
0
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;
        }
    }
}