usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / udpxy / rtp.c
blob6f98e504042a7488d7bb8d4cb6861dede17f37d4
1 /* @(#) implementation of RTP-protocol parsing functions for udpxy
3 * Copyright 2008-2011 Pavel V. Cherenkov (pcherenkov@gmail.com)
5 * This file is part of udpxy.
7 * udpxy is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * udpxy is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with udpxy. If not, see <http://www.gnu.org/licenses/>.
21 #include <stdio.h>
22 #include <assert.h>
23 #include <sys/types.h>
24 #include <errno.h>
26 #include "rtp.h"
27 #include "mtrace.h"
28 #include "util.h"
31 /* check if the buffer is an RTP packet
33 int
34 RTP_check( const char* buf, const size_t len, int* is_rtp, FILE* log )
36 int rtp_version = 0;
37 int rtp_payload_type = 0;
39 assert( buf && len && is_rtp && log );
41 if( len < RTP_MIN_SIZE ) {
42 (void)tmfprintf( log, "RTP_check: buffer size [%lu] is "
43 "less than minimum [%lu]\n" , (u_long)len, (u_long)RTP_MIN_SIZE );
44 return -1;
47 /* initial assumption: is NOT RTP */
48 *is_rtp = 0;
50 if( MPEG_TS_SIG == buf[0] ) {
51 TRACE( (void)tmfputs( "MPEG-TS stream detected\n", log ) );
52 return 0;
55 rtp_version = ( buf[0] & 0xC0 ) >> 6;
56 if( RTP_VER2 != rtp_version ) {
57 TRACE( (void)tmfprintf( log, "RTP_check: wrong RTP version [%d], "
58 "must be [%d]\n", (int)rtp_version, (int)RTP_VER2) );
59 return 0;
62 if( len < RTP_HDR_SIZE ) {
63 TRACE( (void)tmfprintf( log, "RTP_check: header size "
64 "is too small [%lu]\n", (u_long)len ) );
65 return 0;
68 *is_rtp = 1;
70 rtp_payload_type = buf[1] & 0x7F;
71 switch( rtp_payload_type ) {
72 case P_MPGA:
73 TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG audio stream\n",
74 (int)rtp_payload_type ) );
75 break;
76 case P_MPGV:
77 TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG video stream\n",
78 (int)rtp_payload_type ) );
79 break;
80 case P_MPGTS:
81 TRACE( (void)tmfprintf( log, "RTP_check: [%d] MPEG TS stream\n",
82 (int)rtp_payload_type ) );
83 break;
85 default:
86 (void) tmfprintf( log, "RTP_check: unsupported RTP "
87 "payload type [%d]\n", (int)rtp_payload_type );
88 return -1;
91 return 0;
95 /* return 1 if buffer contains an RTP packet, 0 otherwise
97 int
98 RTP_verify( const char* buf, const size_t len, FILE* log )
100 int rtp_version = 0;
101 int rtp_payload_type = 0;
103 if( (len < RTP_MIN_SIZE) || (len < RTP_HDR_SIZE) ) {
104 (void)tmfprintf( log, "RTP_verify: inappropriate size=[%lu] "
105 "of RTP packet\n", (u_long)len );
106 return 0;
109 rtp_version = ( buf[0] & 0xC0 ) >> 6;
110 rtp_payload_type = buf[1] & 0x7F;
113 TRACE( (void)tmfprintf( log, "RTP version [%d] at [%p]\n", rtp_version,
114 (const void*)buf ) );
117 if( RTP_VER2 != rtp_version ) {
119 TRACE( (void)tmfprintf( log, "RTP_verify: wrong RTP version [%d], "
120 "must be [%d]\n", (int)rtp_version, (int)RTP_VER2) );
122 return 0;
125 switch( rtp_payload_type ) {
126 case P_MPGA:
127 case P_MPGV:
128 case P_MPGTS:
129 break;
130 default:
131 (void) tmfprintf( log, "RTP_verify: unsupported RTP "
132 "payload type [%d]\n", (int)rtp_payload_type );
133 return 0;
136 return 1;
140 /* calculate length of an RTP header
143 RTP_hdrlen( const char* buf, const size_t len, size_t* hdrlen, FILE* log )
145 int rtp_CSRC = -1, rtp_ext = -1;
146 int rtp_payload = -1;
147 ssize_t front_skip = 0,
148 ext_len = 0;
150 assert( buf && (len >= RTP_HDR_SIZE) && hdrlen && log );
152 rtp_payload = buf[1] & 0x7F;
153 rtp_CSRC = buf[0] & 0x0F;
154 rtp_ext = buf[0] & 0x10;
156 /* profile-based skip: adopted from vlc 0.8.6 code */
157 if( (P_MPGA == rtp_payload) || (P_MPGV == rtp_payload) )
158 front_skip = 4;
159 else if( P_MPGTS != rtp_payload ) {
160 (void)tmfprintf( log, "RTP_process: "
161 "Unsupported payload type [%d]\n", rtp_payload );
162 return -1;
165 if( rtp_ext ) {
167 TRACE( (void)tmfprintf( log, "%s: RTP x-header detected, CSRC=[%d]\n",
168 __func__, rtp_CSRC) );
171 if( len < RTP_XTHDRLEN ) {
173 TRACE( (void)tmfprintf( log, "%s: RTP x-header requires "
174 "[%lu] bytes, only [%lu] provided\n", __func__,
175 (u_long)(XTLEN_OFFSET + 1), (u_long)len ) );
177 return ENOMEM;
181 if( rtp_ext ) {
182 ext_len = XTSIZE +
183 sizeof(int32_t) * ((buf[ XTLEN_OFFSET ] << 8) + buf[ XTLEN_OFFSET + 1 ]);
186 front_skip += RTP_HDR_SIZE + (CSRC_SIZE * rtp_CSRC) + ext_len;
188 *hdrlen = front_skip;
189 return 0;
193 /* process RTP package to retrieve the payload
196 RTP_process( void** pbuf, size_t* len, int verify, FILE* log )
198 int rtp_padding = -1;
199 size_t front_skip = 0, back_skip = 0, pad_len = 0;
201 char* buf = NULL;
202 size_t pkt_len = 0;
204 assert( pbuf && len && log );
205 buf = *pbuf;
206 pkt_len = *len;
208 if( verify && !RTP_verify( buf, pkt_len, log ) )
209 return -1;
211 if( 0 != RTP_hdrlen( buf, pkt_len, &front_skip, log ) )
212 return -1;
214 rtp_padding = buf[0] & 0x20;
215 if( rtp_padding ) {
216 pad_len = buf[ pkt_len - 1 ];
219 back_skip += pad_len;
221 if( verify && (pkt_len < (front_skip + back_skip)) ) {
222 (void) tmfprintf( log, "RTP_process: invalid header "
223 "(skip [%lu] exceeds packet length [%lu])\n",
224 (u_long)(front_skip + back_skip), (u_long)pkt_len );
225 return -1;
228 /* adjust buffer/length to skip heading and padding */
230 TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, "
231 "fskip=[%ld], bskip=[%lu]\n",
232 (void*)buf, (u_long)pkt_len,
233 (u_long)front_skip, (u_long)back_skip ) );
236 buf += front_skip;
237 pkt_len -= (front_skip + back_skip);
240 TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n",
241 (void*)buf, (u_long)pkt_len ) );
243 *pbuf = buf;
244 *len = pkt_len;
246 return 0;
250 /* __EOF__ */