static bool_t queue_packet(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded) { mblk_t *tmp; int header_size; *discarded=0; header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc); if ((mp->b_wptr - mp->b_rptr)==header_size){ ortp_debug("Rtp packet contains no data."); (*discarded)++; freemsg(mp); return FALSE; } /* and then add the packet to the queue */ rtp_putq(q,mp); /* make some checks: q size must not exceed RtpStream::max_rq_size */ while (q->q_mcount > maxrqsz) { /* remove the oldest mblk_t */ tmp=getq(q); if (mp!=NULL) { ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp); freemsg(tmp); (*discarded)++; } } return TRUE; }
void split_and_queue(queue_t *q, int maxrqsz, mblk_t *mp, rtp_header_t *rtp, int *discarded) { mblk_t *mdata,*tmp; int header_size; *discarded=0; header_size=RTP_FIXED_HEADER_SIZE+ (4*rtp->cc); if ((mp->b_wptr - mp->b_rptr)==header_size){ ortp_debug("Rtp packet contains no data."); (*discarded)++; freemsg(mp); return; } /* creates a new mblk_t to be linked with the rtp header*/ mdata=dupb(mp); mp->b_wptr=mp->b_rptr+header_size; mdata->b_rptr+=header_size; /* link proto with data */ mp->b_cont=mdata; /* and then add the packet to the queue */ rtp_putq(q,mp); /* make some checks: q size must not exceed RtpStream::max_rq_size */ while (q->q_mcount > maxrqsz) { /* remove the oldest mblk_t */ tmp=getq(q); if (mp!=NULL) { ortp_debug("rtp_putq: Queue is full. Discarding message with ts=%i",((rtp_header_t*)mp->b_rptr)->timestamp); freemsg(tmp); (*discarded)++; } } }
mblk_t *rtp_getq(queue_t *q,guint32 timestamp, int *rejected) { mblk_t *tmp,*ret=NULL,*old; rtp_header_t *tmprtp; guint32 oldest; guint32 ts_found=0; *rejected=0; ortp_debug("rtp_getq(): Timestamp %i wanted.",timestamp); if (qempty(q)) { /*ortp_debug("rtp_getq: q is empty.");*/ return NULL; } /* prevent somebody to ask for a timestamp that is older than the oldest of the queue */ oldest=((rtp_header_t*) qfirst(q)->b_rptr)->timestamp; if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(oldest,timestamp)) { ortp_debug("rtp_getq(): asking for too old packet ! oldest=%i",oldest); return NULL; } ret=NULL; old=NULL; /* return the packet with ts just equal or older than the asked timestamp */ while ((tmp=qfirst(q))!=NULL) { tmprtp=(rtp_header_t*)tmp->b_rptr; ortp_debug("rtp_getq: Seeing packet with ts=%i",tmprtp->timestamp); if ( RTP_TIMESTAMP_IS_NEWER_THAN(timestamp,tmprtp->timestamp) ) { if (ret!=NULL && tmprtp->timestamp==ts_found) { /* we've found two packets with same timestamp. return the first one */ break; } if (old!=NULL) { ortp_debug("rtp_getq: discarding too old packet with ts=%i",ts_found); (*rejected)++; freemsg(old); } ret=getq(q); /* dequeue the packet, since it has an interesting timestamp*/ ts_found=tmprtp->timestamp; ortp_debug("rtp_getq: Found packet with ts=%i",tmprtp->timestamp); old=ret; } else { break; } } return ret; }
gpointer rtp_scheduler_schedule(gpointer psched) { RtpScheduler *sched=(RtpScheduler*) psched; RtpTimer *timer=sched->timer; RtpSession *current; int err; /* try to get the real time priority by getting root*/ #ifndef _WIN32 #ifdef HAVE_SETEUID err=seteuid(0); #else err=setuid(0); #endif if (err<0) g_message("Could not get root euid: %s",strerror(errno)); #endif g_message("scheduler: trying to reach real time kernel scheduling..."); /* take this lock to prevent the thread to start until g_thread_create() returns because we need sched->thread to be initialized */ g_mutex_lock(sched->lock); g_cond_signal(sched->unblock_select_cond); /* unblock the starting thread */ g_mutex_unlock(sched->lock); g_thread_set_priority(sched->thread,G_THREAD_PRIORITY_HIGH); timer->timer_init(); while(sched->thread_running) { /* do the processing here: */ g_mutex_lock(sched->lock); current=sched->list; /* processing all scheduled rtp sessions */ while (current!=NULL) { ortp_debug("scheduler: processing session=%p.\n",current); rtp_session_process(current,sched->time_,sched); current=current->next; } /* wake up all the threads that are sleeping in _select() */ g_cond_broadcast(sched->unblock_select_cond); g_mutex_unlock(sched->lock); /* now while the scheduler is going to sleep, the other threads can compute their result mask and see if they have to leave, or to wait for next tick*/ //g_message("scheduler: sleeping."); timer->timer_do(); sched->time_+=sched->timer_inc; } /* when leaving the thread, stop the timer */ timer->timer_uninit(); return NULL; }
/* put an rtp packet in queue. It is called by rtp_parse()*/ void rtp_putq(queue_t *q, mblk_t *mp) { mblk_t *tmp; rtp_header_t *rtp=(rtp_header_t*)mp->b_rptr,*tmprtp; /* insert message block by increasing time stamp order : the last (at the bottom) message of the queue is the newest*/ ortp_debug("rtp_putq(): Enqueuing packet with ts=%i and seq=%i",rtp->timestamp,rtp->seq_number); if (qempty(q)) { putq(q,mp); return; } tmp=qlast(q); /* we look at the queue from bottom to top, because enqueued packets have a better chance to be enqueued at the bottom, since there are surely newer */ while (!qend(q,tmp)) { tmprtp=(rtp_header_t*)tmp->b_rptr; ortp_debug("rtp_putq(): Seeing packet with seq=%i",tmprtp->seq_number); if (rtp->seq_number == tmprtp->seq_number) { /* this is a duplicated packet. Don't queue it */ ortp_debug("rtp_putq: duplicated message."); freemsg(mp); return; }else if (RTP_SEQ_IS_GREATER(rtp->seq_number,tmprtp->seq_number)){ insq(q,tmp->b_next,mp); return; } tmp=tmp->b_prev; } /* this packet is the oldest, it has to be placed on top of the queue */ insq(q,qfirst(q),mp); }
void rtp_session_rtcp_process_send(RtpSession *session){ RtpStream *st=&session->rtp; RtcpStream *rtcp_st=&session->rtcp; mblk_t *m; if (st->rcv_last_app_ts - rtcp_st->last_rtcp_report_snt_r > rtcp_st->rtcp_report_snt_interval_r || st->snd_last_ts - rtcp_st->last_rtcp_report_snt_s > rtcp_st->rtcp_report_snt_interval_s){ rtcp_st->last_rtcp_report_snt_r=st->rcv_last_app_ts; rtcp_st->last_rtcp_report_snt_s=st->snd_last_ts; m=make_sr(session); /* send the compound packet */ notify_sent_rtcp(session,m); rtp_session_rtcp_send(session,m); ortp_debug("Rtcp compound message sent."); } }
void * rtp_scheduler_schedule(void * psched) { RtpScheduler *sched=(RtpScheduler*) psched; RtpTimer *timer=sched->timer; RtpSession *current; /* take this lock to prevent the thread to start until g_thread_create() returns because we need sched->thread to be initialized */ ortp_mutex_lock(&sched->lock); ortp_cond_signal(&sched->unblock_select_cond); /* unblock the starting thread */ ortp_mutex_unlock(&sched->lock); timer->timer_init(); while(sched->thread_running) { /* do the processing here: */ ortp_mutex_lock(&sched->lock); current=sched->list; /* processing all scheduled rtp sessions */ while (current!=NULL) { ortp_debug("scheduler: processing session=0x%x.\n",current); rtp_session_process(current,sched->time_,sched); current=current->next; } /* wake up all the threads that are sleeping in _select() */ ortp_cond_broadcast(&sched->unblock_select_cond); ortp_mutex_unlock(&sched->lock); /* now while the scheduler is going to sleep, the other threads can compute their result mask and see if they have to leave, or to wait for next tick*/ //ortp_message("scheduler: sleeping."); timer->timer_do(); sched->time_+=sched->timer_inc; } /* when leaving the thread, stop the timer */ timer->timer_uninit(); return NULL; }
void __rtp_session_rtcp_process(RtpSession *session){ mblk_t *cm=NULL; mblk_t *sdes=NULL; if (session->mode==RTP_SESSION_SENDONLY || session->mode==RTP_SESSION_SENDRECV){ /* first make a SR packet */ cm=allocb(sizeof(rtcp_sr_t),0); cm->b_wptr+=rtcp_sr_init(session,cm->b_wptr,sizeof(rtcp_sr_t)); /* make a SDES packet */ sdes=rtp_session_create_rtcp_sdes_packet(session); /* link them */ cm->b_cont=sdes; }else{ /* make a RR packet */ cm=allocb(sizeof(rtcp_rr_t),0); cm->b_wptr+=rtcp_rr_init(session,cm->b_wptr,sizeof(rtcp_rr_t)); /* if we are recv-only do we need to add SDES packet ? I don't think so as we are not a source */ } /* send the compound packet */ ortp_rtcp_send(session,cm); ortp_debug("Rtcp compound message sent."); }
void rtp_session_rtcp_process_recv(RtpSession *session){ RtpStream *st=&session->rtp; RtcpStream *rtcp_st=&session->rtcp; mblk_t *m=NULL; if (st->rcv_last_app_ts - rtcp_st->last_rtcp_report_snt_r > rtcp_st->rtcp_report_snt_interval_r || st->snd_last_ts - rtcp_st->last_rtcp_report_snt_s > rtcp_st->rtcp_report_snt_interval_s){ rtcp_st->last_rtcp_report_snt_r=st->rcv_last_app_ts; rtcp_st->last_rtcp_report_snt_s=st->snd_last_ts; if (session->rtp.last_rtcp_packet_count<session->rtp.stats.packet_sent){ m=make_sr(session); session->rtp.last_rtcp_packet_count=session->rtp.stats.packet_sent; }else if (session->rtp.stats.packet_recv>0){ /*don't send RR when no packet are received yet*/ m=make_rr(session); } if (m!=NULL){ /* send the compound packet */ notify_sent_rtcp(session,m); rtp_session_rtcp_send(session,m); ortp_debug("Rtcp compound message sent."); } } }
Socket openPort( unsigned short port, unsigned int interfaceIp ) { struct sockaddr_in addr; Socket fd; fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if ( fd == INVALID_SOCKET ) { ortp_error("stun_udp: Could not create a UDP socket"); return INVALID_SOCKET; } memset((char*) &(addr),0, sizeof((addr))); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if ( (interfaceIp != 0) && ( interfaceIp != 0x100007f ) ) { addr.sin_addr.s_addr = htonl(interfaceIp); //ortp_debug("Binding to interface 0x%lu\n",(unsigned long) htonl(interfaceIp)); } if ( bind( fd,(struct sockaddr*)&addr, sizeof(addr)) != 0 ) { int e = getErrno(); switch (e) { case 0: { ortp_error("stun_udp: Could not bind socket");; return INVALID_SOCKET; } case EADDRINUSE: { ortp_error("stun_udp: Port %i for receiving UDP is in use", port); return INVALID_SOCKET; } break; case EADDRNOTAVAIL: { ortp_error("stun_udp: Cannot assign requested address"); return INVALID_SOCKET; } break; default: { #if !defined(_WIN32_WCE) ortp_error("stun_udp: Could not bind UDP receive port Error=%i %s", e, strerror(e)); #else ortp_error("stun_udp: Could not bind UDP receive port Error=%i", e); #endif return INVALID_SOCKET; } break; } } ortp_debug("stun: opened port %i with fd %i\n", port, fd); /* assert( fd != INVALID_SOCKET ); */ return fd; }
static void report_block_init(report_block_t *b, RtpSession *session){ int64_t packet_loss=0; int loss_fraction=0; RtpStream *stream=&session->rtp; uint32_t delay_snc_last_sr=0; /* compute the statistics */ if (stream->hwrcv_since_last_SR!=0){ int expected_packets=stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR; if ( session->flags & RTCP_OVERRIDE_LOST_PACKETS ) { /* If the test mode is enabled, replace the lost packet field with the test vector value set by rtp_session_rtcp_set_lost_packet_value() */ packet_loss = session->lost_packets_test_vector; /* The test value is the definite cumulative one, no need to increment it each time a packet is sent */ session->stats.cum_packet_loss = packet_loss; }else { /* Normal mode */ packet_loss = expected_packets - stream->hwrcv_since_last_SR; session->stats.cum_packet_loss += packet_loss; } if (expected_packets>0){/*prevent division by zero and negative loss fraction*/ loss_fraction=(int)( 256 * packet_loss) / expected_packets; /*make sure this fits into 8 bit unsigned*/ if (loss_fraction>255) loss_fraction=255; else if (loss_fraction<0) loss_fraction=0; }else{ loss_fraction=0; } } ortp_debug("report_block_init[%p]:\n" "\texpected_packets=%d=%u-%u\n" "\thwrcv_since_last_SR=%u\n" "\tpacket_loss=%d\n" "\tcum_packet_loss=%ld\n" "\tloss_fraction=%f%%\n" , session , stream->hwrcv_extseq - stream->hwrcv_seq_at_last_SR, stream->hwrcv_extseq, stream->hwrcv_seq_at_last_SR , stream->hwrcv_since_last_SR , packet_loss , (long)session->stats.cum_packet_loss , loss_fraction/2.56 ); /* reset them */ stream->hwrcv_since_last_SR=0; stream->hwrcv_seq_at_last_SR=stream->hwrcv_extseq; if (stream->last_rcv_SR_time.tv_sec!=0){ struct timeval now; double delay; ortp_gettimeofday(&now,NULL); delay= (now.tv_sec-stream->last_rcv_SR_time.tv_sec)+ ((now.tv_usec-stream->last_rcv_SR_time.tv_usec)*1e-6); delay= (delay*65536); delay_snc_last_sr=(uint32_t) delay; } b->ssrc=htonl(session->rcv.ssrc); report_block_set_cum_packet_lost(b, session->stats.cum_packet_loss); report_block_set_fraction_lost(b, loss_fraction); if ( session->flags & RTCP_OVERRIDE_JITTER ) { /* If the test mode is enabled, replace the interarrival jitter field with the test vector value set by rtp_session_rtcp_set_jitter_value() */ b->interarrival_jitter = htonl( session->interarrival_jitter_test_vector ); } else { /* Normal mode */ b->interarrival_jitter = htonl( (uint32_t) stream->jittctl.inter_jitter ); } b->ext_high_seq_num_rec=htonl(stream->hwrcv_extseq); b->delay_snc_last_sr=htonl(delay_snc_last_sr); if ( session->flags & RTCP_OVERRIDE_DELAY ) { /* If the test mode is enabled, modifies the returned ts (LSR) so it matches the value of the delay test value */ /* refer to the rtp_session_rtcp_set_delay_value() documentation for further explanations */ double new_ts = ( (double)stream->last_rcv_SR_time.tv_sec + (double)stream->last_rcv_SR_time.tv_usec * 1e-6 ) - ( (double)session->delay_test_vector / 1000.0 ); uint32_t new_ts2; /* Converting the time format in RFC3550 (par. 4) format */ new_ts += 2208988800.0; /* 2208988800 is the number of seconds from 1900 to 1970 (January 1, Oh TU) */ new_ts = 65536.0 * new_ts; /* This non-elegant way of coding fits with the gcc and the icc compilers */ new_ts2 = (uint32_t)( (uint64_t)new_ts & 0xffffffff ); b->lsr = htonl( new_ts2 ); } else { /* Normal mode */ b->lsr = htonl( stream->last_rcv_SR_ts ); } }
void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen) { int i; int discarded; int duplicate; rtp_header_t *rtp; int msgsize; RtpStream *rtpstream=&session->rtp; rtp_stats_t *stats=&rtpstream->stats; msgsize=(int)(mp->b_wptr-mp->b_rptr); if (msgsize<RTP_FIXED_HEADER_SIZE){ ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize); rtpstream->stats.bad++; ortp_global_stats.bad++; freemsg(mp); return; } rtp=(rtp_header_t*)mp->b_rptr; if (rtp->version!=2) { /* try to see if it is a STUN packet */ uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t))); stunlen = ntohs(stunlen); if (stunlen+20==mp->b_wptr-mp->b_rptr){ /* this looks like a stun packet */ if (session->eventqs!=NULL){ OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED); OrtpEventData *ed=ortp_event_get_data(ev); ed->packet=mp; memcpy(&ed->source_addr,addr,addrlen); ed->source_addrlen=addrlen; ed->info.socket_type = OrtpRTPSocket; rtp_session_dispatch_event(session,ev); return; } } /* discard in two case: the packet is not stun OR nobody is interested by STUN (no eventqs) */ ortp_debug("Receiving rtp packet with version number !=2...discarded"); stats->bad++; ortp_global_stats.bad++; freemsg(mp); return; } /* only count non-stun packets. */ ortp_global_stats.packet_recv++; stats->packet_recv++; ortp_global_stats.hw_recv+=msgsize; stats->hw_recv+=msgsize; session->rtp.hwrcv_since_last_SR++; session->rtcp_xr_stats.rcv_since_last_stat_summary++; /* convert all header data from network order to host order */ rtp->seq_number=ntohs(rtp->seq_number); rtp->timestamp=ntohl(rtp->timestamp); rtp->ssrc=ntohl(rtp->ssrc); /* convert csrc if necessary */ if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){ ortp_debug("Receiving too short rtp packet."); stats->bad++; ortp_global_stats.bad++; freemsg(mp); return; } #ifndef PERF /* Write down the last RTP/RTCP packet reception time. */ ortp_gettimeofday(&session->last_recv_time, NULL); #endif for (i=0;i<rtp->cc;i++) rtp->csrc[i]=ntohl(rtp->csrc[i]); /*the goal of the following code is to lock on an incoming SSRC to avoid receiving "mixed streams"*/ if (session->ssrc_set){ /*the ssrc is set, so we must check it */ if (session->rcv.ssrc!=rtp->ssrc){ if (session->inc_ssrc_candidate==rtp->ssrc){ session->inc_same_ssrc_count++; }else{ session->inc_same_ssrc_count=0; session->inc_ssrc_candidate=rtp->ssrc; } if (session->inc_same_ssrc_count>=session->rtp.ssrc_changed_thres){ /* store the sender rtp address to do symmetric RTP */ if (!session->use_connect){ if (session->rtp.gs.socket>0 && session->symmetric_rtp){ /* store the sender rtp address to do symmetric RTP */ memcpy(&session->rtp.gs.rem_addr,addr,addrlen); session->rtp.gs.rem_addrlen=addrlen; } } session->rtp.rcv_last_ts = rtp->timestamp; session->rcv.ssrc=rtp->ssrc; rtp_signal_table_emit(&session->on_ssrc_changed); }else{ /*discard the packet*/ ortp_debug("Receiving packet with unknown ssrc."); stats->bad++; ortp_global_stats.bad++; freemsg(mp); return; } } else{ /* The SSRC change must not happen if we still receive ssrc from the initial source. */ session->inc_same_ssrc_count=0; } }else{ session->ssrc_set=TRUE; session->rcv.ssrc=rtp->ssrc; if (!session->use_connect){ if (session->rtp.gs.socket>0 && session->symmetric_rtp){ /* store the sender rtp address to do symmetric RTP */ memcpy(&session->rtp.gs.rem_addr,addr,addrlen); session->rtp.gs.rem_addrlen=addrlen; } } } /* update some statistics */ { poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq; if (rtp->seq_number>extseq->split.lo){ extseq->split.lo=rtp->seq_number; }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){ /* this is a check for sequence number looping */ extseq->split.lo=rtp->seq_number; extseq->split.hi++; } /* the first sequence number received should be initialized at the beginning or at any resync, so that the first receiver reports contains valid loss rate*/ if (!(session->flags & RTP_SESSION_RECV_SEQ_INIT)){ rtp_session_set_flag(session, RTP_SESSION_RECV_SEQ_INIT); rtpstream->hwrcv_seq_at_last_SR=rtp->seq_number-1; session->rtcp_xr_stats.rcv_seq_at_last_stat_summary=rtp->seq_number-1; } if (stats->packet_recv==1){ session->rtcp_xr_stats.first_rcv_seq=extseq->one; } session->rtcp_xr_stats.last_rcv_seq=extseq->one; } /* check for possible telephone events */ if (rtp_profile_is_telephone_event(session->snd.profile, rtp->paytype)){ queue_packet(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&discarded,&duplicate); stats->discarded+=discarded; ortp_global_stats.discarded+=discarded; stats->packet_dup_recv+=duplicate; ortp_global_stats.packet_dup_recv+=duplicate; session->rtcp_xr_stats.discarded_count += discarded; session->rtcp_xr_stats.dup_since_last_stat_summary += duplicate; return; } /* check for possible payload type change, in order to update accordingly our clock-rate dependant parameters */ if (session->hw_recv_pt!=rtp->paytype){ rtp_session_update_payload_type(session,rtp->paytype); } /* Drop the packets while the RTP_SESSION_FLUSH flag is set. */ if (session->flags & RTP_SESSION_FLUSH) { freemsg(mp); return; } jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts); update_rtcp_xr_stat_summary(session, mp, local_str_ts); if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) { /* detect timestamp important jumps in the future, to workaround stupid rtp senders */ if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){ ortp_warning("rtp_parse: timestamp jump in the future detected."); rtp_signal_table_emit2(&session->on_timestamp_jump,&rtp->timestamp); } else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp) || RTP_SEQ_IS_STRICTLY_GREATER_THAN(session->rtp.rcv_last_seq,rtp->seq_number)){ /* don't queue packets older than the last returned packet to the application, or whose sequence number is behind the last packet returned to the application*/ /* Call timstamp jumb in case of * large negative Ts jump or if ts is set to 0 */ if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){ ortp_warning("rtp_parse: negative timestamp jump detected"); rtp_signal_table_emit2(&session->on_timestamp_jump, &rtp->timestamp); } ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp); freemsg(mp); stats->outoftime++; ortp_global_stats.outoftime++; session->rtcp_xr_stats.discarded_count++; return; } } if (queue_packet(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&discarded,&duplicate)) jitter_control_update_size(&session->rtp.jittctl,&session->rtp.rq); stats->discarded+=discarded; ortp_global_stats.discarded+=discarded; stats->packet_dup_recv+=duplicate; ortp_global_stats.packet_dup_recv+=duplicate; session->rtcp_xr_stats.discarded_count += discarded; session->rtcp_xr_stats.dup_since_last_stat_summary += duplicate; if ((discarded == 0) && (duplicate == 0)) { session->rtcp_xr_stats.rcv_count++; } }
void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen) { int i; rtp_header_t *rtp; int msgsize; RtpStream *rtpstream=&session->rtp; rtp_stats_t *stats=&rtpstream->stats; return_if_fail(mp!=NULL); msgsize=msgdsize(mp); if (msgsize<RTP_FIXED_HEADER_SIZE){ ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize); rtpstream->stats.bad++; ortp_global_stats.bad++; freemsg(mp); return; } rtp=(rtp_header_t*)mp->b_rptr; if (rtp->version!=2) { /* try to see if it is a STUN packet */ uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t))); stunlen = ntohs(stunlen); if (stunlen+20==mp->b_wptr-mp->b_rptr){ /* this looks like a stun packet */ if (session->eventqs!=NULL){ OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED); OrtpEventData *ed=ortp_event_get_data(ev); ed->packet=mp; ed->ep=rtp_endpoint_new(addr,addrlen); rtp_session_dispatch_event(session,ev); return; } } freemsg(mp); return; } /* only count non-stun packets. */ ortp_global_stats.packet_recv++; stats->packet_recv++; ortp_global_stats.hw_recv+=msgsize; stats->hw_recv+=msgsize; session->rtp.hwrcv_since_last_SR++; if (rtp->version!=2) { /* discard*/ ortp_debug("Receiving rtp packet with version number !=2...discarded"); stats->bad++; ortp_global_stats.bad++; freemsg(mp); return; } /* convert all header data from network order to host order */ rtp->seq_number=ntohs(rtp->seq_number); rtp->timestamp=ntohl(rtp->timestamp); rtp->ssrc=ntohl(rtp->ssrc); /* convert csrc if necessary */ if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){ ortp_debug("Receiving too short rtp packet."); stats->bad++; ortp_global_stats.bad++; freemsg(mp); return; } /* Write down the last RTP/RTCP packet reception time. */ gettimeofday(&session->last_recv_time, NULL); for (i=0;i<rtp->cc;i++) rtp->csrc[i]=ntohl(rtp->csrc[i]); if (session->rcv.ssrc!=0) { /*the ssrc is set, so we must check it */ if (session->rcv.ssrc!=rtp->ssrc){ /*ortp_debug("rtp_parse: bad ssrc - %i",rtp->ssrc);*/ session->rcv.ssrc=rtp->ssrc; rtp_signal_table_emit(&session->on_ssrc_changed); } }else session->rcv.ssrc=rtp->ssrc; /* update some statistics */ { poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq; if (rtp->seq_number>extseq->split.lo){ extseq->split.lo=rtp->seq_number; }else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){ /* this is a check for sequence number looping */ extseq->split.lo=rtp->seq_number; extseq->split.hi++; } } /* check for possible telephone events */ if (rtp->paytype==session->rcv.telephone_events_pt){ split_and_queue(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i); stats->discarded+=i; ortp_global_stats.discarded+=i; return; } /* check for possible payload type change, in order to update accordingly our clock-rate dependant parameters */ if (session->hw_recv_pt!=rtp->paytype){ rtp_session_update_payload_type(session,rtp->paytype); } if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) { int32_t slide=0; int32_t safe_delay=0; jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts,&slide,&safe_delay); session->rtp.rcv_diff_ts=session->rtp.hwrcv_diff_ts + slide - safe_delay; ortp_debug(" rcv_diff_ts=%i", session->rtp.rcv_diff_ts); /* detect timestamp important jumps in the future, to workaround stupid rtp senders */ if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){ ortp_debug("rtp_parse: timestamp jump ?"); rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp); } else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){ /* don't queue packets older than the last returned packet to the application*/ /* Call timstamp jumb in case of * large negative Ts jump or if ts is set to 0 */ if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){ ortp_warning("rtp_parse: negative timestamp jump"); rtp_signal_table_emit2(&session->on_timestamp_jump, (long)&rtp->timestamp); } ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp); freemsg(mp); stats->outoftime++; ortp_global_stats.outoftime++; return; } } split_and_queue(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i); stats->discarded+=i; ortp_global_stats.discarded+=i; }