]> sjero.net Git - linphone/blob - linphone/oRTP/src/rtpparse.c
Merge branch 'master' of belledonne-communications.com:linphone-private
[linphone] / linphone / oRTP / src / rtpparse.c
1 /*
2   The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
3   Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
4
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20
21 #include <ortp/ortp.h>
22 #include "jitterctl.h"
23 #include "utils.h"
24 #include "rtpsession_priv.h"
25
26 #define SSRC_CHANGED_THRESHOLD 50
27
28 static void queue_packet(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded)
29 {
30         mblk_t *tmp;
31         int header_size;
32         *discarded=0;
33         header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc);
34         if ((mp->b_wptr - mp->b_rptr)==header_size){
35                 ortp_debug("Rtp packet contains no data.");
36                 (*discarded)++;
37                 freemsg(mp);
38                 return;
39         }
40         /* and then add the packet to the queue */
41         
42         rtp_putq(q,mp);
43         /* make some checks: q size must not exceed RtpStream::max_rq_size */
44         while (q->q_mcount > maxrqsz)
45         {
46                 /* remove the oldest mblk_t */
47                 tmp=getq(q);
48                 if (mp!=NULL)
49                 {
50                         ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp);
51                         freemsg(tmp);
52                         (*discarded)++;
53                 }
54         }
55 }
56
57 void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
58 {
59         int i;
60         rtp_header_t *rtp;
61         int msgsize;
62         RtpStream *rtpstream=&session->rtp;
63         rtp_stats_t *stats=&rtpstream->stats;
64         
65         msgsize=mp->b_wptr-mp->b_rptr;
66
67         if (msgsize<RTP_FIXED_HEADER_SIZE){
68                 ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize);
69                 rtpstream->stats.bad++;
70                 ortp_global_stats.bad++;
71                 freemsg(mp);
72                 return;
73         }
74         rtp=(rtp_header_t*)mp->b_rptr;
75         if (rtp->version!=2)
76         {
77                 /* try to see if it is a STUN packet */
78                 uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t)));
79                 stunlen = ntohs(stunlen);
80                 if (stunlen+20==mp->b_wptr-mp->b_rptr){
81                         /* this looks like a stun packet */
82                         if (session->eventqs!=NULL){
83                                 OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED);
84                                 OrtpEventData *ed=ortp_event_get_data(ev);
85                                 ed->packet=mp;
86                                 ed->ep=rtp_endpoint_new(addr,addrlen);
87                                 rtp_session_dispatch_event(session,ev);
88                                 return;
89                         }
90                 }
91                 /* discard in two case: the packet is not stun OR nobody is interested by STUN (no eventqs) */
92                 ortp_debug("Receiving rtp packet with version number !=2...discarded");
93                 stats->bad++;
94                 ortp_global_stats.bad++;
95                 freemsg(mp);
96                 return;
97         }
98
99         /* only count non-stun packets. */
100         ortp_global_stats.packet_recv++;
101         stats->packet_recv++;
102         ortp_global_stats.hw_recv+=msgsize;
103         stats->hw_recv+=msgsize;
104         session->rtp.hwrcv_since_last_SR++;
105
106         
107         /* convert all header data from network order to host order */
108         rtp->seq_number=ntohs(rtp->seq_number);
109         rtp->timestamp=ntohl(rtp->timestamp);
110         rtp->ssrc=ntohl(rtp->ssrc);
111         /* convert csrc if necessary */
112         if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){
113                 ortp_debug("Receiving too short rtp packet.");
114                 stats->bad++;
115                 ortp_global_stats.bad++;
116                 freemsg(mp);
117                 return;
118         }
119
120 #ifndef PERF
121         /* Write down the last RTP/RTCP packet reception time. */
122         gettimeofday(&session->last_recv_time, NULL);
123 #endif
124
125         for (i=0;i<rtp->cc;i++)
126                 rtp->csrc[i]=ntohl(rtp->csrc[i]);
127         /*the goal of the following code is to lock on an incoming SSRC to avoid
128         receiving "mixed streams"*/
129         if (session->ssrc_set){
130                 /*the ssrc is set, so we must check it */
131                 if (session->rcv.ssrc!=rtp->ssrc){
132                         if (session->inc_ssrc_candidate==rtp->ssrc){
133                                 session->inc_same_ssrc_count++;
134                         }else{
135                                 session->inc_same_ssrc_count=0;
136                                 session->inc_ssrc_candidate=rtp->ssrc;
137                         }
138                         if (session->inc_same_ssrc_count>SSRC_CHANGED_THRESHOLD){
139
140                                 /* store the sender rtp address to do symmetric RTP */
141                                 if (!session->use_connect){
142                                         if (session->rtp.socket>0 && session->symmetric_rtp){
143                                                 /* store the sender rtp address to do symmetric RTP */
144                                                 memcpy(&session->rtp.rem_addr,addr,addrlen);
145                                                 session->rtp.rem_addrlen=addrlen;
146                                         }
147                                 }
148                                 session->rtp.rcv_last_ts = rtp->timestamp;
149                                 session->rcv.ssrc=rtp->ssrc;
150                                 rtp_signal_table_emit(&session->on_ssrc_changed);
151                         }else{
152                                 /*discard the packet*/
153                                 ortp_debug("Receiving packet with unknown ssrc.");
154                                 stats->bad++;
155                                 ortp_global_stats.bad++;
156                                 freemsg(mp);
157                                 return;
158                         }
159                 }
160     else{
161                         /* The SSRC change must not happen if we still receive
162                         ssrc from the initial source. */
163                         session->inc_same_ssrc_count=0;
164                 }
165
166         }else{
167                 session->ssrc_set=TRUE;
168                 session->rcv.ssrc=rtp->ssrc;
169
170                 if (!session->use_connect){
171                         if (session->rtp.socket>0 && session->symmetric_rtp){
172                                 /* store the sender rtp address to do symmetric RTP */
173                                 memcpy(&session->rtp.rem_addr,addr,addrlen);
174                                 session->rtp.rem_addrlen=addrlen;
175                         }
176                 }
177         }
178         
179         /* update some statistics */
180         {
181                 poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq;
182                 if (rtp->seq_number>extseq->split.lo){
183                         extseq->split.lo=rtp->seq_number;
184                 }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){
185                         /* this is a check for sequence number looping */
186                         extseq->split.lo=rtp->seq_number;
187                         extseq->split.hi++;
188                 }
189         }
190         
191         /* check for possible telephone events */
192         if (rtp->paytype==session->rcv.telephone_events_pt){
193                 queue_packet(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i);
194                 stats->discarded+=i;
195                 ortp_global_stats.discarded+=i;
196                 return;
197         }
198         
199         /* check for possible payload type change, in order to update accordingly our clock-rate dependant
200         parameters */
201         if (session->hw_recv_pt!=rtp->paytype){
202                 rtp_session_update_payload_type(session,rtp->paytype);
203         }
204         
205         jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts);
206
207         if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) {
208                 /* detect timestamp important jumps in the future, to workaround stupid rtp senders */
209                 if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
210                         ortp_debug("rtp_parse: timestamp jump ?");
211                         rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp);
212                 }
213                 else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){
214                         /* don't queue packets older than the last returned packet to the application*/
215                         /* Call timstamp jumb in case of
216                          * large negative Ts jump or if ts is set to 0
217                         */
218                         
219                         if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){
220                                 ortp_warning("rtp_parse: negative timestamp jump");
221                                 rtp_signal_table_emit2(&session->on_timestamp_jump,
222                                                         (long)&rtp->timestamp);
223                         }
224                         ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
225                         freemsg(mp);
226                         stats->outoftime++;
227                         ortp_global_stats.outoftime++;
228                         return;
229                 }
230         }
231         
232         queue_packet(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
233         stats->discarded+=i;
234         ortp_global_stats.discarded+=i;
235 }
236