예제 #1
0
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: {
		}
		}
	}
}
예제 #2
0
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);
}
예제 #3
0
파일: netsim.c 프로젝트: VTCSecureLLC/ortp
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(&current,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;
}
예제 #4
0
파일: ortp.c 프로젝트: Distrotech/oRTP
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*/
}
예제 #5
0
파일: netsim.c 프로젝트: VTCSecureLLC/ortp
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(&current,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,&current);
	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;
}
예제 #6
0
파일: zrtp.c 프로젝트: zengtaoxian/linphone
/**
* 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;
}
예제 #7
0
파일: zrtp.c 프로젝트: zengtaoxian/linphone
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);
		}
	}
}
예제 #8
0
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: {
		}
		}
	}
}
예제 #9
0
파일: rtcp.c 프로젝트: lidongliangfly/ortp
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;
}
예제 #10
0
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);
}
예제 #11
0
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);
}
예제 #12
0
파일: rtcp.c 프로젝트: lidongliangfly/ortp
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);
}
예제 #13
0
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);
}
예제 #14
0
파일: logging.c 프로젝트: 42p/linphone
/*
 * 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);
}
예제 #15
0
static void init_random_number_generator(){
	struct timeval t;
	ortp_gettimeofday(&t,NULL);
	srandom(t.tv_usec+t.tv_sec);
}
예제 #16
0
/* 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);
}
예제 #17
0
파일: rtcp.c 프로젝트: lidongliangfly/ortp
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 );
	}
}
예제 #18
0
파일: misc.c 프로젝트: korobool/liblinphone
/* 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;
}
예제 #19
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++;
	}
}