static int stateful_qos_analyzer_get_total_emitted(const MSStatefulQosAnalyzer *obj, const report_block_t *rb){
	double dup = obj->burst_ratio;
	int burst_within_start = MAX(obj->previous_ext_high_seq_num_rec, obj->start_seq_number);
	int burst_within_end = MIN(report_block_get_high_ext_seq(rb), obj->last_seq_number);
	int uniq_emitted=report_block_get_high_ext_seq(rb) - obj->previous_ext_high_seq_num_rec;

	return uniq_emitted + MAX(0,burst_within_end - burst_within_start) * dup;
}
Exemple #2
0
bool_t ortp_loss_rate_estimator_process_report_block(OrtpLossRateEstimator *obj, const RtpSession *session, const report_block_t *rb){
	int32_t cum_loss=report_block_get_cum_packet_lost(rb);
	int32_t extseq=report_block_get_high_ext_seq(rb);
	int32_t diff_unique_outgoing=(int32_t)(session->stats.packet_sent-obj->last_packet_sent_count);
	int32_t diff_total_outgoing=diff_unique_outgoing+(int32_t)(session->stats.packet_dup_sent-obj->last_dup_packet_sent_count);
	int32_t diff;
	uint64_t curtime;
	bool_t got_value=FALSE;

	if (obj->last_ext_seq==-1 || obj->last_estimate_time_ms==(uint64_t)-1){
		/*first report cannot be considered, since we don't know the interval it covers*/
		obj->last_ext_seq=extseq;
		obj->last_cum_loss=cum_loss;
		obj->last_estimate_time_ms=ortp_get_cur_time_ms();
		return FALSE;
	}
	diff=extseq-obj->last_ext_seq;
	curtime=ortp_get_cur_time_ms();
	if (diff<0 || diff>obj->min_packet_count_interval * 100){
		ortp_warning("ortp_loss_rate_estimator_process %p: Suspected discontinuity in sequence numbering from %d to %d.", obj, obj->last_ext_seq, extseq);
		obj->last_ext_seq=extseq;
		obj->last_cum_loss=cum_loss;
		obj->last_packet_sent_count=session->stats.packet_sent;
		obj->last_dup_packet_sent_count=session->stats.packet_dup_sent;
	}else if (diff>obj->min_packet_count_interval && curtime-obj->last_estimate_time_ms>=obj->min_time_ms_interval){
		/*we have sufficient interval*/
		int32_t new_losses=cum_loss-obj->last_cum_loss;
		/*if we are using duplicates, they will not be visible in 'diff' variable.
		But since we are the emitter, we can retrieve the total count of packet we
		sent and use this value to compute the loss rate instead.*/
		obj->loss_rate = 100.f * (1.f - MAX(0, (diff_unique_outgoing - new_losses) * 1.f / diff_total_outgoing));

		/*update last values with current*/
		got_value=TRUE;
		obj->last_estimate_time_ms=curtime;

		if (obj->loss_rate>100.f){
			ortp_error("ortp_loss_rate_estimator_process %p: Loss rate MUST NOT be greater than 100%%", obj);
		}
		obj->last_ext_seq=extseq;
		obj->last_cum_loss=cum_loss;
		obj->last_packet_sent_count=session->stats.packet_sent;
		obj->last_dup_packet_sent_count=session->stats.packet_dup_sent;
	}
	return got_value;

}
int capt_parse_rtcp(char *packet, int len, char *json_buffer, int buffer_len) {


	if(packet == NULL || len == 0) return -1;
		
	rtcp_header_t *rtcp = (rtcp_header_t *)packet;
	int ret=0;
	char *rptr;
	
	if(rtcp->version != 2)
	{
		LERR("wrong version\n");
		return -2;
	}

	ret+=snprintf(json_buffer, buffer_len, "{ ");
		
	int pno = 0, total = len;
	LDEBUG("Parsing compound packet (total of %d bytes)\n", total);
	while(rtcp) {
		pno++;
		switch(rtcp->type) {
			case RTCP_SR: {
				/* SR, sender report */
				LDEBUG("#%d SR (200)\n", pno);
				rtcp_sr_t *sr = (rtcp_sr_t*)rtcp;

				ret += snprintf(json_buffer+ret, buffer_len - ret, SENDER_REPORT_JSON, 
								sender_info_get_ntp_timestamp_msw(&sr->si),
								sender_info_get_ntp_timestamp_lsw(&sr->si),								
								sender_info_get_octet_count(&sr->si),
								sender_info_get_rtp_timestamp(&sr->si),
								sender_info_get_packet_count(&sr->si));
				
				if(sr->header.rc > 0) {

					ret += snprintf(json_buffer+ret, buffer_len - ret, REPORT_BLOCK_JSON, 
								ntohl(sr->ssrc), rtcp->type, 
								report_block_get_ssrc(&sr->rb[0]),
								report_block_get_high_ext_seq(&sr->rb[0]),
								report_block_get_fraction_lost(&sr->rb[0]),
								report_block_get_interarrival_jitter(&sr->rb[0]),
								report_block_get_cum_packet_loss(&sr->rb[0]),
								report_block_get_last_SR_time(&sr->rb[0]),
								report_block_get_last_SR_delay(&sr->rb[0]));
				}
				

				break;
			}
			case RTCP_RR: {
				/* RR, receiver report */
				LDEBUG("#%d RR (201)\n", pno);
				rtcp_rr_t *rr = (rtcp_rr_t*)rtcp;

				if(rr->header.rc > 0) {

					ret += snprintf(json_buffer+ret, buffer_len - ret, REPORT_BLOCK_JSON, 
								ntohl(rr->ssrc), rtcp->type, 
								report_block_get_ssrc(&rr->rb[0]),
								report_block_get_high_ext_seq(&rr->rb[0]),
								report_block_get_fraction_lost(&rr->rb[0]),
								report_block_get_interarrival_jitter(&rr->rb[0]),
								report_block_get_cum_packet_loss(&rr->rb[0]),
								report_block_get_last_SR_time(&rr->rb[0]),
								report_block_get_last_SR_delay(&rr->rb[0]));
				}
				break;
			}
			case RTCP_SDES: {
				LDEBUG("#%d SDES (202)\n", pno);

				/* if not needed send sdes */
				if(!send_sdes) break;
								
				rtcp_sdes_t *sdes = (rtcp_sdes_t*)rtcp;

				rptr = rtcp+2;				
				int sdes_report_count = 0;
				
				char *end=(char*) rptr+(4*(rtcp_header_get_length(&sdes->header)+1)-15);
					
				ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_BEGIN_JSON, ntohl(sdes->ssrc), sdes_chunk_get_csrc(&sdes->chunk));

				while(rptr < end) {				

					if (rptr+2<=end) { 
															
						uint8_t chunk_type=rptr[0];
						uint8_t chunk_len=rptr[1];				
						
						if(chunk_len == 0) break;
				
						rptr+=2;
						
						ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_INFO_JSON, chunk_type, chunk_len, rptr);
					
						sdes_report_count++;						
										
						if (rptr+chunk_len<=end) rptr+=chunk_len;							                                                                                           
						else break;												
					}
					else {
						break;
					}
				}
				
				/* cut , off */			
				ret-=1;

				ret += snprintf(json_buffer+ret, buffer_len - ret, SDES_REPORT_END_JSON, sdes_report_count);
				
				break;
			}
			case RTCP_BYE: {
				LDEBUG("#%d BYE (203)\n", pno);
				ret = 0;
				//rtcp_bye_t *bye = (rtcp_bye_t*)rtcp;
				break;
			}
			case RTCP_APP: {			
				LDEBUG("#%d APP (204)\n", pno);
				ret = 0;
				//rtcp_app_t *app = (rtcp_app_t*)rtcp;
				break;
			}
			default:
				break;
		}
		
				
		int length = ntohs(rtcp->length);
		if(length == 0) {
			break;
		}
		total -= length*4+4;
		if(total <= 0) {
			LDEBUG("End of RTCP packet\n");
			break;
		}
		rtcp = (rtcp_header_t *)((uint32_t*)rtcp + length + 1);
	}
	
	/* bad parsed message */
	if(ret  < 10) return 0;
	
	ret+=snprintf(json_buffer+ret-1, buffer_len-ret+1, "}");
			
	return ret;
}
Exemple #4
0
static bool_t stateful_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){
	MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase;
	const report_block_t *rb=NULL;
	if (rtcp_is_SR(rtcp)){
		rb=rtcp_SR_get_report_block(rtcp,0);
	}else if (rtcp_is_RR(rtcp)){
		rb=rtcp_RR_get_report_block(rtcp,0);
	}


	if (rb && report_block_get_ssrc(rb)==rtp_session_get_send_ssrc(obj->session)){
		if (ortp_loss_rate_estimator_process_report_block(objbase->lre,&obj->session->rtp,rb)){
			int i;
			float loss_rate = ortp_loss_rate_estimator_get_value(objbase->lre);
			float up_bw = stateful_qos_analyzer_upload_bandwidth(obj,report_block_get_high_ext_seq(rb));
			obj->curindex++;

			/*flush bandwidth estimation measures for seq number lower than remote report block received*/
			for (i=0;i<BW_HISTORY;i++){
				if (obj->upload_bandwidth[i].seq_number<report_block_get_high_ext_seq(rb)){
					obj->upload_bandwidth[i].seq_number=0;
					obj->upload_bandwidth[i].up_bandwidth=0.f;
				}
			}

			/* Always skip the first report, since values might be erroneous due
			to initialization of multiples objects (encoder/decoder/stats computing..)
			Instead assume loss rate is a good estimation of network capacity */
			if (obj->curindex==1)  {
				obj->network_loss_rate=loss_rate;
				return TRUE;
			}

			obj->latest=ms_new0(rtcpstatspoint_t, 1);
			obj->latest->timestamp=ms_time(0);
			obj->latest->bandwidth=up_bw;
			obj->latest->loss_percent=loss_rate;
			obj->latest->rtt=rtp_session_get_round_trip_propagation(obj->session);

			obj->rtcpstatspoint=ms_list_insert_sorted(obj->rtcpstatspoint,
				obj->latest, (MSCompareFunc)sort_by_bandwidth);

			/*if the measure was 0% loss, reset to 0% every measures below it*/
			if (obj->latest->loss_percent < 1e-5){
				MSList *it=obj->rtcpstatspoint;
				MSList *latest_pos=ms_list_find(obj->rtcpstatspoint,obj->latest);
				while (it!=latest_pos->next){
					((rtcpstatspoint_t *)it->data)->loss_percent=0.f;
					it = it->next;
				}
			}
			ms_message("MSStatefulQosAnalyzer[%p]: one more %d: %f %f",
				obj, obj->curindex-1, obj->latest->bandwidth, obj->latest->loss_percent);

			if (ms_list_size(obj->rtcpstatspoint) > ESTIM_HISTORY){
				int prev_size = ms_list_size(obj->rtcpstatspoint);

				/*clean everything which occurred 60 sec or more ago*/
				time_t clear_time = ms_time(0) - 60;
				obj->rtcpstatspoint = ms_list_remove_custom(obj->rtcpstatspoint,
					(MSCompareFunc)earlier_than, &clear_time);
				ms_message("MSStatefulQosAnalyzer[%p]: reached list maximum capacity "
					"(count=%d) --> Cleaned list (count=%d)",
					obj, prev_size, ms_list_size(obj->rtcpstatspoint));
			}
			return TRUE;
		}
	}
	return FALSE;
}
static bool_t stateful_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){
	MSStatefulQosAnalyzer *obj=(MSStatefulQosAnalyzer*)objbase;
	rtpstats_t *cur;
	const report_block_t *rb=NULL;
	if (rtcp_is_SR(rtcp)){
		rb=rtcp_SR_get_report_block(rtcp,0);
	}else if (rtcp_is_RR(rtcp)){
		rb=rtcp_RR_get_report_block(rtcp,0);
	}
	if (rb && report_block_get_ssrc(rb)==rtp_session_get_send_ssrc(obj->session)){
		double up_bw = stateful_qos_analyzer_upload_bandwidth(obj);
		int total_emitted=stateful_qos_analyzer_get_total_emitted(obj, rb);
		obj->curindex++;
		cur=&obj->stats[obj->curindex % STATS_HISTORY];

		if (obj->clockrate==0){
			PayloadType *pt=rtp_profile_get_payload(rtp_session_get_send_profile(obj->session),rtp_session_get_send_payload_type(obj->session));
			if (pt!=NULL) obj->clockrate=pt->clock_rate;
			else return FALSE;
		}

		cur->lost_percentage=100.0*(float)report_block_get_fraction_lost(rb)/256.0;
		cur->int_jitter=1000.0*(float)report_block_get_interarrival_jitter(rb)/(float)obj->clockrate;
		cur->rt_prop=rtp_session_get_round_trip_propagation(obj->session);
		ms_message("MSSimpleQosAnalyzer: lost_percentage=%f, int_jitter=%f ms, rt_prop=%f sec",cur->lost_percentage,cur->int_jitter,cur->rt_prop);
		if (obj->curindex>2){
			double loss_rate = cur->lost_percentage/100.0;
			int cum_loss=report_block_get_cum_packet_loss(rb);
			int cum_loss_curr=cum_loss - obj->cum_loss_prev;
			int uniq_emitted=report_block_get_high_ext_seq(rb) - obj->previous_ext_high_seq_num_rec;

			if (obj->previous_ext_high_seq_num_rec > 0){
				loss_rate=(1. - (uniq_emitted - cum_loss_curr) * 1.f / total_emitted);
				ms_debug("MSQosStatefulAnalyzer[%p]: RECEIVE estimated loss rate=%f vs 'real'=%f",
					obj, loss_rate, report_block_get_fraction_lost(rb)/256.);
			}

			obj->latest=ms_new0(rtcpstatspoint_t, 1);
			obj->latest->timestamp=ms_time(0);
			obj->latest->bandwidth=up_bw;
			obj->latest->loss_percent=MAX(0,loss_rate);
			obj->latest->rtt=cur->rt_prop;

			obj->rtcpstatspoint=ms_list_insert_sorted(obj->rtcpstatspoint, obj->latest, (MSCompareFunc)sort_points);

			if (obj->latest->loss_percent < 1e-5){
				MSList *it=obj->rtcpstatspoint;
				MSList *latest_pos=ms_list_find(obj->rtcpstatspoint,obj->latest);
				while (it!=latest_pos->next){
					((rtcpstatspoint_t *)it->data)->loss_percent=0.f;
					it = it->next;
				}
			}
			ms_debug("MSQosStatefulAnalyzer[%p]: one more %d: %f %f",
				obj, obj->curindex-2, obj->latest->bandwidth, obj->latest->loss_percent);

			if (ms_list_size(obj->rtcpstatspoint) > ESTIM_HISTORY){
#ifdef DEBUG
				int prev_size = ms_list_size(obj->rtcpstatspoint);
#endif
				/*clean everything which occurred 60 sec or more ago*/
				time_t clear_time = ms_time(0) - 60;
				obj->rtcpstatspoint = ms_list_remove_custom(obj->rtcpstatspoint, (MSCompareFunc)earlier_than, &clear_time);
				ms_debug("MSQosStatefulAnalyzer[%p]: Reached list maximum capacity (count=%d) --> Cleaned list (count=%d)",
					obj, prev_size, ms_list_size(obj->rtcpstatspoint));
			}
		}
		obj->cum_loss_prev=report_block_get_cum_packet_loss(rb);
		obj->previous_ext_high_seq_num_rec=report_block_get_high_ext_seq(rb);
	}
	return rb!=NULL;
}