Пример #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;
}
Пример #2
0
void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_type) {
	reporting_session_report_t * report = call->log->reporting.reports[stats_type];
	reporting_content_metrics_t * metrics = NULL;
	LinphoneCallStats stats = call->stats[stats_type];
	mblk_t *block = NULL;
	int report_interval;

	if (! media_report_enabled(call,stats_type))
		return;

	report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy);

	if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) {
		metrics = &report->remote_metrics;
		block = stats.received_rtcp;
	} else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) {
		metrics = &report->local_metrics;
		block = stats.sent_rtcp;
	}
	do{
		if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){

			uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block);

			metrics->rtcp_xr_count++;

			// for local mos rating, we'll use the quality indicator directly
			// because rtcp XR might not be enabled
			if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE){
				metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ?
					127 : rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f;
				metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ?
					127 : rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f;
			}

			metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block);
			metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block);
			metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block);
			metrics->jitter_buffer.adaptive = (config >> 4) & 0x3;
			metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block);
			metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block);

			metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3;

			metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block);
		}else if (rtcp_is_SR(block)){
			MediaStream *ms=(stats_type==0 ? &call->audiostream->ms : &call->videostream->ms);
			float rtt = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session);

			if (rtt > 1e-6){
				metrics->rtcp_sr_count++;
				metrics->delay.round_trip_delay += (int)(1000*rtt);
			}
		}
	}while(rtcp_next_packet(block));
Пример #3
0
static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){
	do{
		if (rtcp_is_SR(m)){
			const report_block_t *rb;
			ms_message("video_steam_process_rtcp: receiving RTCP SR");
			rb=rtcp_SR_get_report_block(m,0);
			if (rb){
				unsigned int ij;
				float rt=rtp_session_get_round_trip_propagation(stream->ms.session);
				float flost;
				ij=report_block_get_interarrival_jitter(rb);
				flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
				ms_message("video_steam_process_rtcp: interarrival jitter=%u , lost packets percentage since last report=%f, round trip time=%f seconds",ij,flost,rt);
				if (stream->ms.rc)
					ms_bitrate_controller_process_rtcp(stream->ms.rc,m);
			}
		}
	}while(rtcp_next_packet(m));
}
static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){
	do{
		const report_block_t *rb=NULL;
		if (rtcp_is_SR(m)){
			rb=rtcp_SR_get_report_block(m,0);
		}else if (rtcp_is_RR(m)){
			rb=rtcp_RR_get_report_block(m,0);
		}
		if (rb){
			unsigned int ij;
			float rt=rtp_session_get_round_trip_propagation(stream->ms.session);
			float flost;
			ij=report_block_get_interarrival_jitter(rb);
			flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
			ms_message("audio_stream_iterate(): remote statistics available\n\tremote's interarrival jitter=%u\n"
			           "\tremote's lost packets percentage since last report=%f\n\tround trip time=%f seconds",ij,flost,rt);
			if (stream->ms.rc) ms_bitrate_controller_process_rtcp(stream->ms.rc,m);
			if (stream->ms.qi) ms_quality_indicator_update_from_feedback(stream->ms.qi,m);
		}
	}while(rtcp_next_packet(m));
}
Пример #5
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;
}
Пример #6
0
static int rtcp_xr_voip_metrics_init(uint8_t *buf, RtpSession *session) {
	JBParameters jbparams;
	uint32_t expected_packets;
	uint32_t lost_packets;
	rtcp_xr_voip_metrics_report_block_t *block = (rtcp_xr_voip_metrics_report_block_t *)buf;
	float rtt = rtp_session_get_round_trip_propagation(session);
	uint16_t int_rtt = (rtt >= 0) ? (rtt * 1000) : 0;
	float qi = -1;
	float lq_qi = -1;

	rtp_session_get_jitter_buffer_params(session, &jbparams);
	if (session->rtcp.xr_media_callbacks.average_qi != NULL) {
		qi = session->rtcp.xr_media_callbacks.average_qi(session->rtcp.xr_media_callbacks.userdata);
	}
	if (session->rtcp.xr_media_callbacks.average_lq_qi != NULL) {
		lq_qi = session->rtcp.xr_media_callbacks.average_lq_qi(session->rtcp.xr_media_callbacks.userdata);
	}

	block->bh.bt = RTCP_XR_VOIP_METRICS;
	block->bh.flags = 0; // Reserved bits
	block->bh.length = htons(8);
	block->ssrc = htonl(rtp_session_get_recv_ssrc(session));
	block->gmin = RTCP_XR_GMIN;

	// Fill RX config
	block->rx_config = 0;
	if (jbparams.adaptive) {
		block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_JBA_ADA;
	} else {
		block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_JBA_NON;
	}
	if (session->rtcp.xr_media_callbacks.plc != NULL) {
		switch (session->rtcp.xr_media_callbacks.plc(session->rtcp.xr_media_callbacks.userdata)) {
			default:
			case OrtpRtcpXrNoPlc:
				block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_UNS;
				break;
			case OrtpRtcpXrSilencePlc:
				block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_DIS;
				break;
			case OrtpRtcpXrEnhancedPlc:
				block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_ENH;
				break;
		}
	} else {
		block->rx_config |= RTCP_XR_VOIP_METRICS_CONFIG_PLC_UNS;
	}

	// Fill JB fields
	block->jb_nominal = htons((uint16_t)jbparams.nom_size);
	if (jbparams.adaptive) {
		block->jb_maximum = htons((session->rtp.jittctl.adapt_jitt_comp_ts * 1000) / session->rtp.jittctl.clock_rate);
	} else {
		block->jb_maximum = block->jb_nominal;
	}
	block->jb_abs_max = htons(65535);

	if (session->rtcp_xr_stats.rcv_count > 0) {
		expected_packets = session->rtcp_xr_stats.last_rcv_seq - session->rtcp_xr_stats.first_rcv_seq + 1;
		lost_packets = expected_packets - session->rtcp_xr_stats.rcv_count;
		block->loss_rate = calc_rate((double)lost_packets, (double)expected_packets);
		block->discard_rate = calc_rate((double)session->rtcp_xr_stats.discarded_count, (double)expected_packets);
		// TODO: fill burst_density, gap_density, burst_duration, gap_duration
		block->burst_density = 0;
		block->gap_density = 0;
		block->burst_duration = htons(0);
		block->gap_duration = htons(0);
		block->round_trip_delay = htons(int_rtt);
		// TODO: fill end_system_delay
		block->end_system_delay = htons(0);
		if (session->rtcp.xr_media_callbacks.signal_level != NULL) {
			block->signal_level = session->rtcp.xr_media_callbacks.signal_level(session->rtcp.xr_media_callbacks.userdata);
		} else {
			block->signal_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		}
		if (session->rtcp.xr_media_callbacks.noise_level != NULL) {
			block->noise_level = session->rtcp.xr_media_callbacks.noise_level(session->rtcp.xr_media_callbacks.userdata);
		} else {
			block->noise_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		}
		block->rerl = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		if (qi < 0) {
			block->r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		} else {
			block->r_factor = (uint8_t)(qi * 20);
		}
		block->ext_r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		if (lq_qi < 0) {
			block->mos_lq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		} else {
			block->mos_lq = (uint8_t)(lq_qi * 10);
			if (block->mos_lq < 10) block->mos_lq = 10;
		}
		if (qi < 0) {
			block->mos_cq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		} else {
			block->mos_cq = (uint8_t)(qi * 10);
			if (block->mos_cq < 10) block->mos_cq = 10;
		}
	} else {
		block->loss_rate = 0;
		block->discard_rate = 0;
		block->burst_density = 0;
		block->gap_density = 0;
		block->burst_duration = htons(0);
		block->gap_duration = htons(0);
		block->round_trip_delay = htons(0);
		block->end_system_delay = htons(0);
		block->signal_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->noise_level = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->rerl = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->ext_r_factor = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->mos_lq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
		block->mos_cq = ORTP_RTCP_XR_UNAVAILABLE_PARAMETER;
	}
	return sizeof(rtcp_xr_voip_metrics_report_block_t);
}
static void basic_audio_stream_base_2(	const char* marielle_local_ip
									  ,	const char* marielle_remote_ip
									  , int marielle_local_rtp_port
									  , int marielle_remote_rtp_port
									  ,	int marielle_local_rtcp_port
									  , int marielle_remote_rtcp_port
									  ,	const char*  margaux_local_ip
									  , const char*  margaux_remote_ip
									  ,	int margaux_local_rtp_port
									  , int margaux_remote_rtp_port
									  ,	int margaux_local_rtcp_port
									  , int margaux_remote_rtcp_port
									  , int lost_percentage) {
	AudioStream * 	marielle = audio_stream_new2 (_factory, marielle_local_ip, marielle_local_rtp_port, marielle_local_rtcp_port);
	stats_t marielle_stats;
	AudioStream * 	margaux = audio_stream_new2 (_factory, margaux_local_ip, margaux_local_rtp_port,margaux_local_rtcp_port);
	stats_t margaux_stats;
	RtpProfile* profile = rtp_profile_new("default profile");
	char* hello_file = bc_tester_res(HELLO_8K_1S_FILE);
	char* recorded_file = bc_tester_file(RECORDED_8K_1S_FILE);
	uint64_t marielle_rtp_sent=0;

	rtp_session_set_multicast_loopback(marielle->ms.sessions.rtp_session,TRUE);
	rtp_session_set_multicast_loopback(margaux->ms.sessions.rtp_session,TRUE);
	rtp_session_set_rtcp_report_interval(marielle->ms.sessions.rtp_session, 1000);
	rtp_session_set_rtcp_report_interval(margaux->ms.sessions.rtp_session, 1000);

	reset_stats(&marielle_stats);
	reset_stats(&margaux_stats);

	rtp_profile_set_payload (profile,0,&payload_type_pcmu8000);

	BC_ASSERT_EQUAL(audio_stream_start_full(margaux
											, profile
											, ms_is_multicast(margaux_local_ip)?margaux_local_ip:margaux_remote_ip
											, ms_is_multicast(margaux_local_ip)?margaux_local_rtp_port:margaux_remote_rtp_port
											, margaux_remote_ip
											, margaux_remote_rtcp_port
											, 0
											, 50
											, NULL
											, recorded_file
											, NULL
											, NULL
											, 0)
					,0, int, "%d");

	BC_ASSERT_EQUAL(audio_stream_start_full(marielle
											, profile
											, marielle_remote_ip
											, marielle_remote_rtp_port
											, marielle_remote_ip
											, marielle_remote_rtcp_port
											, 0
											, 50
											, hello_file
											, NULL
											, NULL
											, NULL
											, 0)
					,0, int, "%d");

	ms_filter_add_notify_callback(marielle->soundread, notify_cb, &marielle_stats,TRUE);

	wait_for_until(&marielle->ms,&margaux->ms,&marielle_stats.number_of_EndOfFile,1,12000);

	audio_stream_get_local_rtp_stats(marielle,&marielle_stats.rtp);
	audio_stream_get_local_rtp_stats(margaux,&margaux_stats.rtp);
	marielle_rtp_sent = marielle_stats.rtp.sent;


	if (rtp_session_rtcp_enabled(marielle->ms.sessions.rtp_session) && rtp_session_rtcp_enabled(margaux->ms.sessions.rtp_session)) {
		BC_ASSERT_GREATER_STRICT(rtp_session_get_round_trip_propagation(marielle->ms.sessions.rtp_session),0,float,"%f");
		BC_ASSERT_GREATER_STRICT(rtp_session_get_stats(marielle->ms.sessions.rtp_session)->recv_rtcp_packets,0,unsigned long long,"%llu");
	}
Пример #8
0
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;
}