Exemple #1
0
static bool_t simple_analyzer_process_rtcp(MSQosAnalyzer *objbase, mblk_t *rtcp){
	MSSimpleQosAnalyzer *obj=(MSSimpleQosAnalyzer*)objbase;
	rtpstats_t *cur;
	const report_block_t *rb=NULL;
	bool_t got_stats=FALSE;
	
	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)){

		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;
		}
		if (ortp_loss_rate_estimator_process_report_block(objbase->lre,&obj->session->rtp,rb)){
			cur->lost_percentage=ortp_loss_rate_estimator_get_value(objbase->lre);
			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);
			got_stats=TRUE;
		}
	}
	return got_stats;
}
static void rtcp_eventhandler_impl(LinhoneQos *qos, mblk_t *report)
{
    uint32_t ssrc = 0;
    LinphoneRtcpAnaly *analyze = NULL;
    MSList *elem;

    ms_message("linphoneqos begin to handle rtcp report");

    if (!qos || !report) {
        ms_message("linphoneqos report is null");
        return;
    }

    report_block_t *block = NULL;
    if (rtcp_is_SR(report)) {
        ms_message("linphoneqos begin to handle rtcp sr report");
        block = rtcp_SR_get_report_block(report, 0);
    } else if (rtcp_is_RR(report)) {
        ms_message("linphoneqos begin to handle rtcp rr report");
        block = rtcp_RR_get_report_block(report, 0);
    } else {
        ms_message("linphoneqos begin to handle rtcp xr report");
        return;
    }

    if (!block)
        return;

    ssrc = report_block_get_ssrc(block);

    elem = ms_list_find_custom(qos->list, (MSCompareFunc)qos_find_rtcpanly_from_list, &ssrc);
    if (!elem) {
        ms_message("linphoneqos create to rtcpanalyze %u", ssrc);
        analyze = ms_new0(LinphoneRtcpAnaly, 1);
		linphone_initial_analy(qos, analyze);
        analyze->ssrc = ssrc;
        qos->list = ms_list_append(qos->list, analyze); 
    } else {
        analyze = (LinphoneRtcpAnaly *)elem->data;
    }

    if (!analyze)
    {
        ms_message("linphoneqos failed to create rtcpanalyze %u", ssrc);
        return;
    }

    analyze->rtcp_eh(analyze, block); // analyze the rtcp report first
    analyze->net_eh(analyze);  // analyze the net 
    qos->adjust_eh(qos, analyze->action, analyze->adjust_level);  //adjust the net
}
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;
}