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 
00027 void split_and_queue(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded)
00028 {
00029         mblk_t *mdata,*tmp;
00030         int header_size;
00031         *discarded=0;
00032         header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc);
00033         if ((mp->b_wptr - mp->b_rptr)==header_size){
00034                 ortp_debug("Rtp packet contains no data.");
00035                 (*discarded)++;
00036                 freemsg(mp);
00037                 return;
00038         }
00039         /* creates a new mblk_t to be linked with the rtp header*/
00040         mdata=dupb(mp);
00041         
00042         mp->b_wptr=mp->b_rptr+header_size;
00043         mdata->b_rptr+=header_size;
00044         /* link proto with data */
00045         mp->b_cont=mdata;
00046         /* and then add the packet to the queue */
00047         
00048         rtp_putq(q,mp);
00049         /* make some checks: q size must not exceed RtpStream::max_rq_size */
00050         while (q->q_mcount > maxrqsz)
00051         {
00052                 /* remove the oldest mblk_t */
00053                 tmp=getq(q);
00054                 if (mp!=NULL)
00055                 {
00056                         ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp);
00057                         freemsg(tmp);
00058                         (*discarded)++;
00059                 }
00060         }
00061 }
00062 
00063 void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
00064 {
00065         int i;
00066         rtp_header_t *rtp;
00067         int msgsize;
00068         RtpStream *rtpstream=&session->rtp;
00069         rtp_stats_t *stats=&rtpstream->stats;
00070         
00071         return_if_fail(mp!=NULL);
00072         
00073         msgsize=msgdsize(mp);
00074 
00075         if (msgsize<RTP_FIXED_HEADER_SIZE){
00076                 ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize);
00077                 rtpstream->stats.bad++;
00078                 ortp_global_stats.bad++;
00079                 freemsg(mp);
00080                 return;
00081         }
00082         rtp=(rtp_header_t*)mp->b_rptr;
00083         if (rtp->version!=2)
00084         {
00085                 /* try to see if it is a STUN packet */
00086                 uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t)));
00087                 stunlen = ntohs(stunlen);
00088                 if (stunlen+20==mp->b_wptr-mp->b_rptr){
00089                         /* this looks like a stun packet */
00090                         if (session->eventqs!=NULL){
00091                                 OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED);
00092                                 OrtpEventData *ed=ortp_event_get_data(ev);
00093                                 ed->packet=mp;
00094                                 ed->ep=rtp_endpoint_new(addr,addrlen);
00095                                 rtp_session_dispatch_event(session,ev);
00096                                 return;
00097                         }
00098                 }
00099                 freemsg(mp);
00100                 return;
00101         }
00102 
00103         /* only count non-stun packets. */
00104         ortp_global_stats.packet_recv++;
00105         stats->packet_recv++;
00106         ortp_global_stats.hw_recv+=msgsize;
00107         stats->hw_recv+=msgsize;
00108         session->rtp.hwrcv_since_last_SR++;
00109 
00110         if (rtp->version!=2)
00111         {
00112                 /* discard*/
00113                 ortp_debug("Receiving rtp packet with version number !=2...discarded");
00114                 stats->bad++;
00115                 ortp_global_stats.bad++;
00116                 freemsg(mp);
00117                 return;
00118         }
00119         
00120         /* convert all header data from network order to host order */
00121         rtp->seq_number=ntohs(rtp->seq_number);
00122         rtp->timestamp=ntohl(rtp->timestamp);
00123         rtp->ssrc=ntohl(rtp->ssrc);
00124         /* convert csrc if necessary */
00125         if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){
00126                 ortp_debug("Receiving too short rtp packet.");
00127                 stats->bad++;
00128                 ortp_global_stats.bad++;
00129                 freemsg(mp);
00130                 return;
00131         }
00132 
00133         /* Write down the last RTP/RTCP packet reception time. */
00134         gettimeofday(&session->last_recv_time, NULL);
00135 
00136         for (i=0;i<rtp->cc;i++)
00137                 rtp->csrc[i]=ntohl(rtp->csrc[i]);
00138         if (session->rcv.ssrc!=0)
00139         {
00140                 /*the ssrc is set, so we must check it */
00141                 if (session->rcv.ssrc!=rtp->ssrc){
00142                         /*ortp_debug("rtp_parse: bad ssrc - %i",rtp->ssrc);*/
00143                         session->rcv.ssrc=rtp->ssrc;
00144                         rtp_signal_table_emit(&session->on_ssrc_changed);
00145                 }
00146         }else session->rcv.ssrc=rtp->ssrc;
00147         
00148         /* update some statistics */
00149         {
00150                 poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq;
00151                 if (rtp->seq_number>extseq->split.lo){
00152                         extseq->split.lo=rtp->seq_number;
00153                 }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){
00154                         /* this is a check for sequence number looping */
00155                         extseq->split.lo=rtp->seq_number;
00156                         extseq->split.hi++;
00157                 }
00158         }
00159         
00160         /* check for possible telephone events */
00161         if (rtp->paytype==session->rcv.telephone_events_pt){
00162                 split_and_queue(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i);
00163                 stats->discarded+=i;
00164                 ortp_global_stats.discarded+=i;
00165                 return;
00166         }
00167         
00168         /* check for possible payload type change, in order to update accordingly our clock-rate dependant
00169         parameters */
00170         if (session->hw_recv_pt!=rtp->paytype){
00171                 rtp_session_update_payload_type(session,rtp->paytype);
00172         }
00173         
00174         if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) {
00175                 int32_t slide=0;
00176                 int32_t safe_delay=0;
00177                 jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts,&slide,&safe_delay);
00178                 
00179                 session->rtp.rcv_diff_ts=session->rtp.hwrcv_diff_ts + slide - safe_delay;
00180                 ortp_debug("  rcv_diff_ts=%i", session->rtp.rcv_diff_ts);
00181                 
00182                 /* detect timestamp important jumps in the future, to workaround stupid rtp senders */
00183                 if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
00184                         ortp_debug("rtp_parse: timestamp jump ?");
00185                         rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp);
00186                 }
00187                 else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){
00188                         /* don't queue packets older than the last returned packet to the application*/
00189                         /* Call timstamp jumb in case of
00190                          * large negative Ts jump or if ts is set to 0
00191                         */
00192                         
00193                         if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){
00194                                 ortp_warning("rtp_parse: negative timestamp jump");
00195                                 rtp_signal_table_emit2(&session->on_timestamp_jump,
00196                                                         (long)&rtp->timestamp);
00197                         }
00198                         ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
00199                         freemsg(mp);
00200                         stats->outoftime++;
00201                         ortp_global_stats.outoftime++;
00202                         return;
00203                 }
00204                 
00205         }
00206         
00207         split_and_queue(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
00208         stats->discarded+=i;
00209         ortp_global_stats.discarded+=i;
00210 }

Generated on Fri Jun 22 17:30:30 2007 for oRTP by  doxygen 1.5.2