]> git.sesse.net Git - vlc/blob - modules/mux/rtp/rtcp.c
Structures and functions for RTCP support. BIG FAT WARNING >>>> This code is untested...
[vlc] / modules / mux / rtp / rtcp.c
1 /*****************************************************************************
2  * rtcp.c: RTP/RTCP source file
3  *****************************************************************************
4  * Copyright (C) 2005 M2X
5  *
6  * $Id$
7  *
8  * Authors: Jean-Paul Saman <jpsaman #_at_# videolan dot org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 #include <netinet/in.h>
26 #include <sys/time.h>
27 #include <sys/time.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc_bits.h>
31 #include <vlc_block.h>
32
33 #include "rtp.h"
34 #include "rtcp.h"
35
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 );
42
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 );
47
48 static int rtcp_decode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
49 {
50     unsigned int u_ssrc_count;
51     unsigned int i = 0;
52
53     if( !p_rtcp && !p_buffer )
54         return VLC_EGENERIC;
55
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,
65         u_ssrc_count );
66
67     for( i=0; i < u_ssrc_count; i++ )
68     {
69         unsigned char count[4];
70
71         p_rtcp->stats.u_fract_lost = p_buffer[32+RTCP_HEADER_LEN];
72
73         count[0] = 0;
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];
77
78         /* FIXME: I don't like the sight of this */
79         p_rtcp->stats.u_pkt_lost = ntohl((int)count);
80
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] );
85
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 );
93     }
94     return VLC_SUCCESS;
95 }
96
97 static int rtcp_decode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
98 {
99     unsigned int u_ssrc_count;
100     unsigned int i = 0;
101
102     if( !p_rtcp && !p_buffer )
103         return VLC_EGENERIC;
104
105     msg_Dbg( p_this, "decoding record: RR" );
106
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 );
110
111     for( i=0; i < u_ssrc_count; i++ )
112     {
113         unsigned char count[4];
114
115         p_rtcp->stats.u_fract_lost = p_buffer[12+RTCP_HEADER_LEN];
116
117         count[0] = 0;
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];
121
122         /* FIXME: I don't like the sight of this */
123         p_rtcp->stats.u_pkt_lost = ntohl((int)count);
124
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] );
129
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 );
137     }
138     return VLC_SUCCESS;
139 }
140
141 static int rtcp_decode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
142 {
143     if( !p_rtcp && !p_buffer )
144         return VLC_EGENERIC;
145
146     msg_Dbg( p_this, "decoding record: SDES" );
147
148     switch( p_buffer[8] )
149     {
150         case RTCP_INFO_CNAME:
151             p_rtcp->stats.l_dest_SSRC = ntohs( (int)(p_buffer[4+RTCP_HEADER_LEN]) );
152             break;
153         case RTCP_INFO_NAME:
154         case RTCP_INFO_EMAIL:
155         case RTCP_INFO_PHONE:
156         case RTCP_INFO_LOC:
157         case RTCP_INFO_TOOL:
158         case RTCP_INFO_NOTE:
159         case RTCP_INFO_PRIV: /* ignoring these */
160             break;
161         default:
162             return VLC_EGENERIC;
163     }
164     return VLC_SUCCESS;
165 }
166
167 static int rtcp_decode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
168 {
169     if( !p_rtcp && !p_buffer )
170         return VLC_EGENERIC;
171
172     msg_Dbg( p_this, "decoding record: BYE" );
173     return VLC_SUCCESS;
174 }
175
176 static int rtcp_decode_APP( vlc_object_t *p_this, rtcp_t *p_rtcp, uint8_t *p_buffer )
177 {
178     if( !p_rtcp && !p_buffer )
179         return VLC_EGENERIC;
180
181     msg_Dbg( p_this, "decoding record: APP" );
182     /* Just ignore this packet */
183     return VLC_SUCCESS;
184 }
185
186 /* Decode RTCP packet
187  * Decode incoming RTCP packet and inspect the records types.
188  */
189 int rtcp_decode( vlc_object_t *p_this, rtcp_t *p_rtcp, block_t *p_block )
190 {
191     uint8_t *p_buffer = NULL;
192     unsigned int i_length = 0;
193     unsigned int i;
194
195     if( !p_rtcp && !p_block )
196         return VLC_EGENERIC;
197
198     i_length = p_block->i_buffer;
199     p_buffer = p_block->p_buffer;
200
201     for( i=0; i<i_length; ++i )
202     {
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",
208             p_rtcp->u_count,
209             p_rtcp->u_version,
210             p_rtcp->u_payload_type,
211             p_rtcp->u_length );
212
213         switch( p_rtcp->u_payload_type )
214         {
215             case RTCP_SR:
216                 rtcp_decode_SR( p_this, p_rtcp, p_buffer );
217                 break;
218             case RTCP_RR:
219                 rtcp_decode_RR( p_this, p_rtcp, p_buffer );
220                 break;
221             case RTCP_SDES:
222                 rtcp_decode_SDES( p_this, p_rtcp, p_buffer );
223                 break;
224             case RTCP_BYE:
225                 rtcp_decode_BYE( p_this, p_rtcp, p_buffer );
226                 break;
227             case RTCP_APP:
228                 rtcp_decode_APP( p_this, p_rtcp, p_buffer );
229                 break;
230             default:
231                 return VLC_EGENERIC;
232         }
233     }
234     return VLC_SUCCESS;
235 }
236
237 /*
238  * Create RTCP records for reporting to server.
239  */
240 block_t *rtcp_encode( vlc_object_t *p_this, int type )
241 {
242     rtcp_t  *p_rtcp = NULL;
243     block_t *p_block = NULL;
244
245     p_rtcp = (rtcp_t *) malloc( sizeof( rtcp_t ) );
246     if( !p_rtcp )
247         return NULL;
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;
252
253     switch( type )
254     {
255         case RTCP_SR: p_rtcp->u_length += sizeof(rtcp_SR); break;
256         case RTCP_RR: p_rtcp->u_length += sizeof(rtcp_RR); break;
257         case RTCP_SDES:
258             p_rtcp->u_length += sizeof(rtcp_SDES) + strlen(p_rtcp->report.sdes.p_data);
259             break;
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;
262     }
263
264     /* FIXME: Maybe this should be a buffer pool instead */
265     p_block = block_New( p_this, p_rtcp->u_length );
266     return p_block;
267 }
268
269 static block_t *rtcp_encode_SR( vlc_object_t *p_this, rtcp_t *p_rtcp )
270 {
271     mtime_t ntp_time;
272     bs_t bits, *s = &bits;
273     block_t *p_block = NULL;
274
275     /* FIXME: Maybe this should be a buffer pool instead */
276     p_block = block_New( p_this, p_rtcp->u_length );
277     if( !p_block )
278         return NULL;
279
280     bs_init( s, p_block->p_buffer, p_block->i_buffer );
281
282     /* Fill in header */
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 );
288
289     /* fill in record */
290     bs_write( s, 32, htonl( p_rtcp->report.sr.u_ssrc ) );
291
292     ntp_time = mdate();
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 */
295
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 ) );
304
305     return p_block;
306 }
307
308 static block_t *rtcp_encode_RR( vlc_object_t *p_this, rtcp_t *p_rtcp )
309 {
310     bs_t bits, *s = &bits;
311     block_t *p_block = NULL;
312
313     /* FIXME: Maybe this should be a buffer pool instead */
314     p_block = block_New( p_this, p_rtcp->u_length );
315     if( !p_block )
316         return NULL;
317
318     bs_init( s, p_block->p_buffer, p_block->i_buffer );
319
320     /* Fill in header */
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 );
326
327     /* fill in record */
328     bs_write( s, 32, htonl( p_rtcp->report.rr.u_ssrc ) );
329
330     return p_block;
331 }
332
333 static block_t *rtcp_encode_SDES( vlc_object_t *p_this, rtcp_t *p_rtcp )
334 {
335     bs_t bits, *s = &bits;
336     block_t *p_block = NULL;
337     char *p_hostname = strdup("hostname");
338     int i_length;
339     int i;
340
341     /* FIXME: Maybe this should be a buffer pool instead */
342     p_block = block_New( p_this, p_rtcp->u_length );
343     if( !p_block )
344         return NULL;
345
346     bs_init( s, p_block->p_buffer, p_block->i_buffer );
347
348     /* Fill in header */
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 );
354
355     /* fill in record */
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 ) );
359
360     i_length = strlen(p_hostname);
361     bs_write( s, 8, i_length );
362     for( i=0; i<i_length; i++ )
363     {
364         bs_write( s, 8, p_hostname[i] );
365     }
366     free(p_hostname);
367     return p_block;
368 }
369
370 static block_t *rtcp_encode_BYE( vlc_object_t *p_this, rtcp_t *p_rtcp )
371 {
372     bs_t bits, *s = &bits;
373     block_t *p_block = NULL;
374     char *p_reason = strdup( "Stream ended." );
375     int i_length;
376     int i;
377
378     /* FIXME: Maybe this should be a buffer pool instead */
379     p_block = block_New( p_this, p_rtcp->u_length );
380     if( !p_block )
381         return NULL;
382
383     bs_init( s, p_block->p_buffer, p_block->i_buffer );
384
385     /* Fill in header */
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 );
391
392     /* fill in record */
393     bs_write( s, 32, htonl( p_rtcp->report.sdes.u_ssrc ) );
394
395     i_length = strlen(p_reason);
396     bs_write( s, 8, i_length );
397     for( i=0; i<i_length; i++ )
398     {
399         bs_write( s, 8, p_reason[i] );
400     }
401     free(p_reason);
402     return p_block;
403 }