Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia / rtp.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20 #include <pjmedia/rtp.h>
21 #include <pjmedia/errno.h>
22 #include <pj/log.h>
23 #include <pj/sock.h>    /* pj_htonx, pj_htonx */
24 #include <pj/assert.h>
25 #include <pj/rand.h>
26 #include <pj/string.h>
27
28
29 #define THIS_FILE   "rtp.c"
30
31 #define RTP_VERSION     2
32
33 #define RTP_SEQ_MOD     (1 << 16)
34 #define MAX_DROPOUT     ((pj_int16_t)3000)
35 #define MAX_MISORDER    ((pj_int16_t)100)
36 #define MIN_SEQUENTIAL  ((pj_int16_t)2)
37
38 static void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *seq_ctrl, 
39                                     pj_uint16_t seq);
40
41
42 PJ_DEF(pj_status_t) pjmedia_rtp_session_init( pjmedia_rtp_session *ses,
43                                               int default_pt, 
44                                               pj_uint32_t sender_ssrc )
45 {
46     PJ_LOG(5, (THIS_FILE, 
47                "pjmedia_rtp_session_init: ses=%p, default_pt=%d, ssrc=0x%x",
48                ses, default_pt, sender_ssrc));
49
50     /* Check RTP header packing. */
51     if (sizeof(struct pjmedia_rtp_hdr) != 12) {
52         pj_assert(!"Wrong RTP header packing!");
53         return PJMEDIA_RTP_EINPACK;
54     }
55
56     /* If sender_ssrc is not specified, create from random value. */
57     if (sender_ssrc == 0 || sender_ssrc == (pj_uint32_t)-1) {
58         sender_ssrc = pj_htonl(pj_rand());
59     } else {
60         sender_ssrc = pj_htonl(sender_ssrc);
61     }
62
63     /* Initialize session. */
64     pj_bzero(ses, sizeof(*ses));
65
66     /* Initial sequence number SHOULD be random, according to RFC 3550. */
67     /* According to RFC 3711, it should be random within 2^15 bit */
68     ses->out_extseq = pj_rand() & 0x7FFF;
69     ses->peer_ssrc = 0;
70     
71     /* Build default header for outgoing RTP packet. */
72     ses->out_hdr.v = RTP_VERSION;
73     ses->out_hdr.p = 0;
74     ses->out_hdr.x = 0;
75     ses->out_hdr.cc = 0;
76     ses->out_hdr.m = 0;
77     ses->out_hdr.pt = (pj_uint8_t) default_pt;
78     ses->out_hdr.seq = (pj_uint16_t) pj_htons( (pj_uint16_t)ses->out_extseq );
79     ses->out_hdr.ts = 0;
80     ses->out_hdr.ssrc = sender_ssrc;
81
82     /* Keep some arguments as session defaults. */
83     ses->out_pt = (pj_uint16_t) default_pt;
84
85     return PJ_SUCCESS;
86 }
87
88 PJ_DEF(pj_status_t) pjmedia_rtp_session_init2( 
89                                     pjmedia_rtp_session *ses,
90                                     pjmedia_rtp_session_setting settings)
91 {
92     pj_status_t status;
93     int          pt = 0;
94     pj_uint32_t  sender_ssrc = 0;
95
96     if (settings.flags & 1)
97         pt = settings.default_pt;
98     if (settings.flags & 2)
99         sender_ssrc = settings.sender_ssrc;
100
101     status = pjmedia_rtp_session_init(ses, pt, sender_ssrc);
102     if (status != PJ_SUCCESS)
103         return status;
104
105     if (settings.flags & 4) {
106         ses->out_extseq = settings.seq;
107         ses->out_hdr.seq = pj_htons((pj_uint16_t)ses->out_extseq);
108     }
109     if (settings.flags & 8)
110         ses->out_hdr.ts = pj_htonl(settings.ts);
111
112     return PJ_SUCCESS;
113 }
114
115
116 PJ_DEF(pj_status_t) pjmedia_rtp_encode_rtp( pjmedia_rtp_session *ses, 
117                                             int pt, int m,
118                                             int payload_len, int ts_len,
119                                             const void **rtphdr, int *hdrlen )
120 {
121     PJ_UNUSED_ARG(payload_len);
122
123     /* Update timestamp */
124     ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len);
125
126     /* If payload_len is zero, bail out.
127      * This is a clock frame; we're not really transmitting anything.
128      */
129     if (payload_len == 0)
130         return PJ_SUCCESS;
131
132     /* Update session. */
133     ses->out_extseq++;
134
135     /* Create outgoing header. */
136     ses->out_hdr.pt = (pj_uint8_t) ((pt == -1) ? ses->out_pt : pt);
137     ses->out_hdr.m = (pj_uint16_t) m;
138     ses->out_hdr.seq = pj_htons( (pj_uint16_t) ses->out_extseq);
139
140     /* Return values */
141     *rtphdr = &ses->out_hdr;
142     *hdrlen = sizeof(pjmedia_rtp_hdr);
143
144     return PJ_SUCCESS;
145 }
146
147
148 PJ_DEF(pj_status_t) pjmedia_rtp_decode_rtp( pjmedia_rtp_session *ses, 
149                                             const void *pkt, int pkt_len,
150                                             const pjmedia_rtp_hdr **hdr,
151                                             const void **payload,
152                                             unsigned *payloadlen)
153 {
154     int offset;
155
156     PJ_UNUSED_ARG(ses);
157
158     /* Assume RTP header at the start of packet. We'll verify this later. */
159     *hdr = (pjmedia_rtp_hdr*)pkt;
160
161     /* Check RTP header sanity. */
162     if ((*hdr)->v != RTP_VERSION) {
163         return PJMEDIA_RTP_EINVER;
164     }
165
166     /* Payload is located right after header plus CSRC */
167     offset = sizeof(pjmedia_rtp_hdr) + ((*hdr)->cc * sizeof(pj_uint32_t));
168
169     /* Adjust offset if RTP extension is used. */
170     if ((*hdr)->x) {
171         pjmedia_rtp_ext_hdr *ext = (pjmedia_rtp_ext_hdr*) 
172                                     (((pj_uint8_t*)pkt) + offset);
173         offset += ((pj_ntohs(ext->length)+1) * sizeof(pj_uint32_t));
174     }
175
176     /* Check that offset is less than packet size */
177     if (offset > pkt_len)
178         return PJMEDIA_RTP_EINLEN;
179
180     /* Find and set payload. */
181     *payload = ((pj_uint8_t*)pkt) + offset;
182     *payloadlen = pkt_len - offset;
183  
184     /* Remove payload padding if any */
185     if ((*hdr)->p && *payloadlen > 0) {
186         pj_uint8_t pad_len;
187
188         pad_len = ((pj_uint8_t*)(*payload))[*payloadlen - 1];
189         if (pad_len <= *payloadlen)
190             *payloadlen -= pad_len;
191     }
192
193     return PJ_SUCCESS;
194 }
195
196
197 PJ_DEF(void) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, 
198                                          const pjmedia_rtp_hdr *hdr,
199                                          pjmedia_rtp_status *p_seq_st)
200 {
201     pjmedia_rtp_session_update2(ses, hdr, p_seq_st, PJ_TRUE);
202 }
203
204 PJ_DEF(void) pjmedia_rtp_session_update2( pjmedia_rtp_session *ses, 
205                                           const pjmedia_rtp_hdr *hdr,
206                                           pjmedia_rtp_status *p_seq_st,
207                                           pj_bool_t check_pt)
208 {
209     pjmedia_rtp_status seq_st;
210
211     /* for now check_pt MUST be either PJ_TRUE or PJ_FALSE.
212      * In the future we might change check_pt from boolean to 
213      * unsigned integer to accommodate more flags.
214      */
215     pj_assert(check_pt==PJ_TRUE || check_pt==PJ_FALSE);
216
217     /* Init status */
218     seq_st.status.value = 0;
219     seq_st.diff = 0;
220
221     /* Check SSRC. */
222     if (ses->peer_ssrc == 0) ses->peer_ssrc = pj_ntohl(hdr->ssrc);
223
224     if (pj_ntohl(hdr->ssrc) != ses->peer_ssrc) {
225         seq_st.status.flag.badssrc = 1;
226         ses->peer_ssrc = pj_ntohl(hdr->ssrc);
227     }
228
229     /* Check payload type. */
230     if (check_pt && hdr->pt != ses->out_pt) {
231         if (p_seq_st) {
232             p_seq_st->status.value = seq_st.status.value;
233             p_seq_st->status.flag.bad = 1;
234             p_seq_st->status.flag.badpt = 1;
235         }
236         return;
237     }
238
239     /* Initialize sequence number on first packet received. */
240     if (ses->received == 0)
241         pjmedia_rtp_seq_init( &ses->seq_ctrl, pj_ntohs(hdr->seq) );
242
243     /* Check sequence number to see if remote session has been restarted. */
244     pjmedia_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq), &seq_st);
245     if (seq_st.status.flag.restart) {
246         ++ses->received;
247
248     } else if (!seq_st.status.flag.bad) {
249         ++ses->received;
250     }
251
252     if (p_seq_st) {
253         p_seq_st->status.value = seq_st.status.value;
254         p_seq_st->diff = seq_st.diff;
255     }
256 }
257
258
259
260 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *sess, pj_uint16_t seq)
261 {
262     sess->base_seq = seq;
263     sess->max_seq = seq;
264     sess->bad_seq = RTP_SEQ_MOD + 1;
265     sess->cycles = 0;
266 }
267
268
269 void pjmedia_rtp_seq_init(pjmedia_rtp_seq_session *sess, pj_uint16_t seq)
270 {
271     pjmedia_rtp_seq_restart(sess, seq);
272
273     sess->max_seq = (pj_uint16_t) (seq - 1);
274     sess->probation = MIN_SEQUENTIAL;
275 }
276
277
278 void pjmedia_rtp_seq_update( pjmedia_rtp_seq_session *sess, 
279                              pj_uint16_t seq,
280                              pjmedia_rtp_status *seq_status)
281 {
282     pj_uint16_t udelta = (pj_uint16_t) (seq - sess->max_seq);
283     pjmedia_rtp_status st;
284     
285     /* Init status */
286     st.status.value = 0;
287     st.diff = 0;
288
289     /*
290      * Source is not valid until MIN_SEQUENTIAL packets with
291      * sequential sequence numbers have been received.
292      */
293     if (sess->probation) {
294
295         st.status.flag.probation = 1;
296         
297         if (seq == sess->max_seq+ 1) {
298             /* packet is in sequence */
299             st.diff = 1;
300             sess->probation--;
301             sess->max_seq = seq;
302             if (sess->probation == 0) {
303                 st.status.flag.probation = 0;
304             }
305         } else {
306
307             st.diff = 0;
308
309             st.status.flag.bad = 1;
310             if (seq == sess->max_seq)
311                 st.status.flag.dup = 1;
312             else
313                 st.status.flag.outorder = 1;
314
315             sess->probation = MIN_SEQUENTIAL - 1;
316             sess->max_seq = seq;
317         }
318
319
320     } else if (udelta == 0) {
321
322         st.status.flag.dup = 1;
323
324     } else if (udelta < MAX_DROPOUT) {
325         /* in order, with permissible gap */
326         if (seq < sess->max_seq) {
327             /* Sequence number wrapped - count another 64K cycle. */
328             sess->cycles += RTP_SEQ_MOD;
329         }
330         sess->max_seq = seq;
331
332         st.diff = udelta;
333
334     } else if (udelta <= (RTP_SEQ_MOD - MAX_MISORDER)) {
335         /* the sequence number made a very large jump */
336         if (seq == sess->bad_seq) {
337             /*
338              * Two sequential packets -- assume that the other side
339              * restarted without telling us so just re-sync
340              * (i.e., pretend this was the first packet).
341              */
342             pjmedia_rtp_seq_restart(sess, seq);
343             st.status.flag.restart = 1;
344             st.status.flag.probation = 1;
345             st.diff = 1;
346         }
347         else {
348             sess->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
349             st.status.flag.bad = 1;
350             st.status.flag.outorder = 1;
351         }
352     } else {
353         /* old duplicate or reordered packet.
354          * Not necessarily bad packet (?)
355          */
356         st.status.flag.outorder = 1;
357     }
358     
359
360     if (seq_status) {
361         seq_status->diff = st.diff;
362         seq_status->status.value = st.status.value;
363     }
364 }
365
366