Structures and functions for RTCP support. BIG FAT WARNING >>>> This code is untested...
authorJean-Paul Saman <jpsaman@videolan.org>
Fri, 3 Mar 2006 21:43:48 +0000 (21:43 +0000)
committerJean-Paul Saman <jpsaman@videolan.org>
Fri, 3 Mar 2006 21:43:48 +0000 (21:43 +0000)
modules/mux/rtp/rtcp.c [new file with mode: 0644]
modules/mux/rtp/rtcp.h [new file with mode: 0644]
modules/mux/rtp/rtp.h [new file with mode: 0644]

diff --git a/modules/mux/rtp/rtcp.c b/modules/mux/rtp/rtcp.c
new file mode 100644 (file)
index 0000000..126c6d9
--- /dev/null
@@ -0,0 +1,403 @@
+/*****************************************************************************
+ * rtcp.c: RTP/RTCP source file
+ *****************************************************************************
+ * Copyright (C) 2005 M2X
+ *
+ * $Id$
+ *
+ * Authors: Jean-Paul Saman <jpsaman #_at_# videolan dot org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/time.h>
+
+#include <vlc/vlc.h>
+#include <vlc_bits.h>
+#include <vlc_block.h>
+
+#include "rtp.h"
+#include "rtcp.h"
+
+static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_block );
+static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
+static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
+static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
+static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
+static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
+
+static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp );
+static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp );
+static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp );
+static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp );
+
+static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
+{
+    unsigned int u_ssrc_count;
+    unsigned int i = 0;
+
+    if( !p_rtcp && !p_buffer )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_this, "decoding record: SR" );
+    p_rtcp->stats.u_SR_received++;
+    p_rtcp->stats.u_pkt_count   = p_buffer[20+RTCP_HEADER_LEN];
+    p_rtcp->stats.u_octet_count = p_buffer[24+RTCP_HEADER_LEN];
+    u_ssrc_count = p_buffer[RTCP_HEADER_LEN] & 0x1f;
+    msg_Dbg( p_this, "SR received %d, packet count %d, octect count %d, SSRC count %d",
+        p_rtcp->stats.u_SR_received,
+        p_rtcp->stats.u_pkt_count,
+        p_rtcp->stats.u_octet_count,
+        u_ssrc_count );
+
+    for( i=0; i < u_ssrc_count; i++ )
+    {
+        unsigned char count[4];
+
+        p_rtcp->stats.u_fract_lost = p_buffer[32+RTCP_HEADER_LEN];
+
+        count[0] = 0;
+        count[1] = p_buffer[33+RTCP_HEADER_LEN];
+        count[2] = p_buffer[34+RTCP_HEADER_LEN];
+        count[3] = p_buffer[35+RTCP_HEADER_LEN];
+
+        /* FIXME: I don't like the sight of this */
+        p_rtcp->stats.u_pkt_lost = ntohl((int)count);
+
+        p_rtcp->stats.u_highest_seq_no = ntohl( p_buffer[36+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_jitter  = ntohl( p_buffer[40+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_last_SR = ntohl( p_buffer[44+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_delay_since_last_SR = (mtime_t) ntohl( p_buffer[48+RTCP_HEADER_LEN] );
+
+        msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, jitter %d, last SR %d, delay %lld",
+            p_rtcp->stats.u_fract_lost,
+            p_rtcp->stats.u_pkt_lost,
+            p_rtcp->stats.u_highest_seq_no,
+            p_rtcp->stats.u_jitter,
+            p_rtcp->stats.u_last_SR,
+            p_rtcp->stats.u_delay_since_last_SR );
+    }
+    return VLC_SUCCESS;
+}
+
+static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
+{
+    unsigned int u_ssrc_count;
+    unsigned int i = 0;
+
+    if( !p_rtcp && !p_buffer )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_this, "decoding record: RR" );
+
+    p_rtcp->stats.u_RR_received++;
+    u_ssrc_count = (p_buffer[RTCP_HEADER_LEN] & 0x1f);
+    msg_Dbg( p_this, "RR received %d, SSRC count %d", p_rtcp->stats.u_RR_received, u_ssrc_count );
+
+    for( i=0; i < u_ssrc_count; i++ )
+    {
+        unsigned char count[4];
+
+        p_rtcp->stats.u_fract_lost = p_buffer[12+RTCP_HEADER_LEN];
+
+        count[0] = 0;
+        count[1] = p_buffer[13+RTCP_HEADER_LEN];
+        count[2] = p_buffer[14+RTCP_HEADER_LEN];
+        count[3] = p_buffer[15+RTCP_HEADER_LEN];
+
+        /* FIXME: I don't like the sight of this */
+        p_rtcp->stats.u_pkt_lost = ntohl((int)count);
+
+        p_rtcp->stats.u_highest_seq_no = ntohl( p_buffer[16+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_jitter  = ntohl( p_buffer[20+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_last_RR = ntohl( p_buffer[24+RTCP_HEADER_LEN] );
+        p_rtcp->stats.u_delay_since_last_RR = (mtime_t) ntohl( p_buffer[28+RTCP_HEADER_LEN] );
+
+        msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, jitter %d, last RR %d, delay %lld",
+            p_rtcp->stats.u_fract_lost,
+            p_rtcp->stats.u_pkt_lost,
+            p_rtcp->stats.u_highest_seq_no,
+            p_rtcp->stats.u_jitter,
+            p_rtcp->stats.u_last_RR,
+            p_rtcp->stats.u_delay_since_last_RR );
+    }
+    return VLC_SUCCESS;
+}
+
+static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
+{
+    if( !p_rtcp && !p_buffer )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_this, "decoding record: SDES" );
+
+    switch( p_buffer[8] )
+    {
+        case RTCP_INFO_CNAME:
+            p_rtcp->stats.l_dest_SSRC = ntohs( (int)(p_buffer[4+RTCP_HEADER_LEN]) );
+            break;
+        case RTCP_INFO_NAME:
+        case RTCP_INFO_EMAIL:
+        case RTCP_INFO_PHONE:
+        case RTCP_INFO_LOC:
+        case RTCP_INFO_TOOL:
+        case RTCP_INFO_NOTE:
+        case RTCP_INFO_PRIV: /* ignoring these */
+            break;
+        default:
+            return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
+{
+    if( !p_rtcp && !p_buffer )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_this, "decoding record: BYE" );
+    return VLC_SUCCESS;
+}
+
+static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
+{
+    if( !p_rtcp && !p_buffer )
+        return VLC_EGENERIC;
+
+    msg_Dbg( p_this, "decoding record: APP" );
+    /* Just ignore this packet */
+    return VLC_SUCCESS;
+}
+
+/* Decode RTCP packet
+ * Decode incoming RTCP packet and inspect the records types.
+ */
+int rtcp_decode( vlc_object_t *p_this, rtcp_t *p_rtcp, block_t *p_block )
+{
+    uint8_t *p_buffer = NULL;
+    unsigned int i_length = 0;
+    unsigned int i;
+
+    if( !p_rtcp && !p_block )
+        return VLC_EGENERIC;
+
+    i_length = p_block->i_buffer;
+    p_buffer = p_block->p_buffer;
+
+    for( i=0; i<i_length; ++i )
+    {
+        p_rtcp->u_count = p_buffer[i] & 0xF8;
+        p_rtcp->u_version = p_buffer[i] & 0x03;
+        p_rtcp->u_payload_type = p_buffer[i+1];
+        p_rtcp->u_length = (p_buffer[i+2]<<8) + p_buffer[i+3];
+        msg_Dbg( p_this, "New RTCP packet: count %d, version %d, type %d, lenght %d",
+            p_rtcp->u_count,
+            p_rtcp->u_version,
+            p_rtcp->u_payload_type,
+            p_rtcp->u_length );
+
+        switch( p_rtcp->u_payload_type )
+        {
+            case RTCP_SR:
+                rtcp_decode_SR( p_this, p_rtcp, p_buffer );
+                break;
+            case RTCP_RR:
+                rtcp_decode_RR( p_this, p_rtcp, p_buffer );
+                break;
+            case RTCP_SDES:
+                rtcp_decode_SDES( p_this, p_rtcp, p_buffer );
+                break;
+            case RTCP_BYE:
+                rtcp_decode_BYE( p_this, p_rtcp, p_buffer );
+                break;
+            case RTCP_APP:
+                rtcp_decode_APP( p_this, p_rtcp, p_buffer );
+                break;
+            default:
+                return VLC_EGENERIC;
+        }
+    }
+    return VLC_SUCCESS;
+}
+
+/*
+ * Create RTCP records for reporting to server.
+ */
+block_t *rtcp_encode( vlc_object_t *p_this, int type )
+{
+    rtcp_t  *p_rtcp = NULL;
+    block_t *p_block = NULL;
+
+    p_rtcp = (rtcp_t *) malloc( sizeof( rtcp_t ) );
+    if( !p_rtcp )
+        return NULL;
+    memset( p_rtcp, 0 , sizeof( rtcp_t ) );
+    p_rtcp->u_version = 2;
+    p_rtcp->u_payload_type = type;
+    p_rtcp->u_length = RTCP_HEADER_LEN;
+
+    switch( type )
+    {
+        case RTCP_SR: p_rtcp->u_length += sizeof(rtcp_SR); break;
+        case RTCP_RR: p_rtcp->u_length += sizeof(rtcp_RR); break;
+        case RTCP_SDES:
+            p_rtcp->u_length += sizeof(rtcp_SDES) + strlen(p_rtcp->report.sdes.p_data);
+            break;
+        case RTCP_BYE:  p_rtcp->u_length += sizeof(rtcp_BYE);  break;
+        case RTCP_APP:  /* ignore: p_rtcp->u_length += sizeof(rtcp_APP); */ break;
+    }
+
+    /* FIXME: Maybe this should be a buffer pool instead */
+    p_block = block_New( p_this, p_rtcp->u_length );
+    return p_block;
+}
+
+static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp )
+{
+    mtime_t ntp_time;
+    bs_t bits, *s = &bits;
+    block_t *p_block = NULL;
+
+    /* FIXME: Maybe this should be a buffer pool instead */
+    p_block = block_New( p_this, p_rtcp->u_length );
+    if( !p_block )
+        return NULL;
+
+    bs_init( s, p_block->p_buffer, p_block->i_buffer );
+
+    /* Fill in header */
+    bs_write( s, 5, p_rtcp->u_count );
+    bs_write( s, 1, 0 ); /* padding */
+    bs_write( s, 2, p_rtcp->u_version );
+    bs_write( s, 8, p_rtcp->u_payload_type );
+    bs_write( s, 16, p_rtcp->u_length );
+
+    /* fill in record */
+    bs_write( s, 32, htonl( p_rtcp->report.sr.u_ssrc ) );
+
+    ntp_time = mdate();
+    bs_write( s, 32, htonl( ((unsigned int)(ntp_time>>32)) ) ); /* ntp_timestampH */
+    bs_write( s, 32, htonl( ((unsigned int)ntp_time)) );/* ntp_timestampL */
+
+    /* FIXME: Make sure to generate a good RTP server timestamp.
+        p_rtcp->report.sr.rtp_timestamp = htonl(
+        (unsigned int) ((double)ntp_time.tv_sec +
+        (double)ntp_time.tv_usec/1000000.) * p_mux->rate
+        + session->start_rtptime ); */
+    bs_write( s, 32, htonl( p_rtcp->report.sr.rtp_timestamp ) );
+    bs_write( s, 32, htonl( p_rtcp->report.sr.u_pkt_count ) );
+    bs_write( s, 32, htonl( p_rtcp->report.sr.u_octet_count ) );
+
+    return p_block;
+}
+
+static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp )
+{
+    bs_t bits, *s = &bits;
+    block_t *p_block = NULL;
+
+    /* FIXME: Maybe this should be a buffer pool instead */
+    p_block = block_New( p_this, p_rtcp->u_length );
+    if( !p_block )
+        return NULL;
+
+    bs_init( s, p_block->p_buffer, p_block->i_buffer );
+
+    /* Fill in header */
+    bs_write( s, 5, p_rtcp->u_count );
+    bs_write( s, 1, 0 ); /* padding */
+    bs_write( s, 2, p_rtcp->u_version );
+    bs_write( s, 8, p_rtcp->u_payload_type );
+    bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
+
+    /* fill in record */
+    bs_write( s, 32, htonl( p_rtcp->report.rr.u_ssrc ) );
+
+    return p_block;
+}
+
+static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp )
+{
+    bs_t bits, *s = &bits;
+    block_t *p_block = NULL;
+    char *p_hostname = strdup("hostname");
+    int i_length;
+    int i;
+
+    /* FIXME: Maybe this should be a buffer pool instead */
+    p_block = block_New( p_this, p_rtcp->u_length );
+    if( !p_block )
+        return NULL;
+
+    bs_init( s, p_block->p_buffer, p_block->i_buffer );
+
+    /* Fill in header */
+    bs_write( s, 5, p_rtcp->u_count );
+    bs_write( s, 1, 0 ); /* padding */
+    bs_write( s, 2, p_rtcp->u_version );
+    bs_write( s, 8, p_rtcp->u_payload_type );
+    bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
+
+    /* fill in record */
+    bs_write( s, 32,htonl( p_rtcp->report.sdes.u_ssrc ) );
+    bs_write( s, 8, htonl( p_rtcp->report.sdes.u_attr_name ) );
+    bs_write( s, 8, htonl( p_rtcp->report.sdes.u_length ) );
+
+    i_length = strlen(p_hostname);
+    bs_write( s, 8, i_length );
+    for( i=0; i<i_length; i++ )
+    {
+        bs_write( s, 8, p_hostname[i] );
+    }
+    free(p_hostname);
+    return p_block;
+}
+
+static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp )
+{
+    bs_t bits, *s = &bits;
+    block_t *p_block = NULL;
+    char *p_reason = strdup( "Stream ended." );
+    int i_length;
+    int i;
+
+    /* FIXME: Maybe this should be a buffer pool instead */
+    p_block = block_New( p_this, p_rtcp->u_length );
+    if( !p_block )
+        return NULL;
+
+    bs_init( s, p_block->p_buffer, p_block->i_buffer );
+
+    /* Fill in header */
+    bs_write( s, 5, p_rtcp->u_count );
+    bs_write( s, 1, 0 ); /* padding */
+    bs_write( s, 2, p_rtcp->u_version );
+    bs_write( s, 8, p_rtcp->u_payload_type );
+    bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
+
+    /* fill in record */
+    bs_write( s, 32, htonl( p_rtcp->report.sdes.u_ssrc ) );
+
+    i_length = strlen(p_reason);
+    bs_write( s, 8, i_length );
+    for( i=0; i<i_length; i++ )
+    {
+        bs_write( s, 8, p_reason[i] );
+    }
+    free(p_reason);
+    return p_block;
+}
diff --git a/modules/mux/rtp/rtcp.h b/modules/mux/rtp/rtcp.h
new file mode 100644 (file)
index 0000000..415a479
--- /dev/null
@@ -0,0 +1,147 @@
+/*****************************************************************************
+ * rtcp.h: RTP/RTCP headerfile
+ *****************************************************************************
+ * Copyright (C) 2005 M2X
+ *
+ * $Id$
+ *
+ * Authors: Jean-Paul Saman <jpsaman #_at_# videolan dot org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _RTCP_H
+#define _RTCP_H 1
+
+/* RTCP packet types */
+#define RTCP_SR     200
+#define RTCP_RR     201
+#define RTCP_SDES   202
+#define RTCP_BYE    203
+#define RTCP_APP    204
+/* End of RTCP packet types */
+
+/* RTCP Info */
+#define RTCP_INFO_CNAME 1
+#define RTCP_INFO_NAME  2
+#define RTCP_INFO_EMAIL 3
+#define RTCP_INFO_PHONE 4
+#define RTCP_INFO_LOC   5
+#define RTCP_INFO_TOOL  6
+#define RTCP_INFO_NOTE  7
+#define RTCP_INFO_PRIV  8
+/* End of RTCP Info */
+
+#define RTCP_HEADER_LEN 3
+
+typedef struct
+{
+    unsigned int u_ssrc;
+    unsigned int ntp_timestampH;
+    unsigned int ntp_timestampL;
+    unsigned int rtp_timestamp;
+    unsigned int u_pkt_count;
+    unsigned int u_octet_count;
+} rtcp_SR;
+
+typedef struct _RTCP_header_RR
+{
+    unsigned int u_ssrc;
+} rtcp_RR;
+
+typedef struct
+{
+    unsigned long u_ssrc;
+    unsigned char u_fract_lost;
+    unsigned char u_pck_lost[3];
+    unsigned int  u_highest_seq_no;
+    unsigned int  u_jitter;
+    unsigned int  u_last_SR;
+    unsigned int  u_delay_last_SR;
+} rtcp_report_block_SR;
+
+typedef struct
+{
+    unsigned int  u_ssrc;
+    unsigned char u_attr_name;
+    unsigned char u_length;
+    char          *p_data;
+} rtcp_SDES;
+
+typedef struct
+{
+    unsigned int  u_ssrc;
+    unsigned char u_length;
+} rtcp_BYE;
+
+typedef struct
+{
+    unsigned char u_length;
+    char          *p_data;
+} rtcp_APP;
+
+/**
+ * structure rtcp_stats_t
+ */
+typedef struct
+{
+    unsigned int  u_RR_received;   /*< RR records received */
+    unsigned int  u_SR_received;   /*< SR records received */
+    unsigned long l_dest_SSRC;     /*< SSRC */
+    unsigned int  u_pkt_count;     /*< count of packets received */
+    unsigned int  u_octet_count;   /*< ? */
+    unsigned int  u_pkt_lost;      /*< count of packets lost */
+    unsigned int  u_fract_lost;    /*< count of fractional packets lost */
+    unsigned int  u_highest_seq_no;/*< highest sequence number found */
+    unsigned int  u_jitter;        /*< jitter calculated */
+    unsigned int  u_last_SR;       /*< last SR record received */
+    unsigned int  u_last_RR;       /*< last RR record received */
+    mtime_t u_delay_since_last_SR; /*< delay since last SR record received */
+    mtime_t u_delay_since_last_RR; /*< delay since last RR record received */
+} rtcp_stats_t;
+
+typedef struct {
+    int fd;                 /*< socket descriptor of rtcp stream */
+
+    unsigned int u_count;        /*< packet count */
+    unsigned int u_version;      /*< RTCP version number */
+    unsigned int u_length;       /*< lenght of packet */
+    unsigned int u_payload_type; /*< type of RTCP payload */
+    rtcp_stats_t stats;          /*< RTCP statistics */
+
+    union {
+        rtcp_SR sr;         /*< SR record */
+        rtcp_RR rr;         /*< RR record */
+        rtcp_SDES sdes;     /*< SDES record */
+        rtcp_BYE bye;       /*< BYE record */
+        rtcp_APP app;       /*< APP record */
+    } report;
+
+    /*int (*pf_connect)( void *p_userdata, char *p_server, int i_port );
+    int (*pf_disconnect)( void *p_userdata );
+    int (*pf_read)( void *p_userdata, uint8_t *p_buffer, int i_buffer );
+    int (*pf_write)( void *p_userdata, uint8_t *p_buffer, int i_buffer );*/
+} rtcp_t;
+
+
+/**
+ * Decode RTCP packet
+ * Decode incoming RTCP packet and inspect the records types.
+ */
+int rtcp_decode( vlc_object_t *p_this, rtcp_t *p_rtcp, block_t *p_block );
+//VLC_EXPORT( int, rtcp_decode, ( rtcp_t *p_rtcp, block_t *p_block ) );
+block_t *rtcp_encode( vlc_object_t *p_this, int type );
+
+#endif /* RTCP_H */
diff --git a/modules/mux/rtp/rtp.h b/modules/mux/rtp/rtp.h
new file mode 100644 (file)
index 0000000..7e5c4ca
--- /dev/null
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * rtp.h: RTP/RTCP headerfile
+ *****************************************************************************
+ * Copyright (C) 2005 M2X
+ *
+ * $Id$
+ *
+ * Authors: Jean-Paul Saman <jpsaman #_at_# videolan dot org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _RTP_H
+#define _RTP_H 1
+
+#define RTP_HEADER_LEN 12
+#define RTP_SEQ_NUM_SIZE 65536
+
+/*
+ * See RFC 1889 & RFC 2250.
+ */
+typedef struct {
+    int fd;        /*< socket descriptor of rtp stream */
+
+    unsigned int u_version;      /*< rtp version number */
+    unsigned int u_CSRC_count;   /*< CSRC count */
+    unsigned int u_payload_type; /*< type of RTP payload stream */
+    vlc_bool_t   b_extension;    /*< The header is followed by exactly one header extension */
+    unsigned int u_marker;       /*< marker field expect 1 */
+    unsigned int u_seq_no;       /*< sequence number of RTP stream */
+    uint32_t i_timestamp;        /*< timestamp of stream */
+    unsigned int ssrc;           /*< stream number is used here. */
+
+    unsigned int u_ext_length;   /*< lenght of extension field */
+
+    /*int (*pf_connect)( void *p_userdata, char *p_server, int i_port );
+    int (*pf_disconnect)( void *p_userdata );
+    int (*pf_read)( void *p_userdata, uint8_t *p_buffer, int i_buffer );
+    int (*pf_write)( void *p_userdata, uint8_t *p_buffer, int i_buffer );*/
+} rtp_t;
+
+#endif /* RTP_H */