From 0762b56a36125e6976e5a7fefef2edb3a61a4748 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 15 Apr 2014 10:43:03 +0200 Subject: [PATCH] Quality reporting: let the config file choose if it should enable or not this feature (per account choice) --- coreapi/linphonecore.h | 11 ++++ coreapi/private.h | 4 +- coreapi/proxy.c | 43 ++++++++++++ coreapi/quality_reporting.c | 128 ++++++++++++++++++++++-------------- coreapi/sal.c | 2 +- mediastreamer2 | 2 +- 6 files changed, 137 insertions(+), 53 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 7448341aa..ea03d9874 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -812,6 +812,17 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *o LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); +/** + * Indicates either or not, quality statistics during call should be stored and sent to a collector at termination. + * @param cfg #LinphoneProxyConfig object + * @param val if true, quality statistics publish will be stored and sent to the collector + * + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val); +LINPHONE_PUBLIC bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *obj); + /** * Get the registration state of the given proxy config. * @param[in] obj #LinphoneProxyConfig object. diff --git a/coreapi/private.h b/coreapi/private.h index d92371a5a..94605e506 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -117,7 +117,7 @@ struct _LinphoneCallLog{ time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */ char* call_id; /**unique id of a call*/ - reporting_session_report_t * reports[2]; + reporting_session_report_t * reports[2]; /**config, "proxy", "reg_identity", NULL) : NULL; const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL; const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; + const char *statistics_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_statistics_collector", NULL) : NULL; const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL; const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL; @@ -59,6 +60,8 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob obj->reg_identity = identity ? ms_strdup(identity) : NULL; obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL; obj->reg_route = route ? ms_strdup(route) : NULL; + obj->reg_statistics_collector = statistics_collector ? ms_strdup(statistics_collector) : NULL; + obj->send_statistics = lc ? lp_config_get_default_int(lc->config, "proxy", "send_statistics", 0) : 0; obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL; obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; } @@ -93,6 +96,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); if (obj->reg_identity!=NULL) ms_free(obj->reg_identity); if (obj->reg_route!=NULL) ms_free(obj->reg_route); + if (obj->reg_statistics_collector!=NULL) ms_free(obj->reg_statistics_collector); if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx); if (obj->realm!=NULL) ms_free(obj->realm); if (obj->type!=NULL) ms_free(obj->type); @@ -413,6 +417,37 @@ void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg){ return cfg->dial_escape_plus; } + +void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val){ + cfg->send_statistics = val; +} + +bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg){ + // ensure that collector address is set too! + return cfg->send_statistics && cfg->reg_statistics_collector != NULL; +} + +void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector){ + if (collector!=NULL && strlen(collector)>0){ + LinphoneAddress *addr=linphone_address_new(collector); + if (!addr || linphone_address_get_username(addr)==NULL){ + ms_warning("Invalid sip collector identity: %s",collector); + if (addr) + linphone_address_destroy(addr); + } else { + if (cfg->reg_statistics_collector != NULL) + ms_free(cfg->reg_statistics_collector); + cfg->reg_statistics_collector = ms_strdup(collector); + linphone_address_destroy(addr); + } + } +} + +const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *cfg){ + return cfg->reg_statistics_collector; +} + + /* * http://en.wikipedia.org/wiki/Telephone_numbering_plan * http://en.wikipedia.org/wiki/Telephone_numbers_in_Europe @@ -1059,6 +1094,9 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->reg_route!=NULL){ lp_config_set_string(config,key,"reg_route",obj->reg_route); } + if (obj->reg_statistics_collector!=NULL){ + lp_config_set_string(config,key,"reg_statistics_collector",obj->reg_statistics_collector); + } if (obj->reg_identity!=NULL){ lp_config_set_string(config,key,"reg_identity",obj->reg_identity); } @@ -1072,6 +1110,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); lp_config_set_int(config,key,"publish",obj->publish); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); + lp_config_set_int(config,key,"send_statistics",obj->send_statistics); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); lp_config_set_int(config,key,"privacy",obj->privacy); } @@ -1103,6 +1142,10 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config tmp=lp_config_get_string(config,key,"reg_route",NULL); if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + tmp=lp_config_get_string(config,key,"reg_statistics_collector",NULL); + if (tmp!=NULL) linphone_proxy_config_set_statistics_collector(cfg,tmp); + linphone_proxy_config_enable_statistics(cfg,lp_config_get_int(config,key,"send_statistics",0)); + linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 84a14e9f5..58727acb7 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -36,21 +36,30 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // TO_CHECK: only if call succeeded and ran (busy should NOT call this) // TO_CHECK: executed AFTER BYE's "OK" response has been received + // TO_CHECK: configurable global publish_call_statistics linphone_proxy_config_set_statistics_collector enable_collector + // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). // remote: session desc null parce que linphone_call_get_remote_params le remplit pas - // payload distant supposons que c les meme que locaux pour l'instant - // verifier char* avant assignation + // range 0 - 255 au lieu de 0 - 5 metrics->quality_estimates.rcq, metrics->quality_estimates.moslq, metrics->quality_estimates.moscq); // abstraction audio video - // tests liblinphonetester // valgrind --leakcheck=full - // configurable global publish_call_statistics linphone_proxy_config_set_statistics_collector enable_collector + // tests liblinphonetester // à voir ++ : // video : que se passe t-il si on arrete / resume la vidéo (new stream) // valeurs instanannées : moyenne ? valeur extreme ? // only if this is a linphone account? // rlq: il faut un algo +/*************************************************************************** + * END OF TODO / REMINDER LIST + ****************************************************************************/ + +#define strass(dest, src) {\ + if (dest != NULL) \ + ms_free(dest); \ + dest = src; \ +} // since printf family functions are LOCALE dependent, float separator may differ // depending on the user's locale (LC_NUMERIC env var). @@ -185,18 +194,19 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg); append_to_buffer(buffer, size, offset, "\r\n"); - free(timestamps_start_str); - free(timestamps_stop_str); - free(network_packet_loss_rate_str); - free(jitter_buffer_discard_rate_str); - // free(gap_loss_density_str); - free(moslq_str); - free(moscq_str); + ms_free(timestamps_start_str); + ms_free(timestamps_stop_str); + ms_free(network_packet_loss_rate_str); + ms_free(jitter_buffer_discard_rate_str); + // ms_free(gap_loss_density_str); + ms_free(moslq_str); + ms_free(moscq_str); } static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { LinphoneContent content = {0}; LinphoneAddress *addr; + const char * addr_str; int expires = -1; size_t offset = 0; size_t size = 2048; @@ -228,15 +238,22 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); content.data = buffer; - - // for debug purpose only - printf("%s\n", (char*) content.data); - content.size = strlen((char*)content.data); - addr = linphone_address_new("sip:collector@sip.linphone.org"); - linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); - linphone_address_destroy(addr); + + + + addr_str = call->dest_proxy->reg_statistics_collector; + if (addr_str != NULL) { + addr = linphone_address_new(addr_str); + linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); + linphone_address_destroy(addr); + + // for debug purpose only + printf("%s\n", (char*) content.data); + } else { + ms_warning("Asked to submit reporting statistics but no collector address found"); + } } @@ -265,7 +282,7 @@ static void reporting_update_ip(LinphoneCall * call, int stats_type) { // local info are always up-to-date and correct if (local_desc != NULL) { call->log->reports[stats_type]->info.local_addr.port = local_desc->rtp_port; - call->log->reports[stats_type]->info.local_addr.ip = ms_strdup(local_desc->rtp_addr); + strass(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); } if (remote_desc != NULL) { @@ -274,21 +291,28 @@ static void reporting_update_ip(LinphoneCall * call, int stats_type) { // for IP it can be not set if we are using a direct route if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) { - call->log->reports[stats_type]->info.remote_addr.ip = ms_strdup(remote_desc->rtp_addr); + strass(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); } else { - call->log->reports[stats_type]->info.remote_addr.ip = ms_strdup(sal_call_get_remote_media_description(call->op)->addr); + strass(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); } } } } -void linphone_reporting_update_ip(LinphoneCall * call) { - printf("linphone_reporting_update_remote_ip\n"); +static bool_t reporting_enabled(LinphoneCall * call) { + return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy)); +} +void linphone_reporting_update_ip(LinphoneCall * call) { // This function can be called in two different cases: // - 1) at start when call is starting, remote ip/port info might be the proxy ones to which callee is registered // - 2) later, if we found a direct route between caller and callee with ICE/Stun, ip/port are updated for the direct route access + printf("linphone_reporting_update_remote_ip\n"); + + if (! reporting_enabled(call)) + return; + reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO); if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { @@ -297,33 +321,32 @@ void linphone_reporting_update_ip(LinphoneCall * call) { } void linphone_reporting_update(LinphoneCall * call, int stats_type) { - printf("linphone_reporting_call_stats_updated type=%d\n", stats_type); reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream * stream = NULL; const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; - const LinphoneCallParams * local_params = linphone_call_get_current_params(call); - const LinphoneCallParams * remote_params = linphone_call_get_remote_params(call); - if (report == NULL) { - ms_warning("No reporting created for this stream"); - return; - } + const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - report->info.call_id = ms_strdup(call->log->call_id); - report->info.local_group = ms_strdup_printf(_("linphone-%s-%s"), linphone_core_get_user_agent_name(), report->info.call_id); - report->info.remote_group = ms_strdup_printf(_("linphone-%s-%s"), linphone_call_get_remote_user_agent(call), report->info.call_id); + printf("linphone_reporting_call_stats_updated type=%d\n", stats_type); + + if (! reporting_enabled(call)) + return; + + strass(report->info.call_id, ms_strdup(call->log->call_id)); + strass(report->info.local_group, ms_strdup_printf(_("linphone-%s-%s"), linphone_core_get_user_agent_name(), report->info.call_id)); + strass(report->info.remote_group, ms_strdup_printf(_("linphone-%s-%s"), linphone_call_get_remote_user_agent(call), report->info.call_id)); if (call->dir == LinphoneCallIncoming) { - report->info.remote_id = linphone_address_as_string(call->log->from); - report->info.local_id = linphone_address_as_string(call->log->to); - report->info.orig_id = ms_strdup(report->info.remote_id); + strass(report->info.remote_id, linphone_address_as_string(call->log->from)); + strass(report->info.local_id, linphone_address_as_string(call->log->to)); + strass(report->info.orig_id, ms_strdup(report->info.remote_id)); } else { - report->info.remote_id = linphone_address_as_string(call->log->to); - report->info.local_id = linphone_address_as_string(call->log->from); - report->info.orig_id = ms_strdup(report->info.local_id); + strass(report->info.remote_id, linphone_address_as_string(call->log->to)); + strass(report->info.local_id, linphone_address_as_string(call->log->from)); + strass(report->info.orig_id, ms_strdup(report->info.local_id)); } - report->dialog_id = sal_op_get_dialog_id(call->op); + strass(report->dialog_id, sal_op_get_dialog_id(call->op)); 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); @@ -332,16 +355,15 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { 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 case if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = &call->audiostream->ms; - local_payload = linphone_call_params_get_used_audio_codec(local_params); - if (remote_params != NULL) - remote_payload = linphone_call_params_get_used_audio_codec(remote_params); + 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(local_params); - if (remote_params != NULL) - remote_payload = linphone_call_params_get_used_video_codec(linphone_call_get_remote_params(call)); + local_payload = linphone_call_params_get_used_video_codec(current_params); + remote_payload = local_payload; } if (stream != NULL) { @@ -353,16 +375,16 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { if (local_payload != NULL) { report->local_metrics.session_description.payload_type = local_payload->type; - report->local_metrics.session_description.payload_desc = ms_strdup(local_payload->mime_type); + strass(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); report->local_metrics.session_description.sample_rate = local_payload->clock_rate; - report->local_metrics.session_description.fmtp = ms_strdup(local_payload->recv_fmtp); + strass(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; - report->remote_metrics.session_description.payload_desc = ms_strdup(remote_payload->mime_type); + strass(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_type)); report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; - report->remote_metrics.session_description.fmtp = ms_strdup(remote_payload->recv_fmtp); + strass(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp)); } } @@ -373,6 +395,9 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; + if (! reporting_enabled(call)) + return; + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { metrics = &report->remote_metrics; if (rtcp_is_XR(stats.received_rtcp) == TRUE) { @@ -410,6 +435,9 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { void linphone_reporting_publish(LinphoneCall* call) { printf("linphone_reporting_publish\n"); + if (! reporting_enabled(call)) + return; + if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); } diff --git a/coreapi/sal.c b/coreapi/sal.c index a3ec66b45..e42c124cc 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -374,7 +374,7 @@ const char* sal_op_get_call_id(const SalOp *op) { } char* sal_op_get_dialog_id(const SalOp *op) { if (op->dialog != NULL) { - return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id, + return ms_strdup_printf("%s;to-tag=%s;from-tag=%s", ((SalOpBase*)op)->call_id, belle_sip_dialog_get_remote_tag(op->dialog), belle_sip_dialog_get_local_tag(op->dialog)); } return NULL; diff --git a/mediastreamer2 b/mediastreamer2 index 41db9323b..b76e3dde1 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 41db9323be6a6d136949ee5fdba1198c38a7d787 +Subproject commit b76e3dde111af0d24be4ac5f1d4f633361e654c1