Esempio n. 1
0
static mblk_t * make_rtcp_fb_fir(RtpSession *session) {
	int size = sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t) + sizeof(rtcp_fb_fir_fci_t);
	mblk_t *h = allocb(size, 0);
	rtcp_common_header_t *ch;
	rtcp_fb_header_t *fbh;
	rtcp_fb_fir_fci_t *fci;

	/* Fill FIR */
	ch = (rtcp_common_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_common_header_t);
	fbh = (rtcp_fb_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_header_t);
	fci = (rtcp_fb_fir_fci_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_fir_fci_t);
	fbh->packet_sender_ssrc = htonl(0);
	fbh->media_source_ssrc = htonl(rtp_session_get_recv_ssrc(session));
	fci->ssrc = htonl(rtp_session_get_send_ssrc(session));
	fci->seq_nr = session->rtcp.rtcp_fb_fir_seq_nr++;
	fci->pad1 = 0;
	fci->pad2 = 0;

	/* Fill common header */
	rtcp_common_header_init(ch, session, RTCP_PSFB, RTCP_PSFB_FIR, msgdsize(h));

	return h;
}
int media_stream_set_srtp_recv_key(MediaStream *stream, MSCryptoSuite suite, const char* key){

	if (!media_stream_srtp_supported()) {
		ms_error("ortp srtp support disabled in oRTP or mediastreamer2");
		return -1;
	}
#ifdef ORTP_HAVE_SRTP
	{
		uint32_t ssrc,send_ssrc;
		bool_t updated=FALSE;

		if (check_srtp_session_created(stream)==-1)
			return -1;

		/*check if a previous key was configured, in which case remove it*/
		send_ssrc=rtp_session_get_send_ssrc(stream->sessions.rtp_session);
		ssrc=find_other_ssrc(stream->sessions.srtp_session,htonl(send_ssrc));

		/*careful: remove_stream takes the SSRC in network byte order...*/
		if (ortp_srtp_remove_stream(stream->sessions.srtp_session,ssrc)==0)
			updated=TRUE;
		ssrc=rtp_session_get_recv_ssrc(stream->sessions.rtp_session);
		ms_message("media_stream_set_srtp_recv_key(): %s key %s",updated ? "changing to" : "starting with", key);
		return add_srtp_stream(stream->sessions.srtp_session,suite,ssrc,key,TRUE);
	}
#else
	return -1;
#endif
}
Esempio n. 3
0
static mblk_t * make_rtcp_fb_sli(RtpSession *session, uint16_t first, uint16_t number, uint8_t picture_id) {
	int size = sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t) + sizeof(rtcp_fb_sli_fci_t);
	mblk_t *h = allocb(size, 0);
	rtcp_common_header_t *ch;
	rtcp_fb_header_t *fbh;
	rtcp_fb_sli_fci_t *fci;

	/* Fill SLI */
	ch = (rtcp_common_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_common_header_t);
	fbh = (rtcp_fb_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_header_t);
	fci = (rtcp_fb_sli_fci_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_sli_fci_t);
	fbh->packet_sender_ssrc = htonl(rtp_session_get_send_ssrc(session));
	fbh->media_source_ssrc = htonl(rtp_session_get_recv_ssrc(session));
	rtcp_fb_sli_fci_set_first(fci, first);
	rtcp_fb_sli_fci_set_number(fci, number);
	rtcp_fb_sli_fci_set_picture_id(fci, picture_id);

	/* Fill common header */
	rtcp_common_header_init(ch, session, RTCP_PSFB, RTCP_PSFB_SLI, msgdsize(h));

	return h;
}
Esempio n. 4
0
static int rtcp_xr_stat_summary_init(uint8_t *buf, RtpSession *session) {
	rtcp_xr_stat_summary_report_block_t *block = (rtcp_xr_stat_summary_report_block_t *)buf;
	uint16_t last_rcv_seq = session->rtp.hwrcv_extseq & 0xFFFF;
	uint8_t flags = session->rtcp.xr_conf.stat_summary_flags;
	uint32_t expected_packets;
	uint32_t lost_packets = 0;
	uint32_t dup_packets = session->rtcp_xr_stats.dup_since_last_stat_summary;

	/* Compute lost and duplicate packets statistics */
	if (flags & OrtpRtcpXrStatSummaryLoss) {
		uint32_t no_duplicate_received = session->rtcp_xr_stats.rcv_since_last_stat_summary - dup_packets;
		expected_packets = last_rcv_seq - session->rtcp_xr_stats.rcv_seq_at_last_stat_summary;
		lost_packets = (expected_packets > session->rtcp_xr_stats.rcv_since_last_stat_summary)
			? (expected_packets - no_duplicate_received) : 0;
	}

	block->bh.bt = RTCP_XR_STAT_SUMMARY;
	block->bh.flags = flags;
	block->bh.length = htons(9);
	block->ssrc = htonl(rtp_session_get_recv_ssrc(session));
	block->begin_seq = htons(session->rtcp_xr_stats.rcv_seq_at_last_stat_summary + 1);
	block->end_seq = htons(last_rcv_seq + 1);
	block->lost_packets = htonl(lost_packets);
	block->dup_packets = htonl(dup_packets);
	if ((flags & OrtpRtcpXrStatSummaryJitt)
		&& (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)) {
		block->min_jitter = htonl(session->rtcp_xr_stats.min_jitter_since_last_stat_summary);
		block->max_jitter = htonl(session->rtcp_xr_stats.max_jitter_since_last_stat_summary);
		block->mean_jitter = htonl((session->rtcp_xr_stats.rcv_since_last_stat_summary > 1)
			? (uint32_t)session->rtcp_xr_stats.newm_jitter_since_last_stat_summary : 0);
		block->dev_jitter = htonl((session->rtcp_xr_stats.rcv_since_last_stat_summary > 2)
			? (uint32_t)sqrt(session->rtcp_xr_stats.news_jitter_since_last_stat_summary / (session->rtcp_xr_stats.rcv_since_last_stat_summary - 2)) : 0);
	} else {
		block->min_jitter = htonl(0);
		block->max_jitter = htonl(0);
		block->mean_jitter = htonl(0);
		block->dev_jitter = htonl(0);
	}
	if ((flags & (OrtpRtcpXrStatSummaryTTL | OrtpRtcpXrStatSummaryHL))
		&& (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)) {
		block->min_ttl_or_hl = session->rtcp_xr_stats.min_ttl_or_hl_since_last_stat_summary;
		block->max_ttl_or_hl = session->rtcp_xr_stats.max_ttl_or_hl_since_last_stat_summary;
		block->mean_ttl_or_hl = (session->rtcp_xr_stats.rcv_since_last_stat_summary > 0)
			? (uint8_t)session->rtcp_xr_stats.newm_ttl_or_hl_since_last_stat_summary : 0;
		block->dev_ttl_or_hl = (session->rtcp_xr_stats.rcv_since_last_stat_summary > 1)
			? (uint8_t)sqrt(session->rtcp_xr_stats.news_ttl_or_hl_since_last_stat_summary / (session->rtcp_xr_stats.rcv_since_last_stat_summary - 1)) : 0;
	} else {
		block->min_ttl_or_hl = 0;
		block->max_ttl_or_hl = 0;
		block->mean_ttl_or_hl = 0;
		block->dev_ttl_or_hl = 0;
	}

	session->rtcp_xr_stats.rcv_seq_at_last_stat_summary = last_rcv_seq;
	session->rtcp_xr_stats.rcv_since_last_stat_summary = 0;
	session->rtcp_xr_stats.dup_since_last_stat_summary = 0;

	return sizeof(rtcp_xr_stat_summary_report_block_t);
}
Esempio n. 5
0
void rtp_session_send_rtcp_fb_tmmbr(RtpSession *session, uint64_t mxtbr) {
	mblk_t *m;
	if ((rtp_session_avpf_enabled(session) == TRUE) && (rtp_session_avpf_feature_enabled(session, ORTP_AVPF_FEATURE_TMMBR) == TRUE)) {
		if ((rtp_session_rtcp_rtpfb_scheduled(session, RTCP_RTPFB_TMMBR) != TRUE) && (rtp_session_get_recv_ssrc(session) != 0)) {
			uint16_t overhead = (session->rtp.gs.sockfamily == AF_INET6) ? IP6_UDP_OVERHEAD : IP_UDP_OVERHEAD;
			m = make_rtcp_fb_tmmbr(session, mxtbr, overhead);
			rtp_session_add_fb_packet_to_send(session, m);
			session->rtcp.send_algo.tmmbr_scheduled = TRUE;
		}
		rtp_session_send_fb_rtcp_packet_and_reschedule(session);
	}
}
Esempio n. 6
0
static mblk_t * make_rtcp_fb_rpsi(RtpSession *session, uint8_t *bit_string, uint16_t bit_string_len) {
	uint16_t bit_string_len_in_bytes;
	int additional_bytes;
	int size;
	mblk_t *h;
	rtcp_common_header_t *ch;
	rtcp_fb_header_t *fbh;
	rtcp_fb_rpsi_fci_t *fci;
	int i;

	/* Calculate packet size and allocate memory. */
	bit_string_len_in_bytes = (bit_string_len / 8) + (((bit_string_len % 8) == 0) ? 0 : 1);
	additional_bytes = bit_string_len_in_bytes - 2;
	if (additional_bytes < 0) additional_bytes = 0;
	size = sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t) + sizeof(rtcp_fb_rpsi_fci_t) + additional_bytes;
	h = allocb(size, 0);

	/* Fill RPSI */
	ch = (rtcp_common_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_common_header_t);
	fbh = (rtcp_fb_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_header_t);
	fci = (rtcp_fb_rpsi_fci_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_rpsi_fci_t);
	fbh->packet_sender_ssrc = htonl(rtp_session_get_send_ssrc(session));
	fbh->media_source_ssrc = htonl(rtp_session_get_recv_ssrc(session));
	if (bit_string_len <= 16) {
		fci->pb = 16 - bit_string_len;
		memset(&fci->bit_string, 0, 2);
	} else {
		fci->pb = (bit_string_len - 16) % 32;
		memset(&fci->bit_string, 0, bit_string_len_in_bytes);
	}
	fci->payload_type = rtp_session_get_recv_payload_type(session) & 0x7F;
	memcpy(&fci->bit_string, bit_string, bit_string_len / 8);
	for (i = 0; i < (bit_string_len % 8); i++) {
		fci->bit_string[bit_string_len_in_bytes - 1] |= (bit_string[bit_string_len_in_bytes - 1] & (1 << (7 - i)));
	}

	/* Fill common header */
	rtcp_common_header_init(ch, session, RTCP_PSFB, RTCP_PSFB_RPSI, msgdsize(h));

	return h;
}
Esempio n. 7
0
static mblk_t * make_rtcp_fb_pli(RtpSession *session) {
	int size = sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t);
	mblk_t *h= allocb(size, 0);
	rtcp_common_header_t *ch;
	rtcp_fb_header_t *fbh;

	/* Fill PLI */
	ch = (rtcp_common_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_common_header_t);
	fbh = (rtcp_fb_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_header_t);
	fbh->packet_sender_ssrc = htonl(rtp_session_get_send_ssrc(session));
	fbh->media_source_ssrc = htonl(rtp_session_get_recv_ssrc(session));

	/* Fill common header */
	rtcp_common_header_init(ch, session, RTCP_PSFB, RTCP_PSFB_PLI, msgdsize(h));

	return h;
}
Esempio n. 8
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);
}
Esempio n. 9
0
static mblk_t * make_rtcp_fb_tmmbr(RtpSession *session, uint64_t mxtbr, uint16_t measured_overhead) {
	int size = sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t) + sizeof(rtcp_fb_tmmbr_fci_t);
	mblk_t *h = allocb(size, 0);
	rtcp_common_header_t *ch;
	rtcp_fb_header_t *fbh;
	rtcp_fb_tmmbr_fci_t *fci;
	uint8_t mxtbr_exp = 0;
	uint32_t mxtbr_mantissa = 0;

	/* Compute mxtbr exp and mantissa */
	while (mxtbr >= (1 << 17)) {
		mxtbr >>= 1;
		mxtbr_exp++;
	}
	mxtbr_mantissa = mxtbr & 0x0001FFFF;

	/* Fill TMMBR */
	ch = (rtcp_common_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_common_header_t);
	fbh = (rtcp_fb_header_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_header_t);
	fci = (rtcp_fb_tmmbr_fci_t *)h->b_wptr;
	h->b_wptr += sizeof(rtcp_fb_tmmbr_fci_t);
	fbh->packet_sender_ssrc = htonl(rtp_session_get_send_ssrc(session));
	fbh->media_source_ssrc = htonl(0);
	fci->ssrc = htonl(rtp_session_get_recv_ssrc(session));
	rtcp_fb_tmmbr_fci_set_mxtbr_exp(fci, mxtbr_exp);
	rtcp_fb_tmmbr_fci_set_mxtbr_mantissa(fci, mxtbr_mantissa);
	rtcp_fb_tmmbr_fci_set_measured_overhead(fci, measured_overhead);

	/* Fill common header */
	rtcp_common_header_init(ch, session, RTCP_RTPFB, RTCP_RTPFB_TMMBR, msgdsize(h));

	/* Store packet to be able to retransmit. */
	if (session->rtcp.tmmbr_info.sent) freemsg(session->rtcp.tmmbr_info.sent);
	session->rtcp.tmmbr_info.sent = copymsg(h);

	return h;
}
Esempio n. 10
0
void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
	MediaStream * stream = NULL;
	const PayloadType * local_payload = NULL;
	const PayloadType * remote_payload = NULL;
	const LinphoneCallParams * current_params = linphone_call_get_current_params(call);
	reporting_session_report_t * report = call->log->reporting.reports[stats_type];
	char * dialog_id;

	// call->op might be already released if hanging up in state LinphoneCallOutgoingInit
	if (!media_report_enabled(call, stats_type) || call->op == NULL)
		return;

	dialog_id = sal_op_get_dialog_id(call->op);

	STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id));

	STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(call->core)));
	STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(linphone_call_get_remote_user_agent(call)));

	// RFC states: "LocalGroupID provides the identification for the purposes
	// of aggregation for the local endpoint.".
	STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s"
		, dialog_id ? dialog_id : ""
		, "local"
		, report->local_metrics.user_agent ? report->local_metrics.user_agent : ""
		)
	);
	STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s"
		, dialog_id ? dialog_id : ""
		, "remote"
		, report->remote_metrics.user_agent ? report->remote_metrics.user_agent : ""
		)
	);


	if (call->dir == LinphoneCallIncoming) {
		STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->from));
		STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->to));
		STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id));
	} else {
		STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->to));
		STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->from));
		STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id));
	}


	report->local_metrics.timestamps.start = call->log->start_date_time;
	report->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);

	/*we use same timestamps for remote too*/
	report->remote_metrics.timestamps.start = call->log->start_date_time;
	report->remote_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call);


	/*yet we use the same payload config for local and remote, since this is the largest use case*/
	if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) {
		stream = &call->audiostream->ms;
		local_payload = linphone_call_params_get_used_audio_codec(current_params);
		remote_payload = local_payload;
	} else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) {
		stream = &call->videostream->ms;
		local_payload = linphone_call_params_get_used_video_codec(current_params);
		remote_payload = local_payload;
	} else if (stats_type == LINPHONE_CALL_STATS_TEXT && call->textstream != NULL) {
		stream = &call->textstream->ms;
		local_payload = linphone_call_params_get_used_text_codec(current_params);
		remote_payload = local_payload;
	}

	if (stream != NULL) {
		RtpSession * session = stream->sessions.rtp_session;

		report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session);
		report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session);

		if (stream->qi != NULL){
			report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi) >= 0 ?
				MAX(1, ms_quality_indicator_get_average_lq_rating(stream->qi)) : -1;
			report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi) >= 0 ?
				MAX(1, ms_quality_indicator_get_average_rating(stream->qi)) : -1;
		}
	}

	STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialog_id ? dialog_id : "", report->info.local_addr.ssrc));

	if (local_payload != NULL) {
		report->local_metrics.session_description.payload_type = local_payload->type;
		if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
		report->local_metrics.session_description.sample_rate = local_payload->clock_rate;
		if (local_payload->recv_fmtp!=NULL) STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
	}

	if (remote_payload != NULL) {
		report->remote_metrics.session_description.payload_type = remote_payload->type;
		STR_REASSIGN(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_type));
		report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate;
		STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp));
	}

	ms_free(dialog_id);
}
Esempio n. 11
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);
}