Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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)++;
		}
	}
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/* 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);
	
}
Exemplo n.º 6
0
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.");
	}
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
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.");
}
Exemplo n.º 9
0
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.");
		}
	}
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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 );
	}
}
Exemplo n.º 12
0
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++;
	}
}
Exemplo n.º 13
0
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;
}