1 /*
2 * Copyright (c) 2007-2008 Sippy Software, Inc., http://www.sippysoft.com
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <assert.h>
33 #include <stddef.h>
34
35 #include "rtp.h"
36 #include "rtp_info.h"
37 #include "rtp_packet.h"
38 #include "rtpp_mallocs.h"
39
40 #include "rtpp_wi.h"
41 #include "rtpp_wi_private.h"
42
43 #define RTP_PROFILE_AUDIO(s, nc) {.ts_rate = (s), .sample_rate = (s), \
44 .pt_kind = RTP_PTK_AUDIO, .nchannels = (nc)}
45
46 const struct rtp_profile rtp_profiles[128] = {
47 RTP_PROFILE_AUDIO(8000, 1), /* RTP_PCMU */
48 {.pt_kind = RTP_PTK_RES}, /* Reserved */
49 {.pt_kind = RTP_PTK_RES}, /* Reserved */
50 RTP_PROFILE_AUDIO(8000, 1), /* RTP_GSM */
51 RTP_PROFILE_AUDIO(8000, 1), /* RTP_G723 */
52 RTP_PROFILE_AUDIO(8000, 1), /* RTP_DVI4_8000 */
53 RTP_PROFILE_AUDIO(16000, 1), /* RTP_DVI4_16000 */
54 RTP_PROFILE_AUDIO(8000, 1), /* RTP_LPC */
55 RTP_PROFILE_AUDIO(8000, 1), /* RTP_PCMA */
56 RTP_PROFILE_AUDIO(8000, 1), /* RTP_G722 */
57 RTP_PROFILE_AUDIO(44100, 1), /* RTP_L16_MONO */
58 RTP_PROFILE_AUDIO(44100, 2), /* RTP_L16_STEREO */
59 RTP_PROFILE_AUDIO(8000, 1), /* RTP_QCELP */
60 RTP_PROFILE_AUDIO(8000, 1), /* RTP_CN */
61 RTP_PROFILE_AUDIO(90000, 2), /* RTP_MPA */
62 RTP_PROFILE_AUDIO(8000, 1), /* RTP_G728 */
63 RTP_PROFILE_AUDIO(11025, 1), /* RTP_DVI4_11025 */
64 RTP_PROFILE_AUDIO(22050, 1), /* RTP_DVI4_22050 */
65 RTP_PROFILE_AUDIO(8000, 1) /* RTP_G729 */
66 };
67
68 struct rtp_packet_full;
69
70 struct rtp_packet_priv {
71 struct rtp_info rinfo;
72 struct rtpp_wi wi;
73 };
74
75 struct rtp_packet_full {
76 struct rtp_packet pub;
77 struct rtp_packet_priv pvt;
78 };
79
80 static int
g723_len(unsigned char ch)81 g723_len(unsigned char ch)
82 {
83
84 switch (ch & 3) {
85 case 2:
86 /* Silence Insertion Descriptor (SID) frame */
87 return 4;
88
89 case 0:
90 /* 6.3 kbit/s frame */
91 return 24;
92
93 case 1:
94 /* 5.3 kbit/s frame */
95 return 20;
96
97 default:
98 return RTP_NSAMPLES_UNKNOWN;
99 }
100 }
101
102 static int
g723_samples(const unsigned char * buf,int maxlen)103 g723_samples(const unsigned char *buf, int maxlen)
104 {
105 int pos, samples, n;
106
107 for (pos = 0, samples = 0; pos < maxlen; pos += n) {
108 samples += 240;
109 n = g723_len(buf[pos]);
110 if (n == RTP_NSAMPLES_UNKNOWN)
111 return RTP_NSAMPLES_UNKNOWN;
112 }
113 return samples;
114 }
115
116 static int
rtp_calc_samples(int codec_id,size_t nbytes,const unsigned char * data)117 rtp_calc_samples(int codec_id, size_t nbytes, const unsigned char *data)
118 {
119
120 switch (codec_id) {
121 case RTP_PCMU:
122 case RTP_PCMA:
123 return nbytes;
124
125 case RTP_G729:
126 return (nbytes / 10) * 80 + (nbytes % 10 == 0 ? 0 : 80);
127
128 case RTP_GSM:
129 return 160 * (nbytes / 33);
130
131 case RTP_G723:
132 return g723_samples(data, nbytes);
133
134 case RTP_G722:
135 return nbytes;
136
137 default:
138 return RTP_NSAMPLES_UNKNOWN;
139 }
140 }
141
142 static void
rtp_packet_chunk_find_g711(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)143 rtp_packet_chunk_find_g711(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
144 {
145
146 ret->nsamples = min_nsamples;
147 ret->bytes = min_nsamples;
148 }
149
150 static void
rtp_packet_chunk_find_g729(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)151 rtp_packet_chunk_find_g729(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
152 {
153 int frames, samples;
154
155 frames = min_nsamples / 80 + ((min_nsamples % 80) == 0 ? 0 : 1);
156 samples = frames * 80;
157
158 if (samples >= pkt->parsed->nsamples) {
159 ret->whole_packet_matched = 1;
160 return;
161 }
162 ret->nsamples = samples;
163 ret->bytes = frames * 10;
164 }
165
166 static void
rtp_packet_chunk_find_gsm(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)167 rtp_packet_chunk_find_gsm(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
168 {
169 int frames, samples;
170
171 frames = min_nsamples / 160 + ((min_nsamples % 160) == 0 ? 0 : 1);
172 samples = frames * 160;
173
174 if (samples >= pkt->parsed->nsamples) {
175 ret->whole_packet_matched = 1;
176 return;
177 }
178 ret->nsamples = samples;
179 ret->bytes = frames * 33;
180 }
181
182 static void
rtp_packet_chunk_find_g723(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)183 rtp_packet_chunk_find_g723(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
184 {
185 int frames, samples, pos, found_samples, n;
186 unsigned char *buf;
187
188 frames = min_nsamples / 240 + ((min_nsamples % 240) == 0 ? 0 : 1);
189 samples = frames * 240;
190
191 pos = 0;
192 found_samples = 0;
193 if (samples >= pkt->parsed->nsamples) {
194 ret->whole_packet_matched = 1;
195 return;
196 }
197
198 buf = &pkt->data.buf[pkt->parsed->data_offset];
199 while (pos < pkt->parsed->data_size && samples > found_samples) {
200 found_samples += 240;
201 n = g723_len(buf[pos]);
202 assert(n != RTP_NSAMPLES_UNKNOWN);
203 pos += n;
204 }
205 ret->nsamples = found_samples;
206 ret->bytes = (pos < pkt->parsed->data_size ? pos : pkt->parsed->data_size);
207 }
208
209 static void
rtp_packet_chunk_find_g722(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)210 rtp_packet_chunk_find_g722(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
211 {
212 ret->nsamples = min_nsamples;
213 ret->bytes = min_nsamples / 2;
214 }
215
216
217 /*
218 * Find the head of the packet with the length at least
219 * of min_nsamples.
220 *
221 * Warning! When whole packet has been matched the chunk can be uninitialized.
222 */
223 void
rtp_packet_first_chunk_find(struct rtp_packet * pkt,struct rtp_packet_chunk * ret,int min_nsamples)224 rtp_packet_first_chunk_find(struct rtp_packet *pkt, struct rtp_packet_chunk *ret, int min_nsamples)
225 {
226
227 assert(pkt->parsed->nsamples > min_nsamples);
228 ret->whole_packet_matched = 0;
229
230 switch (pkt->data.header.pt) {
231 case RTP_PCMU:
232 case RTP_PCMA:
233 rtp_packet_chunk_find_g711(pkt, ret, min_nsamples);
234 break;
235
236 case RTP_G729:
237 rtp_packet_chunk_find_g729(pkt, ret, min_nsamples);
238 break;
239
240 case RTP_GSM:
241 rtp_packet_chunk_find_gsm(pkt, ret, min_nsamples);
242 break;
243
244 case RTP_G723:
245 rtp_packet_chunk_find_g723(pkt, ret, min_nsamples);
246 break;
247
248 case RTP_G722:
249 rtp_packet_chunk_find_g722(pkt, ret, min_nsamples);
250 break;
251
252 default:
253 ret->whole_packet_matched = 1;
254 break;
255 }
256 }
257
258 const char *
rtp_packet_parse_errstr(rtp_parser_err_t ecode)259 rtp_packet_parse_errstr(rtp_parser_err_t ecode)
260 {
261 switch (ecode) {
262 case RTP_PARSER_OK:
263 return "no error";
264
265 case RTP_PARSER_PTOOSHRT:
266 return "packet is too short for RTP header";
267
268 case RTP_PARSER_IHDRVER:
269 return "incorrect RTP header version";
270
271 case RTP_PARSER_PTOOSHRTXS:
272 return "packet is too short for extended RTP header size";
273
274 case RTP_PARSER_PTOOSHRTXH:
275 return "packet is too short for extended RTP header";
276
277 case RTP_PARSER_PTOOSHRTPS:
278 return "packet is too short for RTP padding size";
279
280 case RTP_PARSER_PTOOSHRTP:
281 return "packet is too short for RTP padding";
282
283 case RTP_PARSER_IPS:
284 return "invalid RTP padding size";
285
286 default:
287 abort();
288 }
289
290 /* NOTREACHED */
291 return NULL;
292 }
293
294 rtp_parser_err_t
rtp_packet_parse_raw(unsigned char * buf,size_t size,struct rtp_info * rinfo)295 rtp_packet_parse_raw(unsigned char *buf, size_t size, struct rtp_info *rinfo)
296 {
297 int padding_size;
298 rtp_hdr_ext_t *hdr_ext_ptr;
299 rtp_hdr_t *header;
300
301 header = (rtp_hdr_t *)buf;
302
303 padding_size = 0;
304
305 rinfo->data_size = 0;
306 rinfo->data_offset = 0;
307 rinfo->appendable = 1;
308 rinfo->nsamples = RTP_NSAMPLES_UNKNOWN;
309
310 if (size < sizeof(*header))
311 return RTP_PARSER_PTOOSHRT;
312
313 if (header->version != 2)
314 return RTP_PARSER_IHDRVER;
315
316 rinfo->data_offset = RTP_HDR_LEN(header);
317
318 if (header->x != 0) {
319 if (size < rinfo->data_offset + sizeof(*hdr_ext_ptr))
320 return RTP_PARSER_PTOOSHRTXS;
321 hdr_ext_ptr = (rtp_hdr_ext_t *)&buf[rinfo->data_offset];
322 rinfo->data_offset += sizeof(rtp_hdr_ext_t) +
323 (ntohs(hdr_ext_ptr->length) * sizeof(hdr_ext_ptr->extension[0]));
324 }
325
326 if (size < rinfo->data_offset)
327 return RTP_PARSER_PTOOSHRTXH;
328
329 if (header->p != 0) {
330 if (rinfo->data_offset == size)
331 return RTP_PARSER_PTOOSHRTPS;
332 padding_size = buf[size - 1];
333 if (padding_size == 0)
334 return RTP_PARSER_IPS;
335 }
336
337 if (size < rinfo->data_offset + padding_size)
338 return RTP_PARSER_PTOOSHRTP;
339
340 rinfo->data_size = size - rinfo->data_offset - padding_size;
341 rinfo->ts = ntohl(header->ts);
342 rinfo->seq = ntohs(header->seq);
343 rinfo->ssrc = ntohl(header->ssrc);
344 rinfo->rtp_profile = &rtp_profiles[header->pt];
345
346 if (rinfo->data_size == 0)
347 return RTP_PARSER_OK;
348
349 rinfo->nsamples = rtp_calc_samples(header->pt, rinfo->data_size,
350 &buf[rinfo->data_offset]);
351 /*
352 * G.729 comfort noise frame as the last frame causes
353 * packet to be non-appendable
354 */
355 if (header->pt == RTP_G729 && (rinfo->data_size % 10) != 0)
356 rinfo->appendable = 0;
357 return RTP_PARSER_OK;
358 }
359
360 rtp_parser_err_t
rtp_packet_parse(struct rtp_packet * pkt)361 rtp_packet_parse(struct rtp_packet *pkt)
362 {
363 struct rtp_packet_full *pkt_full;
364 struct rtp_info *rinfo;
365
366 if (pkt->parse_result != RTP_PARSER_NOTPARSED) {
367 return (pkt->parse_result);
368 }
369 assert(pkt->parsed == NULL);
370 pkt_full = (void *)pkt;
371 rinfo = &(pkt_full->pvt.rinfo);
372 pkt->parse_result = rtp_packet_parse_raw(pkt->data.buf, pkt->size, rinfo);
373 if (pkt->parse_result == RTP_PARSER_OK) {
374 pkt->parsed = rinfo;
375 }
376 return (pkt->parse_result);
377 }
378
379 void
rtp_packet_dup(struct rtp_packet * dpkt,struct rtp_packet * spkt,int flags)380 rtp_packet_dup(struct rtp_packet *dpkt, struct rtp_packet *spkt, int flags)
381 {
382 int csize;
383 struct rtp_packet_full *dpkt_full, *spkt_full;
384 struct rtp_info *drinfo, *srinfo;
385
386 csize = offsetof(struct rtp_packet, data.buf) + spkt->size;
387 if ((flags & RTPP_DUP_HDRONLY) != 0) {
388 assert(spkt->parse_result == RTP_PARSER_OK);
389 csize -= spkt->parsed->data_size;
390 }
391 memcpy(dpkt, spkt, csize);
392 dpkt_full = (struct rtp_packet_full *)dpkt;
393 dpkt->wi = &(dpkt_full->pvt.wi);
394 if (dpkt->parsed == NULL) {
395 return;
396 }
397 drinfo = &(dpkt_full->pvt.rinfo);
398 spkt_full = (struct rtp_packet_full *)spkt;
399 srinfo = &(spkt_full->pvt.rinfo);
400 memcpy(drinfo, srinfo, sizeof(struct rtp_info));
401 dpkt->parsed = drinfo;
402 if ((flags & RTPP_DUP_HDRONLY) != 0) {
403 dpkt->size -= dpkt->parsed->data_size;
404 dpkt->parsed->data_size = 0;
405 dpkt->parsed->nsamples = 0;
406 }
407 }
408
409 struct rtp_packet *
rtp_packet_alloc()410 rtp_packet_alloc()
411 {
412 struct rtp_packet_full *pkt;
413
414 pkt = rtpp_zmalloc(sizeof(*pkt));
415 if (pkt == NULL) {
416 return (NULL);
417 }
418 pkt->pub.wi = &pkt->pvt.wi;
419
420 return &(pkt->pub);
421 }
422
423 void
rtp_packet_free(struct rtp_packet * pkt)424 rtp_packet_free(struct rtp_packet *pkt)
425 {
426
427 free(pkt);
428 }
429
430 void
rtp_packet_set_seq(struct rtp_packet * p,uint16_t seq)431 rtp_packet_set_seq(struct rtp_packet *p, uint16_t seq)
432 {
433
434 p->parsed->seq = seq;
435 p->data.header.seq = htons(seq);
436 }
437
438 void
rtp_packet_set_ts(struct rtp_packet * p,uint32_t ts)439 rtp_packet_set_ts(struct rtp_packet *p, uint32_t ts)
440 {
441
442 p->parsed->ts = ts;
443 p->data.header.ts = htonl(ts);
444 }
445