1 /*****************************************************************************
2 * rtcp.c: RTP/RTCP source file
3 *****************************************************************************
4 * Copyright (C) 2005 M2X
8 * Authors: Jean-Paul Saman <jpsaman #_at_# videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 #include <netinet/in.h>
31 #include <vlc_block.h>
36 static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_block );
37 static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
38 static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
39 static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
40 static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
41 static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer );
43 static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp );
44 static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp );
45 static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp );
46 static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp );
48 static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
50 unsigned int u_ssrc_count;
53 if( !p_rtcp && !p_buffer )
56 msg_Dbg( p_this, "decoding record: SR" );
57 p_rtcp->stats.u_SR_received++;
58 p_rtcp->stats.u_pkt_count = p_buffer[20+RTCP_HEADER_LEN];
59 p_rtcp->stats.u_octet_count = p_buffer[24+RTCP_HEADER_LEN];
60 u_ssrc_count = p_buffer[RTCP_HEADER_LEN] & 0x1f;
61 msg_Dbg( p_this, "SR received %d, packet count %d, octect count %d, SSRC count %d",
62 p_rtcp->stats.u_SR_received,
63 p_rtcp->stats.u_pkt_count,
64 p_rtcp->stats.u_octet_count,
67 for( i=0; i < u_ssrc_count; i++ )
69 unsigned char count[4];
71 p_rtcp->stats.u_fract_lost = p_buffer[32+RTCP_HEADER_LEN];
74 count[1] = p_buffer[33+RTCP_HEADER_LEN];
75 count[2] = p_buffer[34+RTCP_HEADER_LEN];
76 count[3] = p_buffer[35+RTCP_HEADER_LEN];
78 /* FIXME: I don't like the sight of this */
79 p_rtcp->stats.u_pkt_lost = ntohl((int)count);
81 p_rtcp->stats.u_highest_seq_no = ntohl( p_buffer[36+RTCP_HEADER_LEN] );
82 p_rtcp->stats.u_jitter = ntohl( p_buffer[40+RTCP_HEADER_LEN] );
83 p_rtcp->stats.u_last_SR = ntohl( p_buffer[44+RTCP_HEADER_LEN] );
84 p_rtcp->stats.u_delay_since_last_SR = (mtime_t) ntohl( p_buffer[48+RTCP_HEADER_LEN] );
86 msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, jitter %d, last SR %d, delay %lld",
87 p_rtcp->stats.u_fract_lost,
88 p_rtcp->stats.u_pkt_lost,
89 p_rtcp->stats.u_highest_seq_no,
90 p_rtcp->stats.u_jitter,
91 p_rtcp->stats.u_last_SR,
92 p_rtcp->stats.u_delay_since_last_SR );
97 static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
99 unsigned int u_ssrc_count;
102 if( !p_rtcp && !p_buffer )
105 msg_Dbg( p_this, "decoding record: RR" );
107 p_rtcp->stats.u_RR_received++;
108 u_ssrc_count = (p_buffer[RTCP_HEADER_LEN] & 0x1f);
109 msg_Dbg( p_this, "RR received %d, SSRC count %d", p_rtcp->stats.u_RR_received, u_ssrc_count );
111 for( i=0; i < u_ssrc_count; i++ )
113 unsigned char count[4];
115 p_rtcp->stats.u_fract_lost = p_buffer[12+RTCP_HEADER_LEN];
118 count[1] = p_buffer[13+RTCP_HEADER_LEN];
119 count[2] = p_buffer[14+RTCP_HEADER_LEN];
120 count[3] = p_buffer[15+RTCP_HEADER_LEN];
122 /* FIXME: I don't like the sight of this */
123 p_rtcp->stats.u_pkt_lost = ntohl((int)count);
125 p_rtcp->stats.u_highest_seq_no = ntohl( p_buffer[16+RTCP_HEADER_LEN] );
126 p_rtcp->stats.u_jitter = ntohl( p_buffer[20+RTCP_HEADER_LEN] );
127 p_rtcp->stats.u_last_RR = ntohl( p_buffer[24+RTCP_HEADER_LEN] );
128 p_rtcp->stats.u_delay_since_last_RR = (mtime_t) ntohl( p_buffer[28+RTCP_HEADER_LEN] );
130 msg_Dbg( p_this, "fract lost %d, packet lost %d, highest seqno %d, jitter %d, last RR %d, delay %lld",
131 p_rtcp->stats.u_fract_lost,
132 p_rtcp->stats.u_pkt_lost,
133 p_rtcp->stats.u_highest_seq_no,
134 p_rtcp->stats.u_jitter,
135 p_rtcp->stats.u_last_RR,
136 p_rtcp->stats.u_delay_since_last_RR );
141 static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
143 if( !p_rtcp && !p_buffer )
146 msg_Dbg( p_this, "decoding record: SDES" );
148 switch( p_buffer[8] )
150 case RTCP_INFO_CNAME:
151 p_rtcp->stats.l_dest_SSRC = ntohs( (int)(p_buffer[4+RTCP_HEADER_LEN]) );
154 case RTCP_INFO_EMAIL:
155 case RTCP_INFO_PHONE:
159 case RTCP_INFO_PRIV: /* ignoring these */
167 static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
169 if( !p_rtcp && !p_buffer )
172 msg_Dbg( p_this, "decoding record: BYE" );
176 static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
178 if( !p_rtcp && !p_buffer )
181 msg_Dbg( p_this, "decoding record: APP" );
182 /* Just ignore this packet */
186 /* Decode RTCP packet
187 * Decode incoming RTCP packet and inspect the records types.
189 int rtcp_decode( vlc_object_t *p_this, rtcp_t *p_rtcp, block_t *p_block )
191 uint8_t *p_buffer = NULL;
192 unsigned int i_length = 0;
195 if( !p_rtcp && !p_block )
198 i_length = p_block->i_buffer;
199 p_buffer = p_block->p_buffer;
201 for( i=0; i<i_length; ++i )
203 p_rtcp->u_count = p_buffer[i] & 0xF8;
204 p_rtcp->u_version = p_buffer[i] & 0x03;
205 p_rtcp->u_payload_type = p_buffer[i+1];
206 p_rtcp->u_length = (p_buffer[i+2]<<8) + p_buffer[i+3];
207 msg_Dbg( p_this, "New RTCP packet: count %d, version %d, type %d, lenght %d",
210 p_rtcp->u_payload_type,
213 switch( p_rtcp->u_payload_type )
216 rtcp_decode_SR( p_this, p_rtcp, p_buffer );
219 rtcp_decode_RR( p_this, p_rtcp, p_buffer );
222 rtcp_decode_SDES( p_this, p_rtcp, p_buffer );
225 rtcp_decode_BYE( p_this, p_rtcp, p_buffer );
228 rtcp_decode_APP( p_this, p_rtcp, p_buffer );
238 * Create RTCP records for reporting to server.
240 block_t *rtcp_encode( vlc_object_t *p_this, int type )
242 rtcp_t *p_rtcp = NULL;
243 block_t *p_block = NULL;
245 p_rtcp = (rtcp_t *) malloc( sizeof( rtcp_t ) );
248 memset( p_rtcp, 0 , sizeof( rtcp_t ) );
249 p_rtcp->u_version = 2;
250 p_rtcp->u_payload_type = type;
251 p_rtcp->u_length = RTCP_HEADER_LEN;
255 case RTCP_SR: p_rtcp->u_length += sizeof(rtcp_SR); break;
256 case RTCP_RR: p_rtcp->u_length += sizeof(rtcp_RR); break;
258 p_rtcp->u_length += sizeof(rtcp_SDES) + strlen(p_rtcp->report.sdes.p_data);
260 case RTCP_BYE: p_rtcp->u_length += sizeof(rtcp_BYE); break;
261 case RTCP_APP: /* ignore: p_rtcp->u_length += sizeof(rtcp_APP); */ break;
264 /* FIXME: Maybe this should be a buffer pool instead */
265 p_block = block_New( p_this, p_rtcp->u_length );
269 static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp )
272 bs_t bits, *s = &bits;
273 block_t *p_block = NULL;
275 /* FIXME: Maybe this should be a buffer pool instead */
276 p_block = block_New( p_this, p_rtcp->u_length );
280 bs_init( s, p_block->p_buffer, p_block->i_buffer );
283 bs_write( s, 5, p_rtcp->u_count );
284 bs_write( s, 1, 0 ); /* padding */
285 bs_write( s, 2, p_rtcp->u_version );
286 bs_write( s, 8, p_rtcp->u_payload_type );
287 bs_write( s, 16, p_rtcp->u_length );
290 bs_write( s, 32, htonl( p_rtcp->report.sr.u_ssrc ) );
293 bs_write( s, 32, htonl( ((unsigned int)(ntp_time>>32)) ) ); /* ntp_timestampH */
294 bs_write( s, 32, htonl( ((unsigned int)ntp_time)) );/* ntp_timestampL */
296 /* FIXME: Make sure to generate a good RTP server timestamp.
297 p_rtcp->report.sr.rtp_timestamp = htonl(
298 (unsigned int) ((double)ntp_time.tv_sec +
299 (double)ntp_time.tv_usec/1000000.) * p_mux->rate
300 + session->start_rtptime ); */
301 bs_write( s, 32, htonl( p_rtcp->report.sr.rtp_timestamp ) );
302 bs_write( s, 32, htonl( p_rtcp->report.sr.u_pkt_count ) );
303 bs_write( s, 32, htonl( p_rtcp->report.sr.u_octet_count ) );
308 static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp )
310 bs_t bits, *s = &bits;
311 block_t *p_block = NULL;
313 /* FIXME: Maybe this should be a buffer pool instead */
314 p_block = block_New( p_this, p_rtcp->u_length );
318 bs_init( s, p_block->p_buffer, p_block->i_buffer );
321 bs_write( s, 5, p_rtcp->u_count );
322 bs_write( s, 1, 0 ); /* padding */
323 bs_write( s, 2, p_rtcp->u_version );
324 bs_write( s, 8, p_rtcp->u_payload_type );
325 bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
328 bs_write( s, 32, htonl( p_rtcp->report.rr.u_ssrc ) );
333 static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp )
335 bs_t bits, *s = &bits;
336 block_t *p_block = NULL;
337 char *p_hostname = strdup("hostname");
341 /* FIXME: Maybe this should be a buffer pool instead */
342 p_block = block_New( p_this, p_rtcp->u_length );
346 bs_init( s, p_block->p_buffer, p_block->i_buffer );
349 bs_write( s, 5, p_rtcp->u_count );
350 bs_write( s, 1, 0 ); /* padding */
351 bs_write( s, 2, p_rtcp->u_version );
352 bs_write( s, 8, p_rtcp->u_payload_type );
353 bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
356 bs_write( s, 32,htonl( p_rtcp->report.sdes.u_ssrc ) );
357 bs_write( s, 8, htonl( p_rtcp->report.sdes.u_attr_name ) );
358 bs_write( s, 8, htonl( p_rtcp->report.sdes.u_length ) );
360 i_length = strlen(p_hostname);
361 bs_write( s, 8, i_length );
362 for( i=0; i<i_length; i++ )
364 bs_write( s, 8, p_hostname[i] );
370 static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp )
372 bs_t bits, *s = &bits;
373 block_t *p_block = NULL;
374 char *p_reason = strdup( "Stream ended." );
378 /* FIXME: Maybe this should be a buffer pool instead */
379 p_block = block_New( p_this, p_rtcp->u_length );
383 bs_init( s, p_block->p_buffer, p_block->i_buffer );
386 bs_write( s, 5, p_rtcp->u_count );
387 bs_write( s, 1, 0 ); /* padding */
388 bs_write( s, 2, p_rtcp->u_version );
389 bs_write( s, 8, p_rtcp->u_payload_type );
390 bs_write( s, 16, (p_rtcp->u_length >> 2) -1 );
393 bs_write( s, 32, htonl( p_rtcp->report.sdes.u_ssrc ) );
395 i_length = strlen(p_reason);
396 bs_write( s, 8, i_length );
397 for( i=0; i<i_length; i++ )
399 bs_write( s, 8, p_reason[i] );