src/rtpparse.c

00001 /*
00002   The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) stack.
00003   Copyright (C) 2001  Simon MORLAT simon.morlat@linphone.org
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014 
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the Free Software
00017   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00020 
00021 #include <ortp/ortp.h>
00022 #include "jitterctl.h"
00023 #include "utils.h"
00024 #include "rtpsession_priv.h"
00025 
00026 #define SSRC_CHANGED_THRESHOLD 50
00027 
00028 void split_and_queue(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded)
00029 {
00030         mblk_t *mdata,*tmp;
00031         int header_size;
00032         *discarded=0;
00033         header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc);
00034         if ((mp->b_wptr - mp->b_rptr)==header_size){
00035                 ortp_debug("Rtp packet contains no data.");
00036                 (*discarded)++;
00037                 freemsg(mp);
00038                 return;
00039         }
00040         /* creates a new mblk_t to be linked with the rtp header*/
00041         mdata=dupb(mp);
00042         
00043         mp->b_wptr=mp->b_rptr+header_size;
00044         mdata->b_rptr+=header_size;
00045         /* link proto with data */
00046         mp->b_cont=mdata;
00047         /* and then add the packet to the queue */
00048         
00049         rtp_putq(q,mp);
00050         /* make some checks: q size must not exceed RtpStream::max_rq_size */
00051         while (q->q_mcount > maxrqsz)
00052         {
00053                 /* remove the oldest mblk_t */
00054                 tmp=getq(q);
00055                 if (mp!=NULL)
00056                 {
00057                         ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp);
00058                         freemsg(tmp);
00059                         (*discarded)++;
00060                 }
00061         }
00062 }
00063 
00064 void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
00065 {
00066         int i;
00067         rtp_header_t *rtp;
00068         int msgsize;
00069         RtpStream *rtpstream=&session->rtp;
00070         rtp_stats_t *stats=&rtpstream->stats;
00071         
00072         msgsize=mp->b_wptr-mp->b_rptr;
00073 
00074         if (msgsize<RTP_FIXED_HEADER_SIZE){
00075                 ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize);
00076                 rtpstream->stats.bad++;
00077                 ortp_global_stats.bad++;
00078                 freemsg(mp);
00079                 return;
00080         }
00081         rtp=(rtp_header_t*)mp->b_rptr;
00082         if (rtp->version!=2)
00083         {
00084                 /* try to see if it is a STUN packet */
00085                 uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t)));
00086                 stunlen = ntohs(stunlen);
00087                 if (stunlen+20==mp->b_wptr-mp->b_rptr){
00088                         /* this looks like a stun packet */
00089                         if (session->eventqs!=NULL){
00090                                 OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED);
00091                                 OrtpEventData *ed=ortp_event_get_data(ev);
00092                                 ed->packet=mp;
00093                                 ed->ep=rtp_endpoint_new(addr,addrlen);
00094                                 rtp_session_dispatch_event(session,ev);
00095                                 return;
00096                         }
00097                 }else{
00098                         /* discard*/
00099                         ortp_debug("Receiving rtp packet with version number !=2...discarded");
00100                         stats->bad++;
00101                         ortp_global_stats.bad++;
00102                         freemsg(mp);
00103                         return;
00104                 }
00105         }
00106 
00107         /* only count non-stun packets. */
00108         ortp_global_stats.packet_recv++;
00109         stats->packet_recv++;
00110         ortp_global_stats.hw_recv+=msgsize;
00111         stats->hw_recv+=msgsize;
00112         session->rtp.hwrcv_since_last_SR++;
00113 
00114         
00115         /* convert all header data from network order to host order */
00116         rtp->seq_number=ntohs(rtp->seq_number);
00117         rtp->timestamp=ntohl(rtp->timestamp);
00118         rtp->ssrc=ntohl(rtp->ssrc);
00119         /* convert csrc if necessary */
00120         if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){
00121                 ortp_debug("Receiving too short rtp packet.");
00122                 stats->bad++;
00123                 ortp_global_stats.bad++;
00124                 freemsg(mp);
00125                 return;
00126         }
00127 
00128 #ifndef PERF
00129         /* Write down the last RTP/RTCP packet reception time. */
00130         gettimeofday(&session->last_recv_time, NULL);
00131 #endif
00132 
00133         for (i=0;i<rtp->cc;i++)
00134                 rtp->csrc[i]=ntohl(rtp->csrc[i]);
00135         /*the goal of the following code is to lock on an incoming SSRC to avoid
00136         receiving "mixed streams"*/
00137         if (session->ssrc_set){
00138                 /*the ssrc is set, so we must check it */
00139                 if (session->rcv.ssrc!=rtp->ssrc){
00140                         if (session->inc_ssrc_candidate==rtp->ssrc){
00141                                 session->inc_same_ssrc_count++;
00142                         }else{
00143                                 session->inc_same_ssrc_count=0;
00144                                 session->inc_ssrc_candidate=rtp->ssrc;
00145                         }
00146                         if (session->inc_same_ssrc_count>SSRC_CHANGED_THRESHOLD){
00147                                 session->rcv.ssrc=rtp->ssrc;
00148                                 rtp_signal_table_emit(&session->on_ssrc_changed);
00149                         }else{
00150                                 /*discard the packet*/
00151                                 ortp_debug("Receiving packet with unknown ssrc.");
00152                                 stats->bad++;
00153                                 ortp_global_stats.bad++;
00154                                 freemsg(mp);
00155                                 return;
00156                         }
00157                 }
00158         }else{
00159                 session->ssrc_set=TRUE;
00160                 session->rcv.ssrc=rtp->ssrc;
00161         }
00162         
00163         /* update some statistics */
00164         {
00165                 poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq;
00166                 if (rtp->seq_number>extseq->split.lo){
00167                         extseq->split.lo=rtp->seq_number;
00168                 }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){
00169                         /* this is a check for sequence number looping */
00170                         extseq->split.lo=rtp->seq_number;
00171                         extseq->split.hi++;
00172                 }
00173         }
00174         
00175         /* check for possible telephone events */
00176         if (rtp->paytype==session->rcv.telephone_events_pt){
00177                 split_and_queue(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i);
00178                 stats->discarded+=i;
00179                 ortp_global_stats.discarded+=i;
00180                 return;
00181         }
00182         
00183         /* check for possible payload type change, in order to update accordingly our clock-rate dependant
00184         parameters */
00185         if (session->hw_recv_pt!=rtp->paytype){
00186                 rtp_session_update_payload_type(session,rtp->paytype);
00187         }
00188         
00189         if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) {
00190                 int32_t slide=0;
00191                 int32_t safe_delay=0;
00192                 jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts,&slide,&safe_delay);
00193                 
00194                 session->rtp.rcv_diff_ts=session->rtp.hwrcv_diff_ts + slide - safe_delay;
00195                 ortp_debug("  rcv_diff_ts=%i", session->rtp.rcv_diff_ts);
00196                 
00197                 /* detect timestamp important jumps in the future, to workaround stupid rtp senders */
00198                 if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
00199                         ortp_debug("rtp_parse: timestamp jump ?");
00200                         rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp);
00201                 }
00202                 else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){
00203                         /* don't queue packets older than the last returned packet to the application*/
00204                         /* Call timstamp jumb in case of
00205                          * large negative Ts jump or if ts is set to 0
00206                         */
00207                         
00208                         if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){
00209                                 ortp_warning("rtp_parse: negative timestamp jump");
00210                                 rtp_signal_table_emit2(&session->on_timestamp_jump,
00211                                                         (long)&rtp->timestamp);
00212                         }
00213                         ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
00214                         freemsg(mp);
00215                         stats->outoftime++;
00216                         ortp_global_stats.outoftime++;
00217                         return;
00218                 }
00219                 
00220         }
00221         
00222         split_and_queue(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
00223         stats->discarded+=i;
00224         ortp_global_stats.discarded+=i;
00225 }

Generated on Thu Feb 14 16:10:27 2008 for oRTP by  doxygen 1.5.4