From 3c71544b24ef3f5421b2fd9bb789d9af59188b84 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 12:58:08 +0200 Subject: [PATCH] Store reporting struct in linphone call --- coreapi/linphonecall.c | 3 + coreapi/private.h | 5 + coreapi/quality_reporting.c | 247 ++++++++++++------------------------ coreapi/quality_reporting.h | 112 ++++++++++++++++ 4 files changed, 200 insertions(+), 167 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c095898ae..f9574f576 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1849,6 +1849,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna playfile=lc->play_file; recfile=lc->rec_file; call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); + call->audio_reporting=ms_new0(reporting_session_report_t,1); if (used_pt!=-1){ call->current_params.audio_codec = rtp_profile_get_payload(call->audio_profile, used_pt); @@ -1978,6 +1979,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,vstream->proto,SalVideo); call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); + call->video_reporting=ms_new0(reporting_session_report_t,1); + if (used_pt!=-1){ VideoStreamDir dir=VideoStreamSendRecv; MSWebCam *cam=lc->video_conf.device; diff --git a/coreapi/private.h b/coreapi/private.h index e2feef54a..9e37f11b7 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -34,6 +34,7 @@ extern "C" { #include "linphonecore_utils.h" #include "sal/sal.h" #include "sipsetup.h" +#include "quality_reporting.h" #include #include @@ -191,6 +192,10 @@ struct _LinphoneCall StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/ struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; + + reporting_session_report_t *audio_reporting; + reporting_session_report_t *video_reporting; + MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; LinphoneCallParams params; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 84271287d..5e82b4a96 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -89,152 +89,57 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } - -struct _reporting_addr_st { - char * ip; - int port; - uint32_t ssrc; -}; - -struct _reporting_content_metrics_st { - // timestamps - mandatory - struct { - time_t start; - time_t stop; - } timestamps; - - // session description - optional - struct { - int payload_type; - char * payload_desc; // mime type - int sample_rate; // clock rate - int frame_duration; // to check (ptime?) - audio only - int frame_ocets; // no - int frames_per_sec; // no - int packets_per_sec; // no - char * fmtp; // pt.recv_fmtp - int packet_loss_concealment; // in voip metrics - audio only - char * silence_suppression_state; // no - } session_description; - - // jitter buffet - optional - struct { - int adaptive; // constant - int rate; // constant - int nominal; // no may vary during the call <- average? worst score? - int max; // no may vary during the call <- average? - int abs_max; // constant - } jitter_buffer; - - // packet loss - optional - struct { - float network_packet_loss_rate; // voip metrics (loss rate) + conversion - float jitter_buffer_discard_rate; //idem - } packet_loss; - - // burst gap loss - optional - // (no) currently not implemented - struct { - int burst_loss_density; - int burst_duration; - float gap_loss_density; - int gap_Duration; - int min_gap_threshold; - } burst_gap_loss; - - // delay - optional - struct { - int round_trip_delay; // no - vary - int end_system_delay; // no - not implemented yet - int one_way_delay; // no - int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay) - int interarrival_jitter; // no - not implemented yet - int mean_abs_jitter; // (no)? - to check - } delay; - - // signal - optional - struct { - int level; // no - vary - int noise_level; // no - vary - int residual_echo_return_loss; // no - } signal; - - // quality estimates - optional - struct { - int rlq; // linked to moslq - in [0..120] - int rcq; //voip metrics R factor - no - vary or avg in [0..120] - float moslq; // no - vary or avg - voip metrics - in [0..4.9] - float moscq; // no - vary or avg - voip metrics - in [0..4.9] - - - int extri; // no - int extro; // no - char * rlqestalg; // no to all alg - char * rcqestalg; - char * moslqestalg; - char * moscqestalg; - char * extriestalg; - char * extroutestalg; - char * qoestalg; - } quality_estimates; -}; - -struct _reporting_session_report_st { - struct { - char * call_id; - char * local_id; - char * remote_id; - char * orig_id; - struct _reporting_addr_st local_addr; - struct _reporting_addr_st remote_addr; - char * local_group; - char * remote_group; - - char * local_mac_addr; // optional - char * remote_mac_addr; // optional - } info; - - struct _reporting_content_metrics_st local_metrics; - struct _reporting_content_metrics_st remote_metrics; // optional - - char * dialog_id; // optional -}; - -struct _reporting_session_report_st get_stats(LinphoneCall * call) { - struct _reporting_session_report_st stats = {{0}}; - stats.info.local_addr.ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); - stats.info.local_addr.port = rtp_session_get_local_port(call->audiostream->ms.session); - stats.info.remote_addr.ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); - // remote address rem_addr - stats.info.call_id = call->log->call_id; - // pour l'ip: itérer sur les streams pour trouver le bon type - // call->resultdesc->streams[0].type - // call->resultdesc->streams[0].rtp_addr - - // const rtp_stats_t * rtp_stats = rtp_session_get_stats(call->audiostream->ms.session); +reporting_session_report_t * update_stats(LinphoneCall * call) { + int count; + reporting_session_report_t * stats = call->audio_reporting; const MSQualityIndicator * qi = media_stream_get_quality_indicator(&call->audiostream->ms); + const PayloadType * payload; - stats.local_metrics.session_description.payload_type = call->params.audio_codec->type; - stats.local_metrics.session_description.payload_desc = ms_strdup(call->params.audio_codec->mime_type); - stats.local_metrics.session_description.sample_rate = call->params.audio_codec->clock_rate; - stats.local_metrics.session_description.fmtp = ms_strdup(call->params.audio_codec->recv_fmtp); - //stats.local_metrics.session_description.packet_loss_concealment = ms_quality_indicator_get_local_late_rate(qi); - - stats.local_metrics.packet_loss.jitter_buffer_discard_rate = ms_quality_indicator_get_local_loss_rate(qi); - - stats.local_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); - if (10 <= stats.local_metrics.quality_estimates.rlq - && stats.local_metrics.quality_estimates.rlq <= 50) { - stats.local_metrics.quality_estimates.moslq = stats.local_metrics.quality_estimates.rlq / 10.f; - } else { - stats.local_metrics.quality_estimates.moslq = -1; + if (stats == NULL) { + ms_warning("No reporting created for this stream"); + return NULL; } - stats.local_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); - if (10 <= stats.local_metrics.quality_estimates.rcq - && stats.local_metrics.quality_estimates.rcq <= 50) { - stats.local_metrics.quality_estimates.moscq = stats.local_metrics.quality_estimates.rcq / 10.f; + + stats->info.local_addr.ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); + stats->info.local_addr.port = rtp_session_get_local_port(call->audiostream->ms.session); + stats->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); + // memcpy(stats->info.remote_addr.ip, &call->audiostream->ms.session->rtp.rem_addr, call->audiostream->ms.session->rtp.rem_addrlen); + stats->info.call_id = call->log->call_id; + for (count = 0; count < call->resultdesc->n_total_streams; ++count) { + if (call->resultdesc->streams[count].type == SalAudio) { + stats->info.local_addr.ip = call->resultdesc->streams[count].rtp_addr; + break; + } + } + if (count == call->resultdesc->n_total_streams) { + ms_warning("Could not find the associated stream of type %d", SalAudio); + } + + payload = call->params.audio_codec; + if (payload != NULL) { + stats->local_metrics.session_description.payload_type = payload->type; + stats->local_metrics.session_description.payload_desc = ms_strdup(payload->mime_type); + stats->local_metrics.session_description.sample_rate = payload->clock_rate; + stats->local_metrics.session_description.fmtp = ms_strdup(payload->recv_fmtp); } else { - stats.local_metrics.quality_estimates.moscq = -1; + // ... + } + + //stats->local_metrics.session_description.packet_loss_concealment = ms_quality_indicator_get_local_late_rate(qi); + stats->local_metrics.packet_loss.jitter_buffer_discard_rate = ms_quality_indicator_get_local_loss_rate(qi); + stats->local_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); + if (10 <= stats->local_metrics.quality_estimates.rlq + && stats->local_metrics.quality_estimates.rlq <= 50) { + stats->local_metrics.quality_estimates.moslq = stats->local_metrics.quality_estimates.rlq / 10.f; + } else { + stats->local_metrics.quality_estimates.moslq = -1; + } + stats->local_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); + if (10 <= stats->local_metrics.quality_estimates.rcq + && stats->local_metrics.quality_estimates.rcq <= 50) { + stats->local_metrics.quality_estimates.moscq = stats->local_metrics.quality_estimates.rcq / 10.f; + } else { + stats->local_metrics.quality_estimates.moscq = -1; } // NOT FOUND @@ -243,21 +148,21 @@ struct _reporting_session_report_st get_stats(LinphoneCall * call) { // jitter_buffer_discard_rate if (call->dir == LinphoneCallIncoming) { - stats.info.remote_id = linphone_address_as_string(call->log->from); - stats.info.local_id = linphone_address_as_string(call->log->to); - stats.info.orig_id = stats.info.remote_id; + stats->info.remote_id = linphone_address_as_string(call->log->from); + stats->info.local_id = linphone_address_as_string(call->log->to); + stats->info.orig_id = stats->info.remote_id; } else { - stats.info.remote_id = linphone_address_as_string(call->log->to); - stats.info.local_id = linphone_address_as_string(call->log->from); - stats.info.orig_id = stats.info.local_id; + stats->info.remote_id = linphone_address_as_string(call->log->to); + stats->info.local_id = linphone_address_as_string(call->log->from); + stats->info.orig_id = stats->info.local_id; } - stats.local_metrics.timestamps.start = call->log->start_date_time; - stats.local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); + stats->local_metrics.timestamps.start = call->log->start_date_time; + stats->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); return stats; } -static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _reporting_content_metrics_st rm) { +static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, reporting_content_metrics_t rm) { char * timpstamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start); char * timpstamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop); char * network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate); @@ -309,34 +214,42 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; - struct _reporting_session_report_st stats = get_stats(call); + reporting_session_report_t *stats = update_stats(call); size_t offset = 0; size_t size = 2048; - char * buffer = (char *) ms_malloc(size); + char * buffer; + + // Somehow the reporting was not created, hence no need to go further + if (stats == NULL) { + PRINT("STATS ARE NULL!"); + return; + } + + buffer = (char *) ms_malloc(size); content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); append_to_buffer(&buffer, &size, &offset, "VQSessionReport: CallTerm\r\n"); - append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", stats.info.call_id); - append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", stats.info.local_id); - append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", stats.info.remote_id); - append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", stats.info.orig_id); + append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", stats->info.call_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", stats->info.local_id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", stats->info.remote_id); + append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", stats->info.orig_id); - append_to_buffer(&buffer, &size, &offset, "LocalGroup: %s\r\n", stats.info.local_group); //linphone-CALLID - append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", stats.info.remote_group); //idem - append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", stats.info.local_addr.ip, stats.info.local_addr.port, stats.info.local_addr.ssrc); - append_to_buffer(&buffer, &size, &offset, "LocalMAC: %s\r\n", stats.info.local_mac_addr); - append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", stats.info.remote_addr.ip, stats.info.remote_addr.port, stats.info.remote_addr.ssrc); - append_to_buffer(&buffer, &size, &offset, "RemoteMAC: %s\r\n", stats.info.remote_mac_addr); + append_to_buffer(&buffer, &size, &offset, "LocalGroup: %s\r\n", stats->info.local_group); //linphone-CALLID + append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", stats->info.remote_group); //idem + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", stats->info.local_addr.ip, stats->info.local_addr.port, stats->info.local_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "LocalMAC: %s\r\n", stats->info.local_mac_addr); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", stats->info.remote_addr.ip, stats->info.remote_addr.port, stats->info.remote_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "RemoteMAC: %s\r\n", stats->info.remote_mac_addr); append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); - add_metrics(&buffer, &size, &offset, stats.local_metrics); + append_metrics_to_buffer(&buffer, &size, &offset, stats->local_metrics); append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); - add_metrics(&buffer, &size, &offset, stats.remote_metrics); - if (stats.dialog_id != NULL) { - append_to_buffer(&buffer, &size, &offset, "DialogID: %s\r\n", stats.dialog_id); + append_metrics_to_buffer(&buffer, &size, &offset, stats->remote_metrics); + if (stats->dialog_id != NULL) { + append_to_buffer(&buffer, &size, &offset, "DialogID: %s\r\n", stats->dialog_id); } content.data = buffer; diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index f56d2b1bd..b8b1a42e4 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -25,6 +25,118 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef __cplusplus extern "C"{ #endif + +typedef struct reporting_addr { + char * ip; + int port; + uint32_t ssrc; +} reporting_addr_t; + +typedef struct reporting_content_metrics { + // timestamps - mandatory + struct { + time_t start; + time_t stop; + } timestamps; + + // session description - optional + struct { + int payload_type; + char * payload_desc; // mime type + int sample_rate; // clock rate + int frame_duration; // to check (ptime?) - audio only + int frame_ocets; // no + int frames_per_sec; // no + int packets_per_sec; // no + char * fmtp; // pt.recv_fmtp + int packet_loss_concealment; // in voip metrics - audio only + char * silence_suppression_state; // no + } session_description; + + // jitter buffet - optional + struct { + int adaptive; // constant + int rate; // constant + int nominal; // no may vary during the call <- average? worst score? + int max; // no may vary during the call <- average? + int abs_max; // constant + } jitter_buffer; + + // packet loss - optional + struct { + float network_packet_loss_rate; // voip metrics (loss rate) + conversion + float jitter_buffer_discard_rate; //idem + } packet_loss; + + // burst gap loss - optional + // (no) currently not implemented + struct { + int burst_loss_density; + int burst_duration; + float gap_loss_density; + int gap_Duration; + int min_gap_threshold; + } burst_gap_loss; + + // delay - optional + struct { + int round_trip_delay; // no - vary + int end_system_delay; // no - not implemented yet + int one_way_delay; // no + int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay) + int interarrival_jitter; // no - not implemented yet + int mean_abs_jitter; // (no)? - to check + } delay; + + // signal - optional + struct { + int level; // no - vary + int noise_level; // no - vary + int residual_echo_return_loss; // no + } signal; + + // quality estimates - optional + struct { + int rlq; // linked to moslq - in [0..120] + int rcq; //voip metrics R factor - no - vary or avg in [0..120] + float moslq; // no - vary or avg - voip metrics - in [0..4.9] + float moscq; // no - vary or avg - voip metrics - in [0..4.9] + + + int extri; // no + int extro; // no + char * rlqestalg; // no to all alg + char * rcqestalg; + char * moslqestalg; + char * moscqestalg; + char * extriestalg; + char * extroutestalg; + char * qoestalg; + } quality_estimates; +} reporting_content_metrics_t; + +typedef struct reporting_session_report { + struct { + char * call_id; + char * local_id; + char * remote_id; + char * orig_id; + reporting_addr_t local_addr; + reporting_addr_t remote_addr; + char * local_group; + char * remote_group; + + char * local_mac_addr; // optional + char * remote_mac_addr; // optional + } info; + + reporting_content_metrics_t local_metrics; + reporting_content_metrics_t remote_metrics; // optional + + char * dialog_id; // optional +} reporting_session_report_t; + + void linphone_quality_reporting_submit(LinphoneCall* call); #ifdef __cplusplus