Commit 4d243c1d authored by Jean-Paul Saman's avatar Jean-Paul Saman

Rewrote internal RTCP to support multiple client connections. TODO: rtcp...

Rewrote internal RTCP to support multiple client connections. TODO: rtcp scheduling function, server socket, hooking it up with RTP stream_out connections.
parent cec120d5
......@@ -1448,6 +1448,7 @@ then
VLC_ADD_PLUGINS([stream_out_dummy stream_out_standard stream_out_es stream_out_rtp stream_out_description vod_rtsp])
VLC_ADD_PLUGINS([stream_out_duplicate stream_out_gather stream_out_display stream_out_transcode stream_out_bridge stream_out_mosaic_bridge stream_out_autodel])
# VLC_ADD_PLUGINS([stream_out_transrate])
VLC_ADD_PLUGINS([rtcp])
VLC_ADD_PLUGINS([profile_parser])
AC_DEFINE(ENABLE_SOUT, 1, Define if you want the stream output support)
......
......@@ -22,9 +22,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/time.h>
#include <vlc/vlc.h>
#include <vlc_bits.h>
......@@ -33,152 +33,576 @@
#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 void send_RTCP( vlc_object_t *p_this, rtcp_event_t rtcp_event )
{
/* FIXME: higher level functions that should be in another file */
}
static void rtcp_schedule( vlc_object_t *p_this, uint64_t i_sched, rtcp_event_t rtcp_event )
{
/* FIXME: higher level functions that should be in another file */
}
/* SDES support functions */
static int SDES_client_item_add( rtcp_client_t *p_client, int i_item, char *psz_name )
{
rtcp_SDES_item_t *p_item = NULL;
p_item = (rtcp_SDES_item_t *) malloc( sizeof( rtcp_SDES_item_t ) );
if( !p_item )
return VLC_EGENERIC;
p_item->u_type = i_item;
p_item->psz_data = strdup( psz_name );
p_item->i_index = p_client->i_items + 1;;
INSERT_ELEM( p_client->pp_sdes, p_client->i_items,
p_item->i_index, p_item );
return VLC_EGENERIC;
}
static int SDES_client_item_del( rtcp_client_t *p_client )
{
uint32_t i = 0;
for( i=0; i < p_client->i_items; i++ )
{
rtcp_SDES_item_t *p_old = p_client->pp_sdes[i];
REMOVE_ELEM( p_client->pp_sdes, p_client->i_items, i );
p_client->i_items--;
if( p_old->psz_data)
free( p_old->psz_data );
free( p_old );
}
return VLC_SUCCESS;
}
int rtcp_add_client( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
rtcp_client_t *p_client = NULL;
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = (rtcp_client_t*) malloc( sizeof(rtcp_client_t) );
if( !p_client )
return VLC_EGENERIC;
p_client->i_index = p_rtcp->i_clients + 1;
p_client->b_deleted = VLC_FALSE;
*i_pos = p_client->i_index ;
INSERT_ELEM( p_rtcp->pp_clients, p_rtcp->i_clients,
p_client->i_index, p_client );
p_rtcp->i_clients++;
p_rtcp->u_clients++;
vlc_mutex_unlock( &p_rtcp->object_lock );
return VLC_SUCCESS;
}
int rtcp_del_client( vlc_object_t *p_this, uint32_t u_ssrc )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
uint32_t i_pos = 0;
vlc_mutex_lock( &p_rtcp->object_lock );
if( p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos ) == VLC_SUCCESS )
{
rtcp_client_t *p_old = p_rtcp->pp_clients[i_pos];
p_old->b_deleted = VLC_TRUE;
p_old->i_timeout = 5 * (p_rtcp->i_date - p_rtcp->i_last_date) +
p_rtcp->i_next_date;
p_rtcp->u_clients--;
}
vlc_mutex_unlock( &p_rtcp->object_lock );
return VLC_SUCCESS;
}
/* rtcp_cleanup_clients should not be called too often */
int rtcp_cleanup_clients( vlc_object_t *p_this )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
uint32_t i = 0;
vlc_mutex_lock( &p_rtcp->object_lock );
for( i=0; i < p_rtcp->i_clients; i++ )
{
rtcp_client_t *p_old = p_rtcp->pp_clients[i];
if( p_old->b_deleted &&
(p_old->i_timeout > mdate()) )
{
REMOVE_ELEM( p_rtcp->pp_clients, p_rtcp->i_clients, i );
p_rtcp->i_clients--;
SDES_client_item_del( p_old );
free( p_old );
}
}
vlc_mutex_unlock( &p_rtcp->object_lock );
return VLC_SUCCESS;
}
/* rtcp_find_client should be called with the object lock held.
* vlc_mutex_lock( &p_rtcp->obj_lock );
*/
int rtcp_find_client( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
uint32_t i = 0;
for( i=0; i < p_rtcp->i_clients; i++ )
{
if( p_rtcp->pp_clients[i]->u_ssrc == u_ssrc )
{
*i_pos = i;
return VLC_SUCCESS;
}
}
*i_pos = -1;
return VLC_EGENERIC;
}
/*--------------------------------------------------------------------------
* rtcp_interval - Calculate the interval in seconds for sending RTCP packets.
*--------------------------------------------------------------------------
*/
uint64_t rtcp_interval( vlc_object_t *p_this, uint64_t u_bandwidth,
vlc_bool_t b_sender, vlc_bool_t b_first )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
rtcp_client_t *p_client = NULL;
uint32_t i_rtcp_min = 5; /* seconds */
uint32_t i_pos = 0;
double i_bandwidth = u_bandwidth;
const double i_compensation = 2.71828 - 1.5;
double i_interval = 0;
int n = p_rtcp->i_clients;
int u_ssrc = 0; /* FIXME: how to know which client we look for?? */
if( b_first )
i_rtcp_min = (i_rtcp_min >> 1);
if( (double)(p_rtcp->u_active) <= (double)(p_rtcp->u_clients * 0.25) )
{
if( b_sender )
{
i_bandwidth = i_bandwidth * 0.25;
n = p_rtcp->u_active;
}
else
{
i_bandwidth = i_bandwidth * ( 1 - 0.25 );
n = n - p_rtcp->u_active;
}
}
/* calculate average time between reports */
p_client = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( !p_client )
return -1;
i_interval = p_client->p_stats->u_avg_pkt_size * ( n / i_bandwidth );
if( i_interval < i_rtcp_min )
i_interval = i_rtcp_min;
i_interval = i_interval * ( drand48() + 0.5 );
i_interval = (double) (i_interval / i_compensation);
return (uint64_t)i_interval;
}
/*--------------------------------------------------------------------------
* rtcp_expire - decides to sent an RTCP report or a BYE record
*--------------------------------------------------------------------------
*/
void rtcp_expire( vlc_object_t *p_this, rtcp_event_t rtcp_event,
uint64_t u_bandwidth, vlc_bool_t b_sender, vlc_bool_t *b_first )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
rtcp_client_t *p_client = NULL;
rtcp_stats_t *p_stats = NULL;
mtime_t i_interval = 0;
uint32_t i_pos = 0;
int u_ssrc = 0; /* FIXME: how to know which client we look for?? */
p_client = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( !p_client )
return;
p_stats = (rtcp_stats_t*) p_client->p_stats;
i_interval = (mtime_t) rtcp_interval( p_this, u_bandwidth,
b_sender, *b_first );
p_rtcp->i_next_date = p_rtcp->i_last_date + i_interval;
switch( rtcp_event )
{
case EVENT_BYE:
if( p_rtcp->i_next_date <= p_rtcp->i_date )
send_RTCP( p_this, rtcp_event );
else
rtcp_schedule( p_this, p_rtcp->i_next_date, rtcp_event );
break;
case EVENT_REPORT:
if( p_rtcp->i_next_date <= p_rtcp->i_date )
{
send_RTCP( p_this, rtcp_event );
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 );
/* Magic numbers are from RFC 3550 page 92
* 1.0/16.0 = 0.0625 and
* 15.0/16.0 = 0.9375
*/
p_stats->u_avg_pkt_size = (uint64_t)
( (double) ( (double)p_stats->u_sent_pkt_size / ((double)0.0625) ) +
( ((double)0.9357) * p_stats->u_avg_pkt_size ) );
/* recalculate */
p_rtcp->i_last_date = p_rtcp->i_date;
i_interval = rtcp_interval( p_this, u_bandwidth,
b_sender, *b_first );
rtcp_schedule( p_this, p_rtcp->i_next_date + i_interval, rtcp_event );
*b_first = VLC_FALSE;
}
else
{
rtcp_schedule( p_this, p_rtcp->i_next_date, rtcp_event );
}
break;
}
p_rtcp->i_date = p_rtcp->i_next_date;
}
static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
/*--------------------------------------------------------------------------
* Local functions prototoypes
*--------------------------------------------------------------------------
*/
static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
/*--------------------------------------------------------------------------
* Local functions
*--------------------------------------------------------------------------
*/
static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
unsigned int u_ssrc_count;
rtcp_t *p_rtcp = (rtcp_t *) p_this;
unsigned int i = 0;
if( !p_rtcp && !p_buffer )
if( !p_pkt )
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];
/* parse sender info */
p_pkt->u_payload_type = RTCP_SR;
p_pkt->report.sr.ntp_timestampH = bs_read( p_rtcp->bs, 32 );
p_pkt->report.sr.ntp_timestampL = bs_read( p_rtcp->bs, 32 );
p_pkt->report.sr.rtp_timestamp = bs_read( p_rtcp->bs, 32 );
p_pkt->report.sr.u_pkt_count = bs_read( p_rtcp->bs, 32 ); /*sender*/
p_pkt->report.sr.u_octet_count = bs_read( p_rtcp->bs, 32 ); /*sender*/
p_rtcp->stats.u_fract_lost = p_buffer[32+RTCP_HEADER_LEN];
/* parse report block */
for( i=0; i < p_pkt->u_report; i++ )
{
rtcp_client_t *p_client = NULL;
uint32_t i_pos = 0;
uint32_t u_ssrc = 0;
int result = 0;
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];
u_ssrc = bs_read( p_rtcp->bs, 32 );
/* FIXME: I don't like the sight of this */
p_rtcp->stats.u_pkt_lost = ntohl((int)count);
result = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
result = p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
return VLC_ENOMEM;
}
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
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] );
p_client->p_stats->u_SR_received++;
p_client->p_stats->u_pkt_count++;
p_client->p_stats->u_octet_count++;
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 );
msg_Dbg( p_this, "SR received %d, packet count %d, octect count %d, SSRC count %d",
p_client->p_stats->u_SR_received,
p_client->p_stats->u_pkt_count,
p_client->p_stats->u_octet_count,
p_pkt->u_ssrc );
p_client->p_stats->u_fraction_lost = bs_read( p_rtcp->bs, 8 );
p_client->p_stats->u_pkt_lost = bs_read( p_rtcp->bs, 24 );
p_client->p_stats->u_highest_seq_no = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_jitter = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_last_SR = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_delay_since_last_SR = (mtime_t) bs_read( p_rtcp->bs, 32 );
/* Magic numbers are from RFC 3550 page 92
* 1.0/16.0 = 0.0625 and
* 15.0/16.0 = 0.9375
*/
p_client->p_stats->u_avg_pkt_size = (uint64_t)
( (double)((double)p_client->p_stats->u_sent_pkt_size * (double)(0.0625)) +
((double)(0.9375) * p_client->p_stats->u_avg_pkt_size) );
msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, "
"jitter %d, last SR %d, delay %lld",
p_client->p_stats->u_fraction_lost,
p_client->p_stats->u_pkt_lost,
p_client->p_stats->u_highest_seq_no,
p_client->p_stats->u_jitter,
p_client->p_stats->u_last_SR,
p_client->p_stats->u_delay_since_last_SR );
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
}
return VLC_SUCCESS;
}
static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
unsigned int u_ssrc_count;
rtcp_t *p_rtcp = (rtcp_t *) p_this;
unsigned int i = 0;
if( !p_rtcp && !p_buffer )
if( !p_pkt )
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++ )
for( i=0; i < p_pkt->u_report; i++ )
{
unsigned char count[4];
rtcp_client_t *p_client = NULL;
uint32_t i_pos = 0;
uint32_t u_ssrc = 0;
int result = 0;
p_rtcp->stats.u_fract_lost = p_buffer[12+RTCP_HEADER_LEN];
u_ssrc = bs_read( p_rtcp->bs, 32 );
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];
result = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
result = p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
return VLC_ENOMEM;
}
/* FIXME: I don't like the sight of this */
p_rtcp->stats.u_pkt_lost = ntohl((int)count);
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
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] );
p_client->p_stats->u_RR_received++;
msg_Dbg( p_this, "RR received %d, SSRC %d",
p_client->p_stats->u_RR_received, u_ssrc );
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 );
p_client->p_stats->u_fraction_lost = bs_read( p_rtcp->bs, 8 );
p_client->p_stats->u_pkt_lost = bs_read( p_rtcp->bs, 24 );
p_client->p_stats->u_highest_seq_no = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_jitter = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_last_SR = bs_read( p_rtcp->bs, 32 );
p_client->p_stats->u_delay_since_last_SR = (mtime_t) bs_read( p_rtcp->bs, 32 );
/* Magic numbers are from RFC 3550 page 92
* 1.0/16.0 = 0.0625 and
* 15.0/16.0 = 0.9375
*/
p_client->p_stats->u_avg_pkt_size = (uint64_t)
( (double)((double)p_client->p_stats->u_sent_pkt_size * (double)(0.0625)) +
((double)(0.9375) * p_client->p_stats->u_avg_pkt_size) );
msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, "
"jitter %d, last SR %d, delay %lld",
p_client->p_stats->u_fraction_lost,
p_client->p_stats->u_pkt_lost,
p_client->p_stats->u_highest_seq_no,
p_client->p_stats->u_jitter,
p_client->p_stats->u_last_SR,
p_client->p_stats->u_delay_since_last_SR );
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
}
return VLC_SUCCESS;
}
static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
if( !p_rtcp && !p_buffer )
rtcp_t *p_rtcp = (rtcp_t *) p_this;
unsigned int i = 0;
if( !p_pkt )
return VLC_EGENERIC;
msg_Dbg( p_this, "decoding record: SDES" );
switch( p_buffer[8] )
for( i = 0; i < p_pkt->u_report; i++ )
{
rtcp_client_t *p_client = NULL;
uint32_t i_pos = 0;
uint32_t u_ssrc = 0;
uint8_t u_item = 0;
uint8_t u_length = 0;
int i = 0;
int result = 0;
u_ssrc = bs_read( p_rtcp->bs, 32 );
result = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
result = p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
return VLC_ENOMEM;
}
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
u_item = bs_read( p_rtcp->bs, 8 );
switch( u_item )
{
case RTCP_SDES_CNAME:
case RTCP_SDES_NAME:
case RTCP_SDES_EMAIL:
case RTCP_SDES_PHONE:
case RTCP_SDES_LOC:
case RTCP_SDES_TOOL:
case RTCP_SDES_NOTE:
{
char psz_name[255];
u_length = bs_read( p_rtcp->bs, 8 );
for( i = 0 ; i < u_length; i++ )
{
case RTCP_INFO_CNAME:
p_rtcp->stats.l_dest_SSRC = ntohs( (int)(p_buffer[4+RTCP_HEADER_LEN]) );
psz_name[i] = bs_read( p_rtcp->bs, 8 );
}
SDES_client_item_add( p_client, u_item, psz_name );
}
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 */
case RTCP_SDES_PRIV: /* ignoring these */
{
uint8_t u_prefix_len = 0;
uint8_t u_length = 0;
char psz_prefix_name[255];
char psz_name[255];
u_length = bs_read( p_rtcp->bs, 8 );
u_prefix_len = bs_read( p_rtcp->bs, 8 );
if( u_prefix_len > 254 )
u_prefix_len = 254;
for( i=0 ; i < u_prefix_len; i++ )
{
psz_prefix_name[i] = bs_read( p_rtcp->bs, 8 );
}
psz_prefix_name[255] = '\0';
SDES_client_item_add( p_client, u_item, psz_prefix_name );
for( i=0 ; i < u_length; i++ )
{
psz_name[i] = bs_read( p_rtcp->bs, 8 );
}
psz_name[255] = '\0';
SDES_client_item_add( p_client, u_item, psz_name );
}
break;
default:
return VLC_EGENERIC;
}
/* Magic numbers are from RFC 3550 page 92
* 1.0/16.0 = 0.0625 and
* 15.0/16.0 = 0.9375
*/
p_client->p_stats->u_avg_pkt_size = (uint64_t)
( (double)((double)p_client->p_stats->u_sent_pkt_size * (double)(0.0625)) +
((double)(0.9375) * p_client->p_stats->u_avg_pkt_size) );
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
}
return VLC_SUCCESS;
}
static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
if( !p_rtcp && !p_buffer )
rtcp_t *p_rtcp = (rtcp_t *) p_this;
uint32_t u_ssrc = 0;
uint8_t u_length = 0;
int i = 0;
if( !p_pkt )
return VLC_EGENERIC;
msg_Dbg( p_this, "decoding record: BYE" );
u_ssrc = bs_read( p_rtcp->bs, 32 );
p_rtcp->pf_del_client( p_this, u_ssrc );
u_length = p_pkt->u_length-1;
for( i = 0 ; i < u_length; i++ )
{
u_ssrc = bs_read( p_rtcp->bs, 8 );
p_rtcp->pf_del_client( p_this, u_ssrc );
}
return VLC_SUCCESS;
}
static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
if( !p_rtcp && !p_buffer )
rtcp_t *p_rtcp = (rtcp_t *) p_this;
rtcp_client_t *p_client = NULL;
char psz_name[4];
char* psz_data = NULL;
uint32_t u_ssrc = 0;
uint32_t i_pos = 0;
uint32_t i = 0;
int result = 0;
if( !p_pkt )
return VLC_EGENERIC;
msg_Dbg( p_this, "decoding record: APP" );
u_ssrc = bs_read( p_rtcp->bs, 32 );
result = p_rtcp->pf_find_client( p_this, u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
result = p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
return VLC_ENOMEM;
}
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
for( i = 0 ; i < 4; i++ )
{
psz_name[i] = bs_read( p_rtcp->bs, 8 );
}
psz_name[4] = '\0';
p_pkt->u_payload_type = RTCP_APP;
p_pkt->report.app.psz_prefix = strdup( psz_name );
p_pkt->report.app.u_prefix_len = 4;
p_pkt->u_length -= 4;
psz_data = (char *) malloc( p_pkt->u_length );
if( !psz_data ) {
vlc_mutex_unlock( &p_rtcp->object_lock );
return VLC_EGENERIC;
}
for( i = 0; i < p_pkt->u_length; i-- )
{
psz_data[i] = bs_read( p_rtcp->bs, 8 );
}
psz_data[p_pkt->u_length] = '\0';
p_pkt->report.app.psz_data = strdup( psz_data );
p_pkt->report.app.u_length = p_pkt->u_length;
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
/* Just ignore this packet */
return VLC_SUCCESS;
}
......@@ -186,47 +610,90 @@ static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buf
/* 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 )
int rtcp_pkt_decode( vlc_object_t *p_this, rtcp_pkt_t *p_pkt, block_t *p_block )
{
uint8_t *p_buffer = NULL;
unsigned int i_length = 0;
unsigned int i;
rtcp_t *p_rtcp = (rtcp_t *) p_this;
if( !p_rtcp && !p_block )
if( !p_pkt && !p_block )
return VLC_EGENERIC;
i_length = p_block->i_buffer;
p_buffer = p_block->p_buffer;
bs_init( p_rtcp->bs, p_block->p_buffer, p_block->i_buffer );
p_pkt->u_version = bs_read( p_rtcp->bs, 2 );
p_pkt->b_padding = bs_read( p_rtcp->bs, 1 ) ? VLC_TRUE : VLC_FALSE;
p_pkt->u_report = bs_read( p_rtcp->bs, 5 );
p_pkt->u_payload_type = bs_read( p_rtcp->bs, 8 );
p_pkt->u_length = bs_read( p_rtcp->bs, 16 );
for( i=0; i<i_length; ++i )
if( p_pkt->u_payload_type != RTCP_SDES )
p_pkt->u_ssrc = bs_read( p_rtcp->bs, 32 );
msg_Dbg( p_this, "New RTCP packet: version %d, padding %s, count %d, "
"type %d, length %d, SSRC %d",
p_pkt->u_version,
p_pkt->b_padding ? "true" : "false",
p_pkt->u_report,
p_pkt->u_payload_type,
p_pkt->u_length,
p_pkt->u_ssrc );
while( !bs_eof( p_rtcp->bs ) )
{
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 );
uint32_t i_pos = 0;
switch( p_rtcp->u_payload_type )
switch( p_pkt->u_payload_type )
{
case RTCP_SR:
rtcp_decode_SR( p_this, p_rtcp, p_buffer );
if( p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
rtcp_decode_SR( p_this, p_pkt );
break;
case RTCP_RR:
rtcp_decode_RR( p_this, p_rtcp, p_buffer );
if( p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
rtcp_decode_RR( p_this, p_pkt );
break;
case RTCP_SDES:
rtcp_decode_SDES( p_this, p_rtcp, p_buffer );
if( p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
rtcp_decode_SDES( p_this, p_pkt );
break;
case RTCP_BYE:
rtcp_decode_BYE( p_this, p_rtcp, p_buffer );
rtcp_decode_BYE( p_this, p_pkt );
#if 0
if( p_rtcp->pf_find_sender( p_this, pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_del_sender( p_this, p_pkt->u_ssrc );
#endif
if( p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_del_client( p_this, p_pkt->u_ssrc );
if( p_rtcp->u_active < p_rtcp->u_members )
{
rtcp_event_t event = EVENT_BYE;
p_rtcp->i_next_date = p_rtcp->i_date +
(mtime_t) ( (p_rtcp->u_active / p_rtcp->u_members) *
(p_rtcp->i_next_date - p_rtcp->i_date) );
p_rtcp->i_last_date = p_rtcp->i_date -
(mtime_t)
( (mtime_t)(p_rtcp->u_active / p_rtcp->u_members) *
(p_rtcp->i_date - p_rtcp->i_last_date) );
/* schedule for next period */
rtcp_schedule( VLC_OBJECT(p_rtcp), p_rtcp->i_next_date, event );
p_rtcp->u_members = p_rtcp->u_active;
}
else p_rtcp->u_members++;
break;
case RTCP_APP:
rtcp_decode_APP( p_this, p_rtcp, p_buffer );
if( p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos ) == VLC_EGENERIC )
p_rtcp->pf_add_client( p_this, p_pkt->u_ssrc, &i_pos );
rtcp_decode_APP( p_this, p_pkt );
break;
default:
return VLC_EGENERIC;
}
......@@ -237,167 +704,328 @@ int rtcp_decode( vlc_object_t *p_this, rtcp_t *p_rtcp, block_t *p_block )
/*
* Create RTCP records for reporting to server.
*/
block_t *rtcp_encode( vlc_object_t *p_this, int type )
rtcp_pkt_t *rtcp_pkt_new( vlc_object_t *p_this, int type )
{
rtcp_t *p_rtcp = NULL;
block_t *p_block = NULL;
rtcp_pkt_t *p_pkt = NULL;
p_rtcp = (rtcp_t *) malloc( sizeof( rtcp_t ) );
if( !p_rtcp )
p_pkt = (rtcp_pkt_t *) malloc( sizeof( rtcp_pkt_t ) );
if( !p_pkt )
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;
memset( p_pkt, 0 , sizeof( rtcp_pkt_t ) );
p_pkt->u_version = 2;
p_pkt->u_payload_type = type;
p_pkt->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_SR:
p_pkt->u_length += sizeof(rtcp_SR_t);
break;
case RTCP_RR:
p_pkt->u_length += sizeof(rtcp_RR_t);
break;
case RTCP_SDES:
p_rtcp->u_length += sizeof(rtcp_SDES) + strlen(p_rtcp->report.sdes.p_data);
p_pkt->u_length += sizeof(rtcp_SDES_t);
if( p_pkt->report.sdes.pp_items )
p_pkt->u_length += p_pkt->report.sdes.u_items;
break;
case RTCP_BYE:
p_pkt->u_length += sizeof(rtcp_BYE_t);
break;
case RTCP_BYE: p_rtcp->u_length += sizeof(rtcp_BYE); break;
case RTCP_APP: /* ignore: p_rtcp->u_length += sizeof(rtcp_APP); */ break;
case RTCP_APP:
p_pkt->u_length += sizeof(rtcp_APP_t);
break;
default:
free(p_pkt);
return NULL;
}
return p_pkt;
}
/* FIXME: Maybe this should be a buffer pool instead */
p_block = block_New( p_this, p_rtcp->u_length );
return p_block;
void rtcp_pkt_del( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
if( !p_pkt )
return;
switch( p_pkt->u_payload_type )
{
case RTCP_SR:
case RTCP_RR:
break;
case RTCP_SDES:
if( p_pkt->report.sdes.pp_items )
{
uint32_t i = 0;
for( i = 0; i < p_pkt->report.sdes.u_items; i++ )
{
rtcp_SDES_item_t *p_old =
p_pkt->report.sdes.pp_items[i];
REMOVE_ELEM( p_pkt->report.sdes.pp_items,
p_pkt->report.sdes.u_items, i );
p_pkt->report.sdes.u_items--;
if( p_old->psz_data )
free( p_old->psz_data );
free( p_old );
}
}
break;
case RTCP_BYE:
break;
case RTCP_APP:
if( p_pkt->report.app.psz_prefix )
free( p_pkt->report.app.psz_prefix );
if( p_pkt->report.app.psz_data )
free( p_pkt->report.app.psz_data );
break;
default:
msg_Err( p_this, "unknown RTCP packet type %d: "
"possible leaking of memory.",
p_pkt->u_payload_type );
break;
}
free( p_pkt );
}
static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp )
block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
mtime_t ntp_time;
bs_t bits, *s = &bits;
block_t *p_block = NULL;
rtcp_stats_t *p_stats = NULL;
rtcp_client_t *p_client = NULL;
uint32_t i_pos = 0;
int result = 0;
if( p_pkt->u_payload_type != RTCP_SR )
return NULL;
/* FIXME: Maybe this should be a buffer pool instead */
p_block = block_New( p_this, p_rtcp->u_length );
p_block = block_New( p_this, p_pkt->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, 2, p_pkt->u_version );
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 ) );
bs_write( s, 5, p_pkt->u_report );
bs_write( s, 8, p_pkt->u_payload_type );
bs_write( s, 16, p_pkt->u_length );
bs_write( s, 32, p_pkt->u_ssrc );
/* sender info */
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 */
bs_write( s, 32, ((unsigned int)(ntp_time>>32)) ); /* ntp_timestampH */
bs_write( s, 32, ((unsigned int)ntp_time) );/* ntp_timestampL */
/* FIXME: Make sure to generate a good RTP server timestamp.
p_rtcp->report.sr.rtp_timestamp = htonl(
p_pkt->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 ) );
bs_write( s, 32, p_pkt->report.sr.rtp_timestamp );
bs_write( s, 32, p_pkt->report.sr.u_pkt_count );
bs_write( s, 32, p_pkt->report.sr.u_octet_count );
/* report block */
result = p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
msg_Err( p_this, "SR: SSRC identifier doesn't exists", p_pkt->u_ssrc );
free( p_block );
return NULL;
}
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
p_stats = p_client->p_stats;
if( !p_stats ) {
msg_Err( p_this, "SR: SSRC identifier doesn't exists", p_pkt->u_ssrc );
free( p_block );
return NULL;
}
bs_write( s, 32, p_stats->l_dest_SSRC );
bs_write( s, 8, p_stats->u_fraction_lost );
bs_write( s, 24, p_stats->u_pkt_lost );
bs_write( s, 32, p_stats->u_highest_seq_no );
bs_write( s, 32, p_stats->u_jitter );
bs_write( s, 32, p_stats->u_last_SR );
bs_write( s, 32, p_stats->u_delay_since_last_SR );
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
/* possible SR extension */
return p_block;
}
static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp )
block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
rtcp_t *p_rtcp = (rtcp_t *) p_this;
bs_t bits, *s = &bits;
block_t *p_block = NULL;
rtcp_stats_t *p_stats = NULL;
rtcp_client_t *p_client = NULL;
uint32_t i_pos = 0;
int result = 0;
if( p_pkt->u_payload_type != RTCP_RR )
return NULL;
/* FIXME: Maybe this should be a buffer pool instead */
p_block = block_New( p_this, p_rtcp->u_length );
p_block = block_New( p_this, p_pkt->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, 2, p_pkt->u_version );
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 );
bs_write( s, 5, p_pkt->u_report );
bs_write( s, 8, p_pkt->u_payload_type );
bs_write( s, 16, p_pkt->u_length );
bs_write( s, 32, p_pkt->u_ssrc );
/* report block */
result = p_rtcp->pf_find_client( p_this, p_pkt->u_ssrc, &i_pos );
if( result == VLC_EGENERIC )
{
msg_Err( p_this, "RR: SSRC identifier doesn't exists", p_pkt->u_ssrc );
free( p_block );
return NULL;
}
/* fill in record */
bs_write( s, 32, htonl( p_rtcp->report.rr.u_ssrc ) );
vlc_mutex_lock( &p_rtcp->object_lock );
p_client = p_rtcp->pp_clients[i_pos];
p_stats = p_client->p_stats;
if( !p_stats ) {
msg_Err( p_this, "RR: SSRC identifier doesn't exists", p_pkt->u_ssrc );
free( p_block );
return NULL;
}
bs_write( s, 32, p_stats->l_dest_SSRC );
bs_write( s, 8, p_stats->u_fraction_lost );
bs_write( s, 24, p_stats->u_pkt_lost );
bs_write( s, 32, p_stats->u_highest_seq_no );
bs_write( s, 32, p_stats->u_jitter );
bs_write( s, 32, p_stats->u_last_RR );
bs_write( s, 32, p_stats->u_delay_since_last_RR );
p_client = NULL;
vlc_mutex_unlock( &p_rtcp->object_lock );
/* possible RR extension */
return p_block;
}
static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp )
block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_pkt_t *p_pkt )
{
bs_t bits, *s = &bits;
block_t *p_block = NULL;
char *p_hostname = strdup("hostname");
int i_length;
int i;
uint32_t i_chunks;
if( p_pkt->u_payload_type != RTCP_SDES )
return NULL;
/* FIXME: Maybe this should be a buffer pool instead */
p_block = block_New( p_this, p_rtcp->u_length );
p_block = block_New( p_this, p_pkt->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, 2, p_pkt->u_version );
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 );
bs_write( s, 5, p_pkt->u_report ); /* Number of SSRC/CSRC chunks */
bs_write( s, 8, p_pkt->u_payload_type );
bs_write( s, 16, p_pkt->u_length );
bs_write( s, 32, p_pkt->u_ssrc );
/* 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 ) );
for( i_chunks = 0; i_chunks < p_pkt->u_report; i_chunks++ )
{
uint32_t i_item;
i_length = strlen(p_hostname);
bs_write( s, 8, i_length );
for( i=0; i<i_length; i++ )
for( i_item = 0 ; i_item < p_pkt->report.sdes.u_items; i_item++ )
{
bs_write( s, 8, p_hostname[i] );
uint32_t i_count = strlen( p_pkt->report.sdes.pp_items[i_item]->psz_data );
uint8_t u_octet = i_count / 8; /* Octect count ??*/
rtcp_SDES_item_t *p_item = p_pkt->report.sdes.pp_items[i_item];
uint32_t i_pos, i_pad, i_padding;
bs_write( s, 8, p_item->u_type );
bs_write( s, 8, u_octet );
for( i_pos = 0; i_pos < i_count; i_pos++ )
{
/* FIXME: must be UTF 8 encoded */
bs_write( s, 8, p_item->psz_data[i_pos] );
}
/* do we need padding to 32 bit boundary? */
i_padding = 0;
if( ((i_count + 2) % 4) != 0 )
i_padding = (i_count + 2) - (((i_count + 2) % 4) << 2);
for( i_pad = 0; i_pad < i_padding; i_pad++ )
{
bs_write( s, 8, 0 );
}
}
}
free(p_hostname);
return p_block;
}
static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp )
block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_pkt_t *p_pkt, char *psz_reason )
{
bs_t bits, *s = &bits;
block_t *p_block = NULL;
char *p_reason = strdup( "Stream ended." );
int i_length;
int i;
uint32_t i_count = strlen( psz_reason );
uint8_t u_octet = i_count / 8; /* Octect count ??*/
uint32_t i_pos, i_pad, i_padding;
if( p_pkt->u_payload_type != RTCP_BYE )
return NULL;
/* FIXME: Maybe this should be a buffer pool instead */
p_block = block_New( p_this, p_rtcp->u_length );
p_block = block_New( p_this, p_pkt->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, 2, p_pkt->u_version );
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 );
bs_write( s, 5, p_pkt->u_report ); /* Number of SSRC/CSRC chunks */
bs_write( s, 8, p_pkt->u_payload_type );
bs_write( s, 16, p_pkt->u_length );
bs_write( s, 32, p_pkt->u_ssrc );
/* fill in record */
bs_write( s, 32, htonl( p_rtcp->report.sdes.u_ssrc ) );
/* Give reason for leaving */
//FIXME: bs_write( s, 8, p_item->u_type );
bs_write( s, 8, u_octet );
for( i_pos = 0; i_pos < i_count; i_pos++ )
{
/* FIXME: must be UTF 8 encoded */
bs_write( s, 8, psz_reason[i_pos] );
}
i_length = strlen(p_reason);
bs_write( s, 8, i_length );
for( i=0; i<i_length; i++ )
/* do we need padding to 32 bit boundary? */
i_padding = 0;
if( ((i_count + 2) % 4) != 0 )
i_padding = (i_count + 2) - (((i_count + 2) % 4) << 2);
for( i_pad = 0; i_pad < i_padding; i_pad++ )
{
bs_write( s, 8, p_reason[i] );
bs_write( s, 8, 0 );
}
free(p_reason);
return p_block;
}
......@@ -33,115 +33,243 @@
#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 */
/* SDES type */
#define RTCP_SDES_CNAME 1
#define RTCP_SDES_NAME 2
#define RTCP_SDES_EMAIL 3
#define RTCP_SDES_PHONE 4
#define RTCP_SDES_LOC 5
#define RTCP_SDES_TOOL 6
#define RTCP_SDES_NOTE 7
#define RTCP_SDES_PRIV 8
/* End of SDES type */
#define RTCP_HEADER_LEN 3
typedef struct
typedef enum rtcp_event_enum
{
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
EVENT_BYE,
EVENT_REPORT
} rtcp_event_t;
typedef struct
{
unsigned int u_ssrc;
} rtcp_RR;
uint32_t ntp_timestampH;
uint32_t ntp_timestampL;
uint32_t rtp_timestamp;
uint32_t u_pkt_count;
uint32_t u_octet_count;
} rtcp_SR_t;
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;
} rtcp_RR_t;
typedef struct SDES_item_t
{
uint32_t i_index; /*< index */
uint8_t u_type; /*< type field */
char *psz_data; /*< null terminated string */
} rtcp_SDES_item_t;
typedef struct
{
unsigned int u_ssrc;
unsigned char u_attr_name;
unsigned char u_length;
char *p_data;
} rtcp_SDES;
uint32_t u_length; /*< length of packet */
uint32_t u_items; /*< number of SDES_items */
rtcp_SDES_item_t **pp_items; /*< list of SDES_items */
} rtcp_SDES_t;
typedef struct
{
unsigned int u_ssrc;
unsigned char u_length;
} rtcp_BYE;
uint32_t u_length; /*< length of packet */
} rtcp_BYE_t;
typedef struct
{
unsigned char u_length;
char *p_data;
} rtcp_APP;
uint32_t u_length; /*< length of packet */
uint32_t u_prefix_len; /*< length of prefix data */
unsigned char *psz_prefix;/*< prefix string (null terminated) */
unsigned char *psz_data; /*< data string (null terminated) */
} rtcp_APP_t;
/**
* 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 */
uint32_t u_RR_received; /*< RR records received */
uint32_t u_SR_received; /*< SR records received */
uint64_t l_dest_SSRC; /*< SSRC of first source */
uint32_t u_pkt_count; /*< count of packets received */
uint32_t u_octet_count; /*< ? */
uint32_t u_pkt_lost; /*< cumulative count of packets lost */
uint8_t u_fraction_lost; /*< count of fractional packets lost */
uint32_t u_highest_seq_no;/*< highest sequence number found */
uint32_t u_jitter; /*< inter arrival jitter calculated */
uint32_t u_last_SR; /*< last SR record received */
uint32_t 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 */
uint64_t u_avg_pkt_size; /*< average RTCP packet size */
uint64_t u_sent_pkt_size; /*< RTCP packet size sent */
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 */
} rtcp_stats_t;
typedef struct
{
uint32_t u_version; /*< RTCP version number */
vlc_bool_t b_padding; /*< indicates if packets has padding */
uint32_t u_report; /*< reception packet count */
uint32_t u_payload_type; /*< type of RTCP payload */
uint32_t u_length; /*< length of packet */
uint32_t u_ssrc; /*< channel name this packet belongs to */
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 */
rtcp_SR_t sr; /*< SR record */
rtcp_RR_t rr; /*< RR record */
rtcp_SDES_t sdes; /*< SDES record */
rtcp_BYE_t bye; /*< BYE record */
rtcp_APP_t 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_pkt_t;
typedef struct rtcp_client_t
{
uint32_t i_index;
uint32_t u_ssrc; /*< channel name */
vlc_bool_t b_deleted; /*< channel deleted ? */
mtime_t i_timeout; /*< remove timeout before real deletion,
* this is recommended by RFC 3550 at
* page 27 to ignore out-of-order packets.
*/
rtcp_stats_t *p_stats; /*< RTCP statistics */
uint32_t i_items; /*< count of SDES item structures */
rtcp_SDES_item_t **pp_sdes; /*< SDES client items */
} rtcp_client_t;
/**
* structure rtcp_t
* This structure is a VLC_OBJECT and holds RTCP statistical information.
*/
typedef struct rtcp_t
{
VLC_COMMON_MEMBERS
int fd; /*< socket descriptor of rtcp stream */
uint32_t u_clients; /*< number of clients connected */
uint32_t u_active; /*< number of active senders */
uint32_t u_members; /*< number of clients in previous interval */
mtime_t i_date; /*< current RTCP packet interval */
mtime_t i_last_date; /*< previous RTCP packet interval */
mtime_t i_next_date; /*< next scheduled transmision time
of RTCP packet */
uint32_t i_clients; /*< count of clients structures */
rtcp_client_t **pp_clients; /*< RTCP clients */
/* bitstream data pointer used for decoding */
bs_t *bs; /*< bitstream decoding data pointer */
int (*pf_add_client)( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos );
int (*pf_del_client)( vlc_object_t *p_this, uint32_t u_ssrc );
int (*pf_find_client)( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos );
} rtcp_t;
int rtcp_add_client( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos );
int rtcp_del_client( vlc_object_t *p_this, uint32_t u_ssrc );
/* Should be called with vlc_mutex_lock( &p_this->objec_lock ) held */
int rtcp_find_client( vlc_object_t *p_this, uint32_t u_ssrc, uint32_t *i_pos );
/**
* rtcp_cleanup_clients - Permanently remove clients from the list
* Permanently delete struct rtcp_client_t from member list when it is there
* time to be removed. RFC 3550 recommends a grace period of five times the
* RTCP packet send/receive interval before permanent removal of session. This
* is to ignore out of order packets for the same SSRC that arrive after the
* BYE report for that SSRC has been received.
* Arguments:
* \param p_this VLC_OBJECT_T of type rtcp_t
*/
int rtcp_cleanup_clients( vlc_object_t *p_this );
//VLC_EXPORT( int, rtcp_cleanup_clients, ( vlc_object_t * ) );
/**
* Decode RTCP packet
* rtcp_pkt_decode - Decode RTCP packet
* Decode incoming RTCP packet and inspect the records types.
* Arguments:
* \param p_this
* \param p_pkt
* \param p_block
*/
int rtcp_pkt_decode( vlc_object_t *p_this, rtcp_pkt_t *p_pkt, block_t *p_block );
//VLC_EXPORT( int, rtcp_decode, ( rtcp_pkt_t *, block_t * ) );
/**
* rtcp_pkt_new - Encode RTCP packet
* Create a new RTCP packet of type 'type'
* Arguments
* \param type type of RTCP packet @see
*/
rtcp_pkt_t *rtcp_pkt_new( vlc_object_t *p_this, int type );
//VLC_EXPORT( block_t* , rtcp_encode, ( vlc_object_t *, int ) );
void rtcp_pkt_del( vlc_object_t *p_this, rtcp_pkt_t *pkt );
block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_pkt_t *p_pkt );
block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_pkt_t *p_pkt, char *psz_reason );
/**
* rtcp_interval
* Calculate the interval at which RTCP compound packets are going to be
* sent or received.
* Arguments:
* \param p_this VLC_OBJECT of type rtcp_t
* \param u_bandwith bandwidth of RTP connection
* \param b_sender are we the sender or the receiver
* \param b_first the first time this function is called use only half
* of the initial waiting time
*/
uint64_t rtcp_interval( vlc_object_t *p_this, uint64_t u_bandwidth,
vlc_bool_t b_sender, vlc_bool_t b_first );
/**
* rtcp_expire
* Decides to sent an RTCP report or a BYE record
* \param p_this VLC_OBJECT of type rtcp_t
* \param u_bandwith bandwidth of RTP connection
* \param rtcp_event type of event received
* \param b_sender are we the sender or the receiver
* \param *b_first the first time this function is called use only half
* of the initial waiting time. If b_first is VLC_TRUE, then
* it will return *b_first = VLC_FALSE;
*/
void rtcp_expire( vlc_object_t *p_this, rtcp_event_t rtcp_event,
uint64_t u_bandwidth, vlc_bool_t b_sender, vlc_bool_t *b_first );
/**
* rtcp_received
* Determine what to do on the received Sender Report, decode it
* or leave the channel (BYE record).
* \param p_this VLC_OBJECT of type rtcp_t
* \param p_pkt RTCP packet that was received
* \param rtcp_event type of event received
*/
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 );
void rtcp_received( vlc_object_t *p_this, rtcp_pkt_t *pkt,
rtcp_event_t rtcp_event );
#endif /* RTCP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment