2 The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
3 Copyright (C) 2001 Simon MORLAT simon.morlat@linphone.org
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.
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.
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
21 #include <ortp/ortp.h>
22 #include "jitterctl.h"
24 #include "rtpsession_priv.h"
26 #define SSRC_CHANGED_THRESHOLD 50
28 static void queue_packet(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded)
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.");
40 /* and then add the packet to the queue */
43 /* make some checks: q size must not exceed RtpStream::max_rq_size */
44 while (q->q_mcount > maxrqsz)
46 /* remove the oldest mblk_t */
50 ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp);
57 void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
62 RtpStream *rtpstream=&session->rtp;
63 rtp_stats_t *stats=&rtpstream->stats;
65 msgsize=mp->b_wptr-mp->b_rptr;
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++;
74 rtp=(rtp_header_t*)mp->b_rptr;
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);
86 ed->ep=rtp_endpoint_new(addr,addrlen);
87 rtp_session_dispatch_event(session,ev);
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");
94 ortp_global_stats.bad++;
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++;
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.");
115 ortp_global_stats.bad++;
121 /* Write down the last RTP/RTCP packet reception time. */
122 gettimeofday(&session->last_recv_time, NULL);
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++;
135 session->inc_same_ssrc_count=0;
136 session->inc_ssrc_candidate=rtp->ssrc;
138 if (session->inc_same_ssrc_count>SSRC_CHANGED_THRESHOLD){
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;
148 session->rtp.rcv_last_ts = rtp->timestamp;
149 session->rcv.ssrc=rtp->ssrc;
150 rtp_signal_table_emit(&session->on_ssrc_changed);
152 /*discard the packet*/
153 ortp_debug("Receiving packet with unknown ssrc.");
155 ortp_global_stats.bad++;
161 /* The SSRC change must not happen if we still receive
162 ssrc from the initial source. */
163 session->inc_same_ssrc_count=0;
167 session->ssrc_set=TRUE;
168 session->rcv.ssrc=rtp->ssrc;
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;
179 /* update some statistics */
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;
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);
195 ortp_global_stats.discarded+=i;
199 /* check for possible payload type change, in order to update accordingly our clock-rate dependant
201 if (session->hw_recv_pt!=rtp->paytype){
202 rtp_session_update_payload_type(session,rtp->paytype);
205 jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts);
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);
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
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);
224 ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
227 ortp_global_stats.outoftime++;
232 queue_packet(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
234 ortp_global_stats.discarded+=i;