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/>.
23 #include <sys/types.h>
31 /* check if the buffer is an RTP packet
34 RTP_check( const char* buf
, const size_t len
, int* is_rtp
, FILE* log
)
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
);
47 /* initial assumption: is NOT RTP */
50 if( MPEG_TS_SIG
== buf
[0] ) {
51 TRACE( (void)tmfputs( "MPEG-TS stream detected\n", log
) );
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
) );
62 if( len
< RTP_HDR_SIZE
) {
63 TRACE( (void)tmfprintf( log
, "RTP_check: header size "
64 "is too small [%lu]\n", (u_long
)len
) );
70 rtp_payload_type
= buf
[1] & 0x7F;
71 switch( rtp_payload_type
) {
73 TRACE( (void)tmfprintf( log
, "RTP_check: [%d] MPEG audio stream\n",
74 (int)rtp_payload_type
) );
77 TRACE( (void)tmfprintf( log
, "RTP_check: [%d] MPEG video stream\n",
78 (int)rtp_payload_type
) );
81 TRACE( (void)tmfprintf( log
, "RTP_check: [%d] MPEG TS stream\n",
82 (int)rtp_payload_type
) );
86 (void) tmfprintf( log
, "RTP_check: unsupported RTP "
87 "payload type [%d]\n", (int)rtp_payload_type
);
95 /* return 1 if buffer contains an RTP packet, 0 otherwise
98 RTP_verify( const char* buf
, const size_t len
, FILE* log
)
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
);
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) );
125 switch( rtp_payload_type
) {
131 (void) tmfprintf( log
, "RTP_verify: unsupported RTP "
132 "payload type [%d]\n", (int)rtp_payload_type
);
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,
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
) )
159 else if( P_MPGTS
!= rtp_payload
) {
160 (void)tmfprintf( log
, "RTP_process: "
161 "Unsupported payload type [%d]\n", rtp_payload
);
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 ) );
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
;
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;
204 assert( pbuf
&& len
&& log
);
208 if( verify
&& !RTP_verify( buf
, pkt_len
, log
) )
211 if( 0 != RTP_hdrlen( buf
, pkt_len
, &front_skip
, log
) )
214 rtp_padding
= buf
[0] & 0x20;
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
);
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 ) );
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 ) );