static void stateful_analyzer_update(MSQosAnalyzer *objbase){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; static time_t last_measure; if (last_measure != ms_time(0)){ obj->upload_bandwidth_count++; obj->upload_bandwidth_sum+=rtp_session_get_send_bandwidth(obj->session)/1000.0; } last_measure = ms_time(0); if (obj->burst_duration_ms>0){ switch (obj->burst_state){ case MSStatefulQosAnalyzerBurstEnable:{ obj->burst_state=MSStatefulQosAnalyzerBurstInProgress; ortp_gettimeofday(&obj->start_time, NULL); rtp_session_set_duplication_ratio(obj->session, obj->burst_ratio); obj->start_seq_number=obj->last_seq_number=obj->session->rtp.snd_seq; } case MSStatefulQosAnalyzerBurstInProgress: { struct timeval now; double elapsed; ortp_gettimeofday(&now,NULL); elapsed=((now.tv_sec-obj->start_time.tv_sec)*1000.0) + ((now.tv_usec-obj->start_time.tv_usec)/1000.0); obj->last_seq_number=obj->session->rtp.snd_seq; if (elapsed > obj->burst_duration_ms){ obj->burst_state=MSStatefulQosAnalyzerBurstDisable; rtp_session_set_duplication_ratio(obj->session, 0); } } case MSStatefulQosAnalyzerBurstDisable: { } } } }
static void __ortp_logv_out(OrtpLogLevel lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; struct timeval tp; struct tm *lt; #ifndef _WIN32 struct tm tmbuf; #endif time_t tt; ortp_gettimeofday(&tp,NULL); tt = (time_t)tp.tv_sec; #ifdef _WIN32 lt = localtime(&tt); #else lt = localtime_r(&tt,&tmbuf); #endif if (__log_file==NULL) __log_file=stderr; switch(lev){ case ORTP_DEBUG: lname="debug"; break; case ORTP_MESSAGE: lname="message"; break; case ORTP_WARNING: lname="warning"; break; case ORTP_ERROR: lname="error"; break; case ORTP_FATAL: lname="fatal"; break; default: ortp_fatal("Bad level !"); } msg=ortp_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) #ifndef _UNICODE OutputDebugStringA(msg); OutputDebugStringA("\r\n"); #else { int len=strlen(msg); wchar_t *tmp=(wchar_t*)ortp_malloc0((len+1)*sizeof(wchar_t)); mbstowcs(tmp,msg,len); OutputDebugStringW(tmp); OutputDebugStringW(L"\r\n"); ortp_free(tmp); } #endif #endif fprintf(__log_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i ortp-%s-%s" ENDLINE ,1900+lt->tm_year,1+lt->tm_mon,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_sec ,(int)(tp.tv_usec/1000), lname,msg); fflush(__log_file); ortp_free(msg); }
static mblk_t * simulate_latency(RtpSession *session, mblk_t *input){ OrtpNetworkSimulatorCtx *sim=session->net_sim_ctx; struct timeval current; mblk_t *output=NULL; uint32_t current_ts; ortp_gettimeofday(¤t,NULL); /*since we must store expiration date in reserved2(32bits) only(reserved1 already used), we need to reduce time stamp to milliseconds only*/ current_ts = 1000*current.tv_sec + current.tv_usec/1000; /*queue the packet - store expiration timestamps in reserved fields*/ if (input){ input->reserved2 = current_ts + sim->params.latency; putq(&sim->latency_q,input); } if ((output=peekq(&sim->latency_q))!=NULL){ if (TIME_IS_NEWER_THAN(current_ts, output->reserved2)){ output->reserved2=0; getq(&sim->latency_q); /*return the first dequeued packet*/ return output; } } return NULL; }
static void init_random_number_generator(void){ #ifndef _WIN32 struct timeval t; ortp_gettimeofday(&t,NULL); srandom(t.tv_usec+t.tv_sec); #endif /*on windows we're using rand_s, which doesn't require initialization*/ }
static mblk_t *simulate_bandwidth_limit_and_jitter(RtpSession *session, mblk_t *input){ OrtpNetworkSimulatorCtx *sim=session->net_sim_ctx; struct timeval current; int64_t elapsed; int bits; int budget_increase; mblk_t *output=NULL; int overhead=(session->rtp.gs.sockfamily==AF_INET6) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD; ortp_gettimeofday(¤t,NULL); if (sim->last_check.tv_sec==0){ sim->last_check=current; sim->bit_budget=0; } /*update the budget */ elapsed=elapsed_us(&sim->last_check,¤t); budget_increase=(elapsed*(int64_t)sim->params.max_bandwidth)/1000000LL; sim->bit_budget+=budget_increase; sim->bit_budget+=simulate_jitter_by_bit_budget_reduction(sim,budget_increase); sim->last_check=current; /* queue the packet for sending*/ if (input){ putq(&sim->q,input); bits=(msgdsize(input)+overhead)*8; sim->qsize+=bits; } /*flow control*/ while (sim->qsize>=sim->params.max_buffer_size){ // ortp_message("rtp_session_network_simulate(): discarding packets."); output=getq(&sim->q); if (output){ bits=(msgdsize(output)+overhead)*8; sim->qsize-=bits; sim->drop_by_congestion++; freemsg(output); } } output=NULL; /*see if we can output a packet*/ if (sim->bit_budget>=0){ output=getq(&sim->q); if (output){ bits=(msgdsize(output)+overhead)*8; sim->bit_budget-=bits; sim->qsize-=bits; } } if (output==NULL && input==NULL && sim->bit_budget>=0){ /* unused budget is lost...*/ sim->last_check.tv_sec=0; } return output; }
/** * Activate timer. * * @param ctx * Pointer to the opaque ZrtpContext structure. * @param time * The time in ms for the timer * @return * zero if activation failed, one if timer was activated */ static int32_t ozrtp_activateTimer (ZrtpContext* ctx, int32_t time ) { if (user_data(ctx)->timerWillTriggerAt != 0) { ortp_error("zrtp_activateTimer while another timer already active"); return 0; } struct timeval t; ortp_gettimeofday(&t,NULL); user_data(ctx)->timerWillTriggerAt=time+convert_timeval_to_millis(&t); return 1; }
static void check_timer(ZrtpContext *zrtpContext, OrtpZrtpContext *c) { if (c->timerWillTriggerAt != 0) { struct timeval t; ortp_gettimeofday(&t,NULL); uint64_t now=convert_timeval_to_millis(&t); if (now > c->timerWillTriggerAt) { c->timerWillTriggerAt=0; zrtp_processTimeout(zrtpContext); } } }
static void stateful_analyzer_update(MSQosAnalyzer *objbase){ MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase; static time_t last_measure; /* Every seconds, save the bandwidth used. This is needed to know how much bandwidth was used when receiving a receiver report. Since the report contains the "last sequence number", it allows us to precisely know which interval to consider */ if (last_measure != ms_time(0)){ obj->upload_bandwidth_count++; obj->upload_bandwidth_sum+=rtp_session_get_send_bandwidth(obj->session)/1000.0; /* Save bandwidth used at this time */ obj->upload_bandwidth[obj->upload_bandwidth_cur].seq_number = rtp_session_get_seq_number(obj->session); obj->upload_bandwidth[obj->upload_bandwidth_cur].up_bandwidth = rtp_session_get_send_bandwidth(obj->session)/1000.0; obj->upload_bandwidth_cur = (obj->upload_bandwidth_cur+1)%BW_HISTORY; } last_measure = ms_time(0); if (obj->burst_duration_ms>0){ switch (obj->burst_state){ case MSStatefulQosAnalyzerBurstEnable:{ obj->burst_state=MSStatefulQosAnalyzerBurstInProgress; ortp_gettimeofday(&obj->start_time, NULL); rtp_session_set_duplication_ratio(obj->session, obj->burst_ratio); } case MSStatefulQosAnalyzerBurstInProgress: { struct timeval now; float elapsed; ortp_gettimeofday(&now,NULL); elapsed=((now.tv_sec-obj->start_time.tv_sec)*1000.0) + ((now.tv_usec-obj->start_time.tv_usec)/1000.0); if (elapsed > obj->burst_duration_ms){ obj->burst_state=MSStatefulQosAnalyzerBurstDisable; rtp_session_set_duplication_ratio(obj->session, 0); } } case MSStatefulQosAnalyzerBurstDisable: { } } } }
static void sender_info_init(sender_info_t *info, RtpSession *session){ struct timeval tv; uint64_t ntp; ortp_gettimeofday(&tv,NULL); ntp=ortp_timeval_to_ntp(&tv); info->ntp_timestamp_msw=htonl(ntp >>32); info->ntp_timestamp_lsw=htonl(ntp & 0xFFFFFFFF); info->rtp_timestamp=htonl(session->rtp.snd_last_ts); info->senders_packet_count=(uint32_t) htonl((u_long) session->stats.packet_sent); info->senders_octet_count=(uint32_t) htonl((u_long) session->rtp.sent_payload_bytes); session->rtp.last_rtcp_packet_count=(uint32_t)session->stats.packet_sent; }
static int rtcp_xr_rcvr_rtt_init(uint8_t *buf, RtpSession *session) { struct timeval tv; uint64_t ntp; rtcp_xr_rcvr_rtt_report_block_t *block = (rtcp_xr_rcvr_rtt_report_block_t *)buf; block->bh.bt = RTCP_XR_RCVR_RTT; block->bh.flags = 0; // Reserved bits block->bh.length = htons(2); ortp_gettimeofday(&tv, NULL); ntp = ortp_timeval_to_ntp(&tv); block->ntp_timestamp_msw = htonl(ntp >> 32); block->ntp_timestamp_lsw = htonl(ntp & 0xFFFFFFFF); return sizeof(rtcp_xr_rcvr_rtt_report_block_t); }
static time_t get_current_time(void) { struct timeval tp; struct tm *lt; #ifndef _WIN32 struct tm tmbuf; #endif time_t tt; ortp_gettimeofday(&tp,NULL); tt = (time_t)tp.tv_sec; #ifdef _WIN32 lt = localtime(&tt); #else lt = localtime_r(&tt,&tmbuf); #endif return mktime(lt); }
static void extended_statistics( RtpSession *session, report_block_t * rb ) { /* the jitter raw value is kept in stream clock units */ uint32_t jitter = (uint32_t)session->rtp.jittctl.inter_jitter; session->stats.sent_rtcp_packets ++; session->rtp.jitter_stats.sum_jitter += jitter; session->rtp.jitter_stats.jitter=jitter; /* stores the biggest jitter for that session and its date (in millisecond) since Epoch */ if ( jitter > session->rtp.jitter_stats.max_jitter ) { struct timeval now; session->rtp.jitter_stats.max_jitter = jitter ; ortp_gettimeofday( &now, NULL ); session->rtp.jitter_stats.max_jitter_ts = ( now.tv_sec * 1000LL ) + ( now.tv_usec / 1000LL ); } /* compute mean jitter buffer size */ session->rtp.jitter_stats.jitter_buffer_size_ms=jitter_control_compute_mean_size(&session->rtp.jittctl); }
static int rtcp_xr_dlrr_init(uint8_t *buf, RtpSession *session) { uint32_t dlrr = 0; rtcp_xr_dlrr_report_block_t *block = (rtcp_xr_dlrr_report_block_t *)buf; block->bh.bt = RTCP_XR_DLRR; block->bh.flags = 0; // Reserved bits block->bh.length = htons(3); block->content[0].ssrc = htonl(rtp_session_get_recv_ssrc(session)); block->content[0].lrr = htonl(session->rtcp_xr_stats.last_rcvr_rtt_ts); if (session->rtcp_xr_stats.last_rcvr_rtt_time.tv_sec != 0) { struct timeval now; double delay; ortp_gettimeofday(&now, NULL); delay = ((now.tv_sec - session->rtcp_xr_stats.last_rcvr_rtt_time.tv_sec) + ((now.tv_usec - session->rtcp_xr_stats.last_rcvr_rtt_time.tv_usec) * 1e-6)) * 65536; dlrr = (uint32_t) delay; } block->content[0].dlrr = htonl(dlrr); return sizeof(rtcp_xr_dlrr_report_block_t); }
/* * Called from any linphone thread. */ void linphone_gtk_log_push(OrtpLogLevel lev, const char *fmt, va_list args){ LinphoneGtkLog *lgl=g_new(LinphoneGtkLog,1); gchar *msg=g_strdup_vprintf(fmt,args); gchar *dated_msg; struct timeval tp; struct tm *lt; time_t tt; ortp_gettimeofday(&tp, NULL); tt = (time_t)tp.tv_sec; lt = localtime((const time_t*)&tt); dated_msg=g_strdup_printf("%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i %s", 1900 + lt->tm_year, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, (int)(tp.tv_usec / 1000), msg); g_free(msg); lgl->lev=lev; lgl->msg=dated_msg; linphone_gtk_log_file(lev, dated_msg); g_static_mutex_lock(&log_mutex); log_queue=g_list_append(log_queue,lgl); g_static_mutex_unlock(&log_mutex); }
static void init_random_number_generator(){ struct timeval t; ortp_gettimeofday(&t,NULL); srandom(t.tv_usec+t.tv_sec); }
/* Helper functions */ static ORTP_INLINE uint64_t get_timeval_in_millis() { struct timeval t; ortp_gettimeofday(&t,NULL); return (1000LL*t.tv_sec)+(t.tv_usec/1000LL); }
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 ); } }
/* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ const char *server=linphone_core_get_stun_server(lc); StunCandidate *ac=&call->ac; StunCandidate *vc=&call->vc; if (lc->sip_conf.ipv6_enabled){ ms_warning("stun support is not implemented for ipv6"); return -1; } if (server!=NULL){ const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); ortp_socket_t sock1=-1, sock2=-1; int loops=0; bool_t video_enabled=linphone_core_video_enabled(lc); bool_t got_audio,got_video; bool_t cone_audio=FALSE,cone_video=FALSE; struct timeval init,cur; double elapsed; int ret=0; if (ai==NULL){ ms_error("Could not obtain stun server addrinfo."); return -1; } if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Stun lookup in progress...")); /*create the two audio and video RTP sockets, and send STUN message to our stun server */ sock1=create_socket(call->audio_port); if (sock1==-1) return -1; if (video_enabled){ sock2=create_socket(call->video_port); if (sock2==-1) return -1; } got_audio=FALSE; got_video=FALSE; ortp_gettimeofday(&init,NULL); do{ int id; if (loops%20==0){ ms_message("Sending stun requests..."); sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,11,TRUE); sendStunRequest(sock1,ai->ai_addr,ai->ai_addrlen,1,FALSE); if (sock2!=-1){ sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,22,TRUE); sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE); } } ms_usleep(10000); if (recvStunResponse(sock1,ac->addr, &ac->port,&id)>0){ ms_message("STUN test result: local audio port maps to %s:%i", ac->addr, ac->port); if (id==11) cone_audio=TRUE; got_audio=TRUE; } if (recvStunResponse(sock2,vc->addr, &vc->port,&id)>0){ ms_message("STUN test result: local video port maps to %s:%i", vc->addr, vc->port); if (id==22) cone_video=TRUE; got_video=TRUE; } ortp_gettimeofday(&cur,NULL); elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); if (elapsed>2000) { ms_message("Stun responses timeout, going ahead."); ret=-1; break; } loops++; }while(!(got_audio && (got_video||sock2==-1) ) ); if (ret==0) ret=(int)elapsed; if (!got_audio){ ms_error("No stun server response for audio port."); }else{ if (!cone_audio) { ms_message("NAT is symmetric for audio port"); } } if (sock2!=-1){ if (!got_video){ ms_error("No stun server response for video port."); }else{ if (!cone_video) { ms_message("NAT is symmetric for video port."); } } } close_socket(sock1); if (sock2!=-1) close_socket(sock2); return ret; } return -1; }
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++; } }