From 8417c0b18d8f5d6575e3d64a06dce8dc44009fb4 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 7 Apr 2014 16:50:27 +0200 Subject: [PATCH 01/25] Quality reporting: on call end, send a PUBLISH message with call quality data (work in progress) --- build/android/Android.mk | 3 +- build/vsx/LibLinphone/LibLinphone.vcxproj | 3 +- coreapi/CMakeLists.txt | 1 + coreapi/Makefile.am | 1 + coreapi/linphonecall.c | 1 + coreapi/linphonecore.c | 3 + coreapi/quality_reporting.c | 125 ++++++++++++++++++++++ coreapi/quality_reporting.h | 34 ++++++ 8 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 coreapi/quality_reporting.c create mode 100644 coreapi/quality_reporting.h diff --git a/build/android/Android.mk b/build/android/Android.mk index 18fbbdbfd..d815a11a9 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -64,7 +64,8 @@ LOCAL_SRC_FILES := \ xml.c \ xml2lpc.c \ lpc2xml.c \ - remote_provisioning.c + remote_provisioning.c \ + quality_reporting.c ifndef LINPHONE_VERSION LINPHONE_VERSION = "Devel" diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index 9bc9aadf9..bc1f56695 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -203,6 +203,7 @@ + @@ -275,4 +276,4 @@ - \ No newline at end of file + diff --git a/coreapi/CMakeLists.txt b/coreapi/CMakeLists.txt index 8b2650950..05ae3d811 100644 --- a/coreapi/CMakeLists.txt +++ b/coreapi/CMakeLists.txt @@ -74,6 +74,7 @@ set(SOURCE_FILES offeranswer.c presence.c proxy.c + quality_reporting.c remote_provisioning.c sal.c siplogin.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 68d78447f..5edc54059 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -56,6 +56,7 @@ liblinphone_la_SOURCES=\ xml2lpc.c \ lpc2xml.c \ remote_provisioning.c \ + quality_reporting.c \ $(GITVERSION_FILE) if BUILD_UPNP diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eb4a00551..c095898ae 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -782,6 +782,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const Indeed it does not change the state of the call (still paused or running)*/ call->state=cstate; } + if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ switch(call->non_op_error.reason){ case SalReasonDeclined: diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index bd852968e..23090baba 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sipsetup.h" #include "lpconfig.h" #include "private.h" +#include "quality_reporting.h" #include #include @@ -3469,6 +3470,8 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ /*stop ringing*/ linphone_core_stop_ringing(lc); + linphone_quality_reporting_submit(call); + linphone_call_stop_media_streams(call); #ifdef BUILD_UPNP diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c new file mode 100644 index 000000000..e3d25c424 --- /dev/null +++ b/coreapi/quality_reporting.c @@ -0,0 +1,125 @@ +/* +linphone +Copyright (C) 2014 - Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include "linphonecore.h" +#include "private.h" +#include "sal/sal.h" + +#define PRINT2(x, f) ms_message(#x ": " #f, x) +#define PRINT(x) PRINT2(x, "%s") + +void linphone_quality_reporting_submit(LinphoneCall* call) { + // example at http://tools.ietf.org/html/rfc6035#section-4.7.3 + // only if this is a linphone account + // only if call succeeded + // to: collector@sip.linphone.com + // executed AFTER BYE's "OK" response has been received + // expires value? + // un envoi à faire par stream ? (ssrc différent pour chaque stream) + // memory leaks + + LinphoneContent content = {0}; + LinphoneAddress *addr; + int expires = 3600; + const char *remote_identity; + const char *local_identity; + const char *orig_identity; + const char *local_ip = call->localdesc->addr; //or call->localip ? + const char *remote_ip = "TODO"; + uint32_t local_ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); + uint32_t remote_ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); + + int local_port = 0; //TODO + int remote_port = 0;//linphone_address_get_port(linphone_call_get_remote_address(call)); + + if (call->dir == LinphoneCallIncoming) { + remote_identity = linphone_address_as_string(call->log->from); + local_identity = linphone_address_as_string(call->log->to); + orig_identity = remote_identity; + } else { + remote_identity = linphone_address_as_string(call->log->to); + local_identity = linphone_address_as_string(call->log->from); + orig_identity = local_identity; + } + + ms_message("Submitting PUBLISH packet for call between %s and %s", local_identity, remote_identity); + + PRINT(call->dest_proxy->contact_params); + PRINT(call->dest_proxy->contact_uri_params); + PRINT(call->dest_proxy->dial_prefix); + PRINT(call->dest_proxy->realm); + PRINT(call->dest_proxy->type); + PRINT(call->dest_proxy->reg_identity); + PRINT(call->dest_proxy->reg_proxy); + PRINT(call->dest_proxy->reg_route); + + PRINT(sal_op_get_route(call->op)); + PRINT(sal_op_get_from(call->op)); + PRINT(sal_op_get_to(call->op)); + PRINT(sal_op_get_proxy(call->op)); + PRINT(sal_op_get_remote_contact(call->op)); + PRINT(sal_op_get_network_origin(call->op)); + + PRINT(call->log->refkey); + PRINT(call->localdesc->addr); + + PRINT2(call->log->start_date_time, "%ld"); + PRINT2(call->log->start_date_time + call->log->duration, "%ld"); + PRINT(linphone_timestamp_to_rfc3339_string(call->log->start_date_time)); + + + content.type = ms_strdup("application"); + content.subtype = ms_strdup("vq-rtcpxr"); + content.data = ms_strdup_printf(_("VQSessionReport: CallTerm\r\n")); + content.data = ms_strdup_printf(_("%sCallID: %s\r\n"), content.data, call->log->call_id); + content.data = ms_strdup_printf(_("%sLocalID: %s\r\n"), content.data, local_identity); + content.data = ms_strdup_printf(_("%sRemoteID: %s\r\n"), content.data, remote_identity); + content.data = ms_strdup_printf(_("%sOrigID: %s\r\n"), content.data, orig_identity); + + // content.data = ms_strdup_printf(_("%sLocalGroup: %s\r\n"), content.data, "TO_DO"); + // content.data = ms_strdup_printf(_("%sRemoteGroup: %s\r\n"), content.data, "TO_DO"); + content.data = ms_strdup_printf(_("%sLocalAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, local_ip, local_port, local_ssrc); + // content.data = ms_strdup_printf(_("%sLocalMAC: %s\r\n"), content.data, "TO_DO"); + content.data = ms_strdup_printf(_("%sRemoteAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, remote_ip, remote_port, remote_ssrc); + // content.data = ms_strdup_printf(_("%sRemoteMAC: %s\r\n"), content.data, "TO_DO"); + + content.data = ms_strdup_printf(_("%sLocalMetrics:\r\n"), content.data); + content.data = ms_strdup_printf(_("%sTimestamps: START=%s STOP=%s\r\n"), content.data, + linphone_timestamp_to_rfc3339_string(call->log->start_date_time), + linphone_timestamp_to_rfc3339_string(call->log->start_date_time + call->log->duration)); + content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data, "TO_DO"); + + content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data, "TO_DO"); + content.data = ms_strdup_printf(_("%sTimestamps: %s\r\n"), content.data, "TO_DO"); + content.data = ms_strdup_printf(_("%sDialogID: %s\r\n"), content.data, "TO_DO"); + + content.size = strlen((char*)content.data); + + addr = linphone_address_new("sip:collector@sip.linphone.org"); + + ms_message("packet content: %s", (char*)content.data); + linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); + + linphone_address_destroy(addr); +} + diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h new file mode 100644 index 000000000..f56d2b1bd --- /dev/null +++ b/coreapi/quality_reporting.h @@ -0,0 +1,34 @@ +/* +linphone +Copyright (C) 2014 - Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef quality_reporting_h +#define quality_reporting_h + +#include "linphonecore.h" + +#ifdef __cplusplus +extern "C"{ +#endif +void linphone_quality_reporting_submit(LinphoneCall* call); + +#ifdef __cplusplus +} +#endif + +#endif From ce0d3bde0ed0b5ba84fc11a2bc7d61e4f281e80b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 8 Apr 2014 14:37:08 +0200 Subject: [PATCH 02/25] Set timestamp_to_string method accessible from other coreAPI files --- coreapi/presence.c | 4 ++-- coreapi/private.h | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index af4c5184d..08996329f 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -170,7 +170,7 @@ static time_t parse_timestamp(const char *timestamp) { return seconds - timezone; } -static char * timestamp_to_string(time_t timestamp) { +char * linphone_timestamp_to_rfc3339_string(time_t timestamp) { char timestamp_str[22]; struct tm *ret; #ifndef WIN32 @@ -1604,7 +1604,7 @@ static void write_xml_presence_note_obj(LinphonePresenceNote *note, struct _pres static int write_xml_presence_timestamp(xmlTextWriterPtr writer, time_t timestamp) { int err; - char *timestamp_str = timestamp_to_string(timestamp); + char *timestamp_str = linphone_timestamp_to_rfc3339_string(timestamp); err = xmlTextWriterWriteElement(writer, (const xmlChar *)"timestamp", (const xmlChar *)timestamp_str); if (timestamp_str) ms_free(timestamp_str); return err; diff --git a/coreapi/private.h b/coreapi/private.h index 45dc5f305..e2feef54a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -854,11 +854,18 @@ char * linphone_get_xml_text_content(xmlparsing_context_t *xml_ctx, const char * void linphone_free_xml_text_content(const char *text); xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context_t *xml_ctx, const char *xpath_expression); +/***************************************************************************** + * OTHER UTILITY FUNCTIONS * + ****************************************************************************/ +char * linphone_timestamp_to_rfc3339_string(time_t timestamp); + + static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none(); return (const LinphoneErrorInfo*)sal_op_get_error_info(op); } + /** Belle Sip-based objects need unique ids */ From ee0a646d9338d581159223802f74c526ee5af516 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 8 Apr 2014 17:37:28 +0200 Subject: [PATCH 03/25] Use a struct to store reporting data --- coreapi/quality_reporting.c | 165 ++++++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 45 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index e3d25c424..03f9bb65f 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -25,9 +25,105 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "sal/sal.h" -#define PRINT2(x, f) ms_message(#x ": " #f, x) +#define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") +// since printf family functions are LOCALE dependent, float separator may differ +// depending on the user's locale (LC_NUMERIC env var). +static char * float_to_one_decimal_string(float f) { + int floor_part = (int)f; + int one_decimal_part = (int) (10.f * (f - floor_part)); + + return ms_strdup_printf(_("%d.%d"), floor_part, one_decimal_part); +} + +struct _reporting_metrics_st { + time_t ts_start; + time_t ts_stop; + + int sd_pt; + char * sd_pd; + int sd_sr; + int sd_fd; + int sd_fo; + int sd_fpp; + int sd_pps; + char * sd_fmtp; + int sd_plc; + char * sd_ssup; + + int jb_jba; + int jb_jbr; + int jb_jbn; + int jb_jbm; + int jb_jbx; + + float pl_nlr; + float pl_jdr; + + int bgl_bld; + int bgl_bd; + float bgl_gld; + int bgl_gd; + int bgl_gmin; + + int d_rtd; + int d_esd; + int d_sowd; + int d_iaj; + int d_maj; + + int s_sl; + int s_nl; + int s_rerl; + + int qe_rlq; + int qe_rcq; + int qe_extri; + float qe_moslq; + float qe_moscq; + char * qe_qoeestalg; +}; + +static char * add_metrics(char * dest, struct _reporting_metrics_st rm) { + char * tmp = dest; + + dest = ms_strdup_printf(_("%sTimestamps:START=%s STOP=%s\r\n"), tmp, + linphone_timestamp_to_rfc3339_string(rm.ts_start), + linphone_timestamp_to_rfc3339_string(rm.ts_stop)); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sSessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n"), + tmp, rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sJitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n"), + tmp, rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sPacketLoss:NLR=%s JDR=%s\r\n"), + tmp, float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sBurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n"), + tmp, rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sDelay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n"), + tmp, rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sSignal:SL=%d NL=%d RERL=%d\r\n"), + tmp, rm.s_sl, rm.s_nl, rm.s_rerl); + ms_free(tmp); + tmp = dest; + dest = ms_strdup_printf(_("%sQualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n"), + tmp, rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); + ms_free(tmp); + + return dest; +} + void linphone_quality_reporting_submit(LinphoneCall* call) { // example at http://tools.ietf.org/html/rfc6035#section-4.7.3 // only if this is a linphone account @@ -37,21 +133,24 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { // expires value? // un envoi à faire par stream ? (ssrc différent pour chaque stream) // memory leaks - + // belle_sip_snprintf + //ex RERL 404 code différent potentiellement avec info manquante + // 3611 pour savoir les valeurs pour les champs non disponibles LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; + const char *local_ip = "TODO";//stream dependentcall->localdesc->addr; //or call->localip ? + const char *remote_ip = "TODO"; + int local_port = 0; //TODO + int remote_port = 0;//linphone_address_get_port(linphone_call_get_remote_address(call)); + uint32_t local_ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); + uint32_t remote_ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); + struct _reporting_metrics_st local_metrics = {0}; + struct _reporting_metrics_st remote_metrics = {0}; + const char *remote_identity; const char *local_identity; const char *orig_identity; - const char *local_ip = call->localdesc->addr; //or call->localip ? - const char *remote_ip = "TODO"; - uint32_t local_ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); - uint32_t remote_ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); - - int local_port = 0; //TODO - int remote_port = 0;//linphone_address_get_port(linphone_call_get_remote_address(call)); - if (call->dir == LinphoneCallIncoming) { remote_identity = linphone_address_as_string(call->log->from); local_identity = linphone_address_as_string(call->log->to); @@ -64,30 +163,6 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { ms_message("Submitting PUBLISH packet for call between %s and %s", local_identity, remote_identity); - PRINT(call->dest_proxy->contact_params); - PRINT(call->dest_proxy->contact_uri_params); - PRINT(call->dest_proxy->dial_prefix); - PRINT(call->dest_proxy->realm); - PRINT(call->dest_proxy->type); - PRINT(call->dest_proxy->reg_identity); - PRINT(call->dest_proxy->reg_proxy); - PRINT(call->dest_proxy->reg_route); - - PRINT(sal_op_get_route(call->op)); - PRINT(sal_op_get_from(call->op)); - PRINT(sal_op_get_to(call->op)); - PRINT(sal_op_get_proxy(call->op)); - PRINT(sal_op_get_remote_contact(call->op)); - PRINT(sal_op_get_network_origin(call->op)); - - PRINT(call->log->refkey); - PRINT(call->localdesc->addr); - - PRINT2(call->log->start_date_time, "%ld"); - PRINT2(call->log->start_date_time + call->log->duration, "%ld"); - PRINT(linphone_timestamp_to_rfc3339_string(call->log->start_date_time)); - - content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); content.data = ms_strdup_printf(_("VQSessionReport: CallTerm\r\n")); @@ -104,22 +179,22 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { // content.data = ms_strdup_printf(_("%sRemoteMAC: %s\r\n"), content.data, "TO_DO"); content.data = ms_strdup_printf(_("%sLocalMetrics:\r\n"), content.data); - content.data = ms_strdup_printf(_("%sTimestamps: START=%s STOP=%s\r\n"), content.data, - linphone_timestamp_to_rfc3339_string(call->log->start_date_time), - linphone_timestamp_to_rfc3339_string(call->log->start_date_time + call->log->duration)); - content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data, "TO_DO"); - - content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data, "TO_DO"); - content.data = ms_strdup_printf(_("%sTimestamps: %s\r\n"), content.data, "TO_DO"); + local_metrics.ts_start = call->log->start_date_time; + local_metrics.ts_stop = call->log->start_date_time + call->log->duration; + content.data = add_metrics((char*)content.data, local_metrics); + + content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data); + remote_metrics.bgl_gld = 42.34f; + content.data = add_metrics((char*)content.data, remote_metrics); content.data = ms_strdup_printf(_("%sDialogID: %s\r\n"), content.data, "TO_DO"); + // for debug purpose only + PRINT(content.data); + content.size = strlen((char*)content.data); - + addr = linphone_address_new("sip:collector@sip.linphone.org"); - - ms_message("packet content: %s", (char*)content.data); linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); - linphone_address_destroy(addr); } From 2e07b6730fd476f861f97d96ad4bb17b4c597234 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 9 Apr 2014 15:06:56 +0200 Subject: [PATCH 04/25] Continuing quality reporting - use a buffer with belle_sip_snprintf instead of ms_strdup_printf (multiple new allocations) --- coreapi/quality_reporting.c | 224 ++++++++++++++++++++++-------------- 1 file changed, 140 insertions(+), 84 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 03f9bb65f..cee2d8a4a 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -25,22 +25,68 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "sal/sal.h" +#include + #define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") // since printf family functions are LOCALE dependent, float separator may differ // depending on the user's locale (LC_NUMERIC env var). static char * float_to_one_decimal_string(float f) { - int floor_part = (int)f; - int one_decimal_part = (int) (10.f * (f - floor_part)); + float rounded_f = floorf(f * 10 + .5f) / 10; + + int floor_part = (int) rounded_f; + int one_decimal_part = floorf (10 * (rounded_f - floor_part) + .5f); return ms_strdup_printf(_("%d.%d"), floor_part, one_decimal_part); } -struct _reporting_metrics_st { +static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offset, const char *fmt, va_list args) { + belle_sip_error_code ret; + size_t prevoffset = *offset; + +#ifndef WIN32 + va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ + va_copy(cap,args); + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, cap); + va_end(cap); +#else + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, args); +#endif + + // if we are out of memory, we add some size to buffer + if (ret == BELLE_SIP_BUFFER_OVERFLOW) { + ms_warning("Buffer was too small to contain the whole report - doubling its size from %lu to %lu", *buff_size, 2 * *buff_size); + *buff_size += 2048; + *buff = (char *) ms_realloc(*buff, *buff_size); + + *offset = prevoffset; + // recall myself since we did not write all things into the buffer but + // only part of it + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + } +} + +static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + va_end(args); +} + + +struct _reporting_addr_st { + char * ip; + int port; + uint32_t ssrc; +}; + +struct _reporting_content_metrics_st { + // timestamps - mandatory time_t ts_start; time_t ts_stop; + // session description - optional int sd_pt; char * sd_pd; int sd_sr; @@ -52,31 +98,37 @@ struct _reporting_metrics_st { int sd_plc; char * sd_ssup; + // jitter buffet - optional int jb_jba; int jb_jbr; int jb_jbn; int jb_jbm; int jb_jbx; + // packet loss - optional float pl_nlr; float pl_jdr; + // burst gap loss - optional int bgl_bld; int bgl_bd; float bgl_gld; int bgl_gd; int bgl_gmin; + // delay - optional int d_rtd; int d_esd; int d_sowd; int d_iaj; int d_maj; + // signal - optional int s_sl; int s_nl; int s_rerl; + // quality estimates - optional int qe_rlq; int qe_rcq; int qe_extri; @@ -85,43 +137,66 @@ struct _reporting_metrics_st { char * qe_qoeestalg; }; -static char * add_metrics(char * dest, struct _reporting_metrics_st rm) { - char * tmp = dest; +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; - dest = ms_strdup_printf(_("%sTimestamps:START=%s STOP=%s\r\n"), tmp, + 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.remote_addr.ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); + stats.info.call_id = call->log->call_id; + 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; + } 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.local_metrics.ts_start = call->log->start_date_time; + stats.local_metrics.ts_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) { + append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s\r\n", linphone_timestamp_to_rfc3339_string(rm.ts_start), linphone_timestamp_to_rfc3339_string(rm.ts_stop)); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sSessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n"), - tmp, rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sJitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n"), - tmp, rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sPacketLoss:NLR=%s JDR=%s\r\n"), - tmp, float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sBurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n"), - tmp, rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sDelay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n"), - tmp, rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sSignal:SL=%d NL=%d RERL=%d\r\n"), - tmp, rm.s_sl, rm.s_nl, rm.s_rerl); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sQualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n"), - tmp, rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); - ms_free(tmp); - - return dest; + append_to_buffer(buffer, size, offset, "SessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n", + rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); + append_to_buffer(buffer, size, offset, "JitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n", + rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); + append_to_buffer(buffer, size, offset, "PacketLoss:NLR=%s JDR=%s\r\n", + float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); + append_to_buffer(buffer, size, offset, "BurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n", + rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); + append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", + rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); + append_to_buffer(buffer, size, offset, "Signal:SL=%d NL=%d RERL=%d\r\n", + rm.s_sl, rm.s_nl, rm.s_rerl); + append_to_buffer(buffer, size, offset, "QualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n", + rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); } void linphone_quality_reporting_submit(LinphoneCall* call) { @@ -131,62 +206,43 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { // to: collector@sip.linphone.com // executed AFTER BYE's "OK" response has been received // expires value? - // un envoi à faire par stream ? (ssrc différent pour chaque stream) - // memory leaks - // belle_sip_snprintf - //ex RERL 404 code différent potentiellement avec info manquante + // one send by stream (different ssrc) + // memory leaks strings - append_to_buffer + // ex RERL 404 code différent potentiellement avec info manquante // 3611 pour savoir les valeurs pour les champs non disponibles LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; - const char *local_ip = "TODO";//stream dependentcall->localdesc->addr; //or call->localip ? - const char *remote_ip = "TODO"; - int local_port = 0; //TODO - int remote_port = 0;//linphone_address_get_port(linphone_call_get_remote_address(call)); - uint32_t local_ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); - uint32_t remote_ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); - struct _reporting_metrics_st local_metrics = {0}; - struct _reporting_metrics_st remote_metrics = {0}; - - const char *remote_identity; - const char *local_identity; - const char *orig_identity; - if (call->dir == LinphoneCallIncoming) { - remote_identity = linphone_address_as_string(call->log->from); - local_identity = linphone_address_as_string(call->log->to); - orig_identity = remote_identity; - } else { - remote_identity = linphone_address_as_string(call->log->to); - local_identity = linphone_address_as_string(call->log->from); - orig_identity = local_identity; - } - - ms_message("Submitting PUBLISH packet for call between %s and %s", local_identity, remote_identity); - + struct _reporting_session_report_st stats = get_stats(call); + size_t offset = 0; + size_t size = 2048; + char * buffer = (char *) malloc(sizeof(char) * size); content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); - content.data = ms_strdup_printf(_("VQSessionReport: CallTerm\r\n")); - content.data = ms_strdup_printf(_("%sCallID: %s\r\n"), content.data, call->log->call_id); - content.data = ms_strdup_printf(_("%sLocalID: %s\r\n"), content.data, local_identity); - content.data = ms_strdup_printf(_("%sRemoteID: %s\r\n"), content.data, remote_identity); - content.data = ms_strdup_printf(_("%sOrigID: %s\r\n"), content.data, orig_identity); - // content.data = ms_strdup_printf(_("%sLocalGroup: %s\r\n"), content.data, "TO_DO"); - // content.data = ms_strdup_printf(_("%sRemoteGroup: %s\r\n"), content.data, "TO_DO"); - content.data = ms_strdup_printf(_("%sLocalAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, local_ip, local_port, local_ssrc); - // content.data = ms_strdup_printf(_("%sLocalMAC: %s\r\n"), content.data, "TO_DO"); - content.data = ms_strdup_printf(_("%sRemoteAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, remote_ip, remote_port, remote_ssrc); - // content.data = ms_strdup_printf(_("%sRemoteMAC: %s\r\n"), content.data, "TO_DO"); + 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, "LocalGroup: %s\r\n", stats.info.local_group); + append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", stats.info.remote_group); + 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); - content.data = ms_strdup_printf(_("%sLocalMetrics:\r\n"), content.data); - local_metrics.ts_start = call->log->start_date_time; - local_metrics.ts_stop = call->log->start_date_time + call->log->duration; - content.data = add_metrics((char*)content.data, local_metrics); + append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); + add_metrics(&buffer, &size, &offset, stats.local_metrics); - content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data); - remote_metrics.bgl_gld = 42.34f; - content.data = add_metrics((char*)content.data, remote_metrics); - content.data = ms_strdup_printf(_("%sDialogID: %s\r\n"), content.data, "TO_DO"); + 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); + } + + content.data = buffer; // for debug purpose only PRINT(content.data); From b32e79218d93059be61486b56cef9d49d87224eb Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 9 Apr 2014 16:03:09 +0200 Subject: [PATCH 05/25] Quality reporting: added all fields and a bit of refactoring --- coreapi/quality_reporting.c | 159 ++++++++++++++++++++++++------------ 1 file changed, 105 insertions(+), 54 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index cee2d8a4a..f07b363ff 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -83,58 +83,85 @@ struct _reporting_addr_st { struct _reporting_content_metrics_st { // timestamps - mandatory - time_t ts_start; - time_t ts_stop; + struct { + time_t start; + time_t stop; + } timestamps; // session description - optional - int sd_pt; - char * sd_pd; - int sd_sr; - int sd_fd; - int sd_fo; - int sd_fpp; - int sd_pps; - char * sd_fmtp; - int sd_plc; - char * sd_ssup; + struct { + int payload_type; + char * payload_desc; //mime type + int sample_rate; //clock rate + int frame_duration; //(no) ptime? à vérifier - 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; //voip metrics - audio only + char * silence_suppression_state; //no + } session_description; // jitter buffet - optional - int jb_jba; - int jb_jbr; - int jb_jbn; - int jb_jbm; - int jb_jbx; + 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 - float pl_nlr; - float pl_jdr; + struct { + float network_packet_loss_rate; // voip metrics (loss rate) + conversion + float jitter_buffer_discard_rate; //idem + } packet_loss; - // burst gap loss - optional - int bgl_bld; - int bgl_bd; - float bgl_gld; - int bgl_gd; - int bgl_gmin; + // 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 - int d_rtd; - int d_esd; - int d_sowd; - int d_iaj; - int d_maj; + 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 - int s_sl; - int s_nl; - int s_rerl; + struct { + int level; // no - vary + int noise_level; // no - vary + int residual_echo_return_loss; // no + } signal; // quality estimates - optional - int qe_rlq; - int qe_rcq; - int qe_extri; - float qe_moslq; - float qe_moscq; - char * qe_qoeestalg; + struct { + int rlq; // linked to moslq + int rcq; //voip metrics R factor - no - vary or avg + float moslq; // no - vary or avg - voip metrics + float moscq; // no - vary or avg - voip metrics + + + 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 { @@ -161,8 +188,19 @@ struct _reporting_session_report_st { 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); + // rtp_stats-> + + stats.local_metrics.session_description.payload_type = call->params.audio_codec->type; + 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); @@ -172,8 +210,8 @@ struct _reporting_session_report_st get_stats(LinphoneCall * call) { stats.info.local_id = linphone_address_as_string(call->log->from); stats.info.orig_id = stats.info.local_id; } - stats.local_metrics.ts_start = call->log->start_date_time; - stats.local_metrics.ts_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; } @@ -181,22 +219,35 @@ struct _reporting_session_report_st get_stats(LinphoneCall * call) { static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _reporting_content_metrics_st rm) { append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s\r\n", - linphone_timestamp_to_rfc3339_string(rm.ts_start), - linphone_timestamp_to_rfc3339_string(rm.ts_stop)); + linphone_timestamp_to_rfc3339_string(rm.timestamps.start), + linphone_timestamp_to_rfc3339_string(rm.timestamps.stop)); append_to_buffer(buffer, size, offset, "SessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n", - rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); + rm.session_description.payload_type, rm.session_description.payload_desc, rm.session_description.sample_rate, + rm.session_description.frame_duration, rm.session_description.frame_ocets, rm.session_description.frames_per_sec, + rm.session_description.packets_per_sec, rm.session_description.fmtp, rm.session_description.packet_loss_concealment, + rm.session_description.silence_suppression_state); append_to_buffer(buffer, size, offset, "JitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n", - rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); + rm.jitter_buffer.adaptive, rm.jitter_buffer.rate, rm.jitter_buffer.nominal, rm.jitter_buffer.max, rm.jitter_buffer.abs_max); append_to_buffer(buffer, size, offset, "PacketLoss:NLR=%s JDR=%s\r\n", - float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); + float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate), + float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate)); append_to_buffer(buffer, size, offset, "BurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n", - rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); - append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", - rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); + rm.burst_gap_loss.burst_loss_density, rm.burst_gap_loss.burst_duration, + float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density), rm.burst_gap_loss.gap_Duration, + rm.burst_gap_loss.min_gap_threshold); + append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d OWD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", + rm.delay.round_trip_delay, rm.delay.end_system_delay, rm.delay.one_way_delay, rm.delay.symm_one_way_delay, + rm.delay.interarrival_jitter, rm.delay.mean_abs_jitter); append_to_buffer(buffer, size, offset, "Signal:SL=%d NL=%d RERL=%d\r\n", - rm.s_sl, rm.s_nl, rm.s_rerl); - append_to_buffer(buffer, size, offset, "QualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n", - rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); + rm.signal.level, rm.signal.noise_level, rm.signal.residual_echo_return_loss); + append_to_buffer(buffer, size, offset, "QualityEst:RLQ=%d RLQEstAlg=%s RCQ=%d RCQEstAlgo=%s EXTRI=%d ExtRIEstAlg=%s EXTRO=%d ExtROEstAlg=%s MOSLQ=%s MOSLQEstAlgo=%s MOSCQ=%s MOSCQEstAlgo=%s QoEEstAlg=%s\r\n", + rm.quality_estimates.rlq, rm.quality_estimates.rlqestalg, + rm.quality_estimates.rcq, rm.quality_estimates.rcqestalg, + rm.quality_estimates.extri, rm.quality_estimates.extriestalg, + rm.quality_estimates.extro, rm.quality_estimates.extroutestalg, + float_to_one_decimal_string(rm.quality_estimates.moslq), rm.quality_estimates.moslqestalg, + float_to_one_decimal_string(rm.quality_estimates.moscq), rm.quality_estimates.moscqestalg, + rm.quality_estimates.qoestalg); } void linphone_quality_reporting_submit(LinphoneCall* call) { @@ -226,8 +277,8 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { 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); - append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", stats.info.remote_group); + 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); From e6524c1d8f035ed5bf12c1874738fa13e2632231 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 11:24:54 +0200 Subject: [PATCH 06/25] Quality reporting: filling some available fields from reporting struct --- coreapi/quality_reporting.c | 120 +++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index f07b363ff..84271287d 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -27,6 +27,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include +/*************************************************************************** + * TODO / REMINDER LIST + ****************************************************************************/ + // example at http://tools.ietf.org/html/rfc6035#section-4.7.3 + // only if this is a linphone account + // only if call succeeded + // executed AFTER BYE's "OK" response has been received + // to: collector@sip.linphone.com or not + // expires value? + // one send by stream (different ssrc) + // ex RERL 404 code différent potentiellement avec info manquante + // 3611 pour savoir les valeurs pour les champs non disponibles + // video : que se passe t-il si on arrete / resume la vidéo + // memory leaks + #define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") @@ -45,14 +60,14 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs belle_sip_error_code ret; size_t prevoffset = *offset; -#ifndef WIN32 + #ifndef WIN32 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ va_copy(cap,args); ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, cap); va_end(cap); -#else + #else ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, args); -#endif + #endif // if we are out of memory, we add some size to buffer if (ret == BELLE_SIP_BUFFER_OVERFLOW) { @@ -62,7 +77,7 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs *offset = prevoffset; // recall myself since we did not write all things into the buffer but - // only part of it + // only a part of it append_to_buffer_valist(buff, buff_size, offset, fmt, args); } } @@ -91,15 +106,15 @@ struct _reporting_content_metrics_st { // session description - optional struct { int payload_type; - char * payload_desc; //mime type - int sample_rate; //clock rate - int frame_duration; //(no) ptime? à vérifier - 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; //voip metrics - audio only - char * silence_suppression_state; //no + 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 @@ -146,10 +161,10 @@ struct _reporting_content_metrics_st { // quality estimates - optional struct { - int rlq; // linked to moslq - int rcq; //voip metrics R factor - no - vary or avg - float moslq; // no - vary or avg - voip metrics - float moscq; // no - vary or avg - voip metrics + 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 @@ -197,9 +212,35 @@ struct _reporting_session_report_st get_stats(LinphoneCall * call) { // call->resultdesc->streams[0].rtp_addr // const rtp_stats_t * rtp_stats = rtp_session_get_stats(call->audiostream->ms.session); - // rtp_stats-> + const MSQualityIndicator * qi = media_stream_get_quality_indicator(&call->audiostream->ms); 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; + } + 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 + // int packet_loss_concealment; // in voip metrics - audio only + // jitter buffer + // jitter_buffer_discard_rate if (call->dir == LinphoneCallIncoming) { stats.info.remote_id = linphone_address_as_string(call->log->from); @@ -216,11 +257,17 @@ struct _reporting_session_report_st get_stats(LinphoneCall * call) { return stats; } +static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _reporting_content_metrics_st 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); + char * jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate); + char * gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density); + char * moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq); + char * moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq); -static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _reporting_content_metrics_st rm) { append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s\r\n", - linphone_timestamp_to_rfc3339_string(rm.timestamps.start), - linphone_timestamp_to_rfc3339_string(rm.timestamps.stop)); + timpstamps_start_str, timpstamps_stop_str); append_to_buffer(buffer, size, offset, "SessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n", rm.session_description.payload_type, rm.session_description.payload_desc, rm.session_description.sample_rate, rm.session_description.frame_duration, rm.session_description.frame_ocets, rm.session_description.frames_per_sec, @@ -229,11 +276,11 @@ static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _ append_to_buffer(buffer, size, offset, "JitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n", rm.jitter_buffer.adaptive, rm.jitter_buffer.rate, rm.jitter_buffer.nominal, rm.jitter_buffer.max, rm.jitter_buffer.abs_max); append_to_buffer(buffer, size, offset, "PacketLoss:NLR=%s JDR=%s\r\n", - float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate), - float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate)); + network_packet_loss_rate_str, + jitter_buffer_discard_rate_str); append_to_buffer(buffer, size, offset, "BurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n", rm.burst_gap_loss.burst_loss_density, rm.burst_gap_loss.burst_duration, - float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density), rm.burst_gap_loss.gap_Duration, + gap_loss_density_str, rm.burst_gap_loss.gap_Duration, rm.burst_gap_loss.min_gap_threshold); append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d OWD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", rm.delay.round_trip_delay, rm.delay.end_system_delay, rm.delay.one_way_delay, rm.delay.symm_one_way_delay, @@ -245,29 +292,28 @@ static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _ rm.quality_estimates.rcq, rm.quality_estimates.rcqestalg, rm.quality_estimates.extri, rm.quality_estimates.extriestalg, rm.quality_estimates.extro, rm.quality_estimates.extroutestalg, - float_to_one_decimal_string(rm.quality_estimates.moslq), rm.quality_estimates.moslqestalg, - float_to_one_decimal_string(rm.quality_estimates.moscq), rm.quality_estimates.moscqestalg, + moslq_str, rm.quality_estimates.moslqestalg, + moscq_str, rm.quality_estimates.moscqestalg, rm.quality_estimates.qoestalg); + + free(timpstamps_start_str); + free(timpstamps_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); } void linphone_quality_reporting_submit(LinphoneCall* call) { - // example at http://tools.ietf.org/html/rfc6035#section-4.7.3 - // only if this is a linphone account - // only if call succeeded - // to: collector@sip.linphone.com - // executed AFTER BYE's "OK" response has been received - // expires value? - // one send by stream (different ssrc) - // memory leaks strings - append_to_buffer - // ex RERL 404 code différent potentiellement avec info manquante - // 3611 pour savoir les valeurs pour les champs non disponibles LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; struct _reporting_session_report_st stats = get_stats(call); size_t offset = 0; size_t size = 2048; - char * buffer = (char *) malloc(sizeof(char) * size); + char * buffer = (char *) ms_malloc(size); + content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); From 3c71544b24ef3f5421b2fd9bb789d9af59188b84 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 12:58:08 +0200 Subject: [PATCH 07/25] 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 From 0200eb2213dae5d1fc613f18ddf2cd4d37de89bd Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 16:04:48 +0200 Subject: [PATCH 08/25] Quality reporting: remove unimplemented fields and split content filling to an one-field-at-a-time process --- coreapi/linphonecall.c | 8 +- coreapi/linphonecore.c | 2 +- coreapi/private.h | 3 +- coreapi/quality_reporting.c | 289 +++++++++++++++++++++++++----------- coreapi/quality_reporting.h | 38 ++--- 5 files changed, 227 insertions(+), 113 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f9574f576..d1e2d15b7 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1849,7 +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); + call->reports[LINPHONE_CALL_STATS_AUDIO]=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); @@ -1979,7 +1979,7 @@ 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); + call->reports[LINPHONE_CALL_STATS_VIDEO]=ms_new0(reporting_session_report_t,1); if (used_pt!=-1){ VideoStreamDir dir=VideoStreamSendRecv; @@ -2752,6 +2752,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { @@ -2762,6 +2763,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) @@ -2797,6 +2799,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream); + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_AUDIO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { @@ -2807,6 +2810,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_AUDIO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO],(MediaStream*)call->audiostream); + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_AUDIO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]); } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 23090baba..12078604b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3470,7 +3470,7 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ /*stop ringing*/ linphone_core_stop_ringing(lc); - linphone_quality_reporting_submit(call); + linphone_reporting_publish(call, LINPHONE_CALL_STATS_AUDIO); linphone_call_stop_media_streams(call); diff --git a/coreapi/private.h b/coreapi/private.h index 9e37f11b7..4d32a23e6 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -193,8 +193,7 @@ struct _LinphoneCall struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; - reporting_session_report_t *audio_reporting; - reporting_session_report_t *video_reporting; + reporting_session_report_t * reports[2]; MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 5e82b4a96..dc1b1c511 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -40,7 +40,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // ex RERL 404 code différent potentiellement avec info manquante // 3611 pour savoir les valeurs pour les champs non disponibles // video : que se passe t-il si on arrete / resume la vidéo - // memory leaks + // memory leaks + char* strdup + // bouger l'appel de fonction au bon endroit (si c l'autre qui raccroche on envoi pas les données là) #define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") @@ -89,79 +90,90 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } -reporting_session_report_t * update_stats(LinphoneCall * call) { +static reporting_session_report_t * update_report(LinphoneCall * call, int stats_type) { int count; - reporting_session_report_t * stats = call->audio_reporting; - const MSQualityIndicator * qi = media_stream_get_quality_indicator(&call->audiostream->ms); + reporting_session_report_t * report = call->reports[stats_type]; + MediaStream stream; + const MSQualityIndicator * qi = NULL; const PayloadType * payload; + RtpSession * session = NULL; - if (stats == NULL) { + + if (report == NULL) { ms_warning("No reporting created for this stream"); return NULL; } - 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; + if (stats_type == LINPHONE_CALL_STATS_AUDIO) { + stream = call->audiostream->ms; + payload = call->current_params.audio_codec; + } else { + stream = call->videostream->ms; + payload = call->current_params.video_codec; + } + session = stream.sessions.rtp_session; + qi = media_stream_get_quality_indicator(&stream); + + report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); + report->info.local_addr.port = rtp_session_get_local_port(session); + report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); + // memcpy(report->info.remote_addr.ip, &session->rtp.rem_addr, session->rtp.rem_addrlen); + report->info.call_id = call->log->call_id; + report->info.local_group = ms_strdup_printf(_("linphone-%s"), report->info.call_id); + report->info.remote_group = ms_strdup(report->info.local_group); 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; + if (call->resultdesc->streams[count].type == stats_type) { + report->info.local_addr.ip = ms_strdup(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); + ms_warning("Could not find the associated stream of type %d", stats_type); } - 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); + report->local_metrics.session_description.payload_type = payload->type; + report->local_metrics.session_description.payload_desc = ms_strdup(payload->mime_type); + report->local_metrics.session_description.sample_rate = payload->clock_rate; + report->local_metrics.session_description.fmtp = ms_strdup(payload->recv_fmtp); } else { // ... } - //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; + //report->local_metrics.session_description.packet_loss_concealment = ms_quality_indicator_get_local_late_rate(qi); + report->local_metrics.packet_loss.jitter_buffer_discard_rate = ms_quality_indicator_get_local_loss_rate(qi); + report->local_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); + if (10 <= report->local_metrics.quality_estimates.rlq + && report->local_metrics.quality_estimates.rlq <= 50) { + report->local_metrics.quality_estimates.moslq = report->local_metrics.quality_estimates.rlq / 10.f; } else { - stats->local_metrics.quality_estimates.moslq = -1; + report->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; + report->local_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); + if (10 <= report->local_metrics.quality_estimates.rcq + && report->local_metrics.quality_estimates.rcq <= 50) { + report->local_metrics.quality_estimates.moscq = report->local_metrics.quality_estimates.rcq / 10.f; } else { - stats->local_metrics.quality_estimates.moscq = -1; + report->local_metrics.quality_estimates.moscq = -1; } - // NOT FOUND - // int packet_loss_concealment; // in voip metrics - audio only - // jitter buffer - // 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; + 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 = report->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; + 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 = report->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); + 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); - return stats; + return report; } +#define APPEND_STR_TO_BUFFER(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg); + 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); @@ -171,35 +183,67 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off char * moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq); char * moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq); - append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s\r\n", + append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s", timpstamps_start_str, timpstamps_stop_str); - append_to_buffer(buffer, size, offset, "SessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n", - rm.session_description.payload_type, rm.session_description.payload_desc, rm.session_description.sample_rate, - rm.session_description.frame_duration, rm.session_description.frame_ocets, rm.session_description.frames_per_sec, - rm.session_description.packets_per_sec, rm.session_description.fmtp, rm.session_description.packet_loss_concealment, - rm.session_description.silence_suppression_state); - append_to_buffer(buffer, size, offset, "JitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n", - rm.jitter_buffer.adaptive, rm.jitter_buffer.rate, rm.jitter_buffer.nominal, rm.jitter_buffer.max, rm.jitter_buffer.abs_max); - append_to_buffer(buffer, size, offset, "PacketLoss:NLR=%s JDR=%s\r\n", - network_packet_loss_rate_str, - jitter_buffer_discard_rate_str); - append_to_buffer(buffer, size, offset, "BurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n", - rm.burst_gap_loss.burst_loss_density, rm.burst_gap_loss.burst_duration, - gap_loss_density_str, rm.burst_gap_loss.gap_Duration, - rm.burst_gap_loss.min_gap_threshold); - append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d OWD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", - rm.delay.round_trip_delay, rm.delay.end_system_delay, rm.delay.one_way_delay, rm.delay.symm_one_way_delay, - rm.delay.interarrival_jitter, rm.delay.mean_abs_jitter); - append_to_buffer(buffer, size, offset, "Signal:SL=%d NL=%d RERL=%d\r\n", - rm.signal.level, rm.signal.noise_level, rm.signal.residual_echo_return_loss); - append_to_buffer(buffer, size, offset, "QualityEst:RLQ=%d RLQEstAlg=%s RCQ=%d RCQEstAlgo=%s EXTRI=%d ExtRIEstAlg=%s EXTRO=%d ExtROEstAlg=%s MOSLQ=%s MOSLQEstAlgo=%s MOSCQ=%s MOSCQEstAlgo=%s QoEEstAlg=%s\r\n", - rm.quality_estimates.rlq, rm.quality_estimates.rlqestalg, - rm.quality_estimates.rcq, rm.quality_estimates.rcqestalg, - rm.quality_estimates.extri, rm.quality_estimates.extriestalg, - rm.quality_estimates.extro, rm.quality_estimates.extroutestalg, - moslq_str, rm.quality_estimates.moslqestalg, - moscq_str, rm.quality_estimates.moscqestalg, - rm.quality_estimates.qoestalg); + + append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); + append_to_buffer(buffer, size, offset, " PT=%d", rm.session_description.payload_type); + APPEND_STR_TO_BUFFER(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); + append_to_buffer(buffer, size, offset, " SR=%d", rm.session_description.sample_rate); + append_to_buffer(buffer, size, offset, " FD=%d", rm.session_description.frame_duration); + // append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets); + // append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec); + // append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec); + APPEND_STR_TO_BUFFER(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); + append_to_buffer(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state); + + append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); + append_to_buffer(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive); + append_to_buffer(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate); + append_to_buffer(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal); + append_to_buffer(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max); + append_to_buffer(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max); + + append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); + APPEND_STR_TO_BUFFER(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); + APPEND_STR_TO_BUFFER(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); + + append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:"); + append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); + append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); + APPEND_STR_TO_BUFFER(buffer, size, offset, " GLD=%s", gap_loss_density_str); + append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_Duration); + append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); + + append_to_buffer(buffer, size, offset, "\r\nDelay:"); + append_to_buffer(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay); + append_to_buffer(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay); + // append_to_buffer(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay); + append_to_buffer(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay); + append_to_buffer(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter); + append_to_buffer(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter); + + append_to_buffer(buffer, size, offset, "\r\nSignal:"); + append_to_buffer(buffer, size, offset, " SL=%d", rm.signal.level); + append_to_buffer(buffer, size, offset, " NL=%d", rm.signal.noise_level); + // append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss); + + append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); + append_to_buffer(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg); + append_to_buffer(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg); + // append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg); + // append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg); + APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSLQ=%s", moslq_str); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg); + APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSCQ=%s", moscq_str); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg); + append_to_buffer(buffer, size, offset, "\r\n"); free(timpstamps_start_str); free(timpstamps_stop_str); @@ -210,17 +254,17 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off free(moscq_str); } -void linphone_quality_reporting_submit(LinphoneCall* call) { +void linphone_reporting_publish(LinphoneCall* call, int stats_type) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; - reporting_session_report_t *stats = update_stats(call); + reporting_session_report_t *report = update_report(call, stats_type); size_t offset = 0; size_t size = 2048; char * buffer; // Somehow the reporting was not created, hence no need to go further - if (stats == NULL) { + if (report == NULL) { PRINT("STATS ARE NULL!"); return; } @@ -231,25 +275,25 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { 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", report->info.call_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); + append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->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); + if (report->info.local_group != NULL) append_to_buffer(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); + if (report->info.remote_group != NULL) append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); + if (report->info.local_mac_addr != NULL) append_to_buffer(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); + if (report->info.remote_mac_addr != NULL) append_to_buffer(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); - append_metrics_to_buffer(&buffer, &size, &offset, stats->local_metrics); + append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); - 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); + append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); + if (report->dialog_id != NULL) { + append_to_buffer(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); } content.data = buffer; @@ -264,3 +308,70 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { linphone_address_destroy(addr); } + +void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { + reporting_session_report_t * report = call->reports[stats_type]; + reporting_content_metrics_t * metrics = NULL; + reporting_addr_t * addr = NULL; + + LinphoneCallStats stats = call->stats[stats_type]; + mblk_t *block = NULL; + + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { + metrics = &report->remote_metrics; + addr = &report->info.remote_addr; + if (rtcp_is_XR(stats.received_rtcp) == TRUE) { + block = stats.received_rtcp; + } + } else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) { + metrics = &report->local_metrics; + addr = &report->info.local_addr; + if (rtcp_is_XR(stats.sent_rtcp) == TRUE) { + block = stats.sent_rtcp; + } + } + if (block != NULL) { + switch (rtcp_XR_get_block_type(block)) { + case RTCP_XR_STAT_SUMMARY: + // rtcp_XR_stat_summary_get_flags(block); + // rtcp_XR_stat_summary_get_ssrc(block); + // rtcp_XR_stat_summary_get_begin_seq(block); + // rtcp_XR_stat_summary_get_end_seq(block); + // rtcp_XR_stat_summary_get_lost_packets(block); + // rtcp_XR_stat_summary_get_dup_packets(block); + // rtcp_XR_stat_summary_get_min_jitter(block); + metrics->jitter_buffer.max = rtcp_XR_stat_summary_get_max_jitter(block); + // rtcp_XR_stat_summary_get_mean_jitter(block); + // rtcp_XR_stat_summary_get_dev_jitter(block); + // rtcp_XR_stat_summary_get_min_ttl_or_hl(block); + // rtcp_XR_stat_summary_get_max_ttl_or_hl(block); + // rtcp_XR_stat_summary_get_mean_ttl_or_hl(block); + // rtcp_XR_stat_summary_get_dev_ttl_or_hl(block); + break; + case RTCP_XR_VOIP_METRICS: + addr->ssrc = rtcp_XR_voip_metrics_get_ssrc(block); + // rtcp_XR_voip_metrics_get_loss_rate(block); + // rtcp_XR_voip_metrics_get_discard_rate(block); + // rtcp_XR_voip_metrics_get_burst_density(block); + // rtcp_XR_voip_metrics_get_gap_density(block); + // rtcp_XR_voip_metrics_get_burst_duration(block); + // rtcp_XR_voip_metrics_get_gap_duration(block); + // rtcp_XR_voip_metrics_get_round_trip_delay(block); + // rtcp_XR_voip_metrics_get_end_system_delay(block); + // rtcp_XR_voip_metrics_get_signal_level(block); + // rtcp_XR_voip_metrics_get_noise_level(block); + // rtcp_XR_voip_metrics_get_rerl(block); + // rtcp_XR_voip_metrics_get_gmin(block); + metrics->quality_estimates.rlq = rtcp_XR_voip_metrics_get_r_factor(block); + metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block); + metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block); + // rtcp_XR_voip_metrics_get_rx_config(block); + 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); + break; + default: + break; + } + } +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index b8b1a42e4..7e5831212 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -45,12 +45,12 @@ typedef struct reporting_content_metrics { 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 frame_ocets; + // int frames_per_sec; + // int packets_per_sec; + char * fmtp; int packet_loss_concealment; // in voip metrics - audio only - char * silence_suppression_state; // no + // char * silence_suppression_state; } session_description; // jitter buffet - optional @@ -82,17 +82,17 @@ typedef struct reporting_content_metrics { struct { int round_trip_delay; // no - vary int end_system_delay; // no - not implemented yet - int one_way_delay; // no + // int one_way_delay; 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 + int mean_abs_jitter; // to check } delay; // signal - optional struct { int level; // no - vary int noise_level; // no - vary - int residual_echo_return_loss; // no + // int residual_echo_return_loss; } signal; // quality estimates - optional @@ -103,15 +103,15 @@ typedef struct reporting_content_metrics { 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; + // int extri; + // int extro; + // char * rlqestalg; + // char * rcqestalg; + // char * moslqestalg; + // char * moscqestalg; + // char * extriestalg; + // char * extroutestalg; + // char * qoestalg; } quality_estimates; } reporting_content_metrics_t; @@ -137,8 +137,8 @@ typedef struct reporting_session_report { } reporting_session_report_t; -void linphone_quality_reporting_submit(LinphoneCall* call); - +void linphone_reporting_publish(LinphoneCall* call, int stats_type); +void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); #ifdef __cplusplus } #endif From 23cbf843e9363961f4d91fe32b76549f52079fed Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 16:49:03 +0200 Subject: [PATCH 09/25] Quality reporting: Remove burst gap loss since it is not implemented yet --- coreapi/linphonecore.c | 3 ++ coreapi/quality_reporting.c | 84 +++++++++++++++++++++++-------------- coreapi/quality_reporting.h | 14 +++---- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 12078604b..9468189f8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3471,6 +3471,9 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ linphone_core_stop_ringing(lc); linphone_reporting_publish(call, LINPHONE_CALL_STATS_AUDIO); + if (call->videostream!=NULL){ + linphone_reporting_publish(call, LINPHONE_CALL_STATS_VIDEO); + } linphone_call_stop_media_streams(call); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index dc1b1c511..ff8ada7e9 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -30,18 +30,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST ****************************************************************************/ - // example at http://tools.ietf.org/html/rfc6035#section-4.7.3 - // only if this is a linphone account - // only if call succeeded - // executed AFTER BYE's "OK" response has been received - // to: collector@sip.linphone.com or not - // expires value? - // one send by stream (different ssrc) - // ex RERL 404 code différent potentiellement avec info manquante - // 3611 pour savoir les valeurs pour les champs non disponibles - // video : que se passe t-il si on arrete / resume la vidéo + // place pour appeler la fonction submit + // only if call succeeded + // executed AFTER BYE's "OK" response has been received + // si c l'autre qui raccroche on envoi pas les données là // memory leaks + char* strdup - // bouger l'appel de fonction au bon endroit (si c l'autre qui raccroche on envoi pas les données là) + // si aucune data d'une catégorie est renseigné, ne pas mettre la section dans le paquet + // stats + // valeur pour "expires" ? + // packet_loss_concealment + // jitter buffer rate / adaptive + // jitter_buffer_discard_rate; + // network_packet_loss_rate + // vérifier les valeurs par défaut etc. + // ip local potientellement vide + // remote : ip, port, timestamps, session desc + // dialog id ? + // à voir : + // video : que se passe t-il si on arrete / resume la vidéo (new stream) + // valeurs instanannées : moyenne ? valeur extreme ? + // à qui / comment on envoit ? (collector@sip.linphone.com ?) + // only if this is a linphone account? #define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") @@ -139,9 +148,7 @@ static reporting_session_report_t * update_report(LinphoneCall * call, int stats } else { // ... } - - //report->local_metrics.session_description.packet_loss_concealment = ms_quality_indicator_get_local_late_rate(qi); - report->local_metrics.packet_loss.jitter_buffer_discard_rate = ms_quality_indicator_get_local_loss_rate(qi); + report->local_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); if (10 <= report->local_metrics.quality_estimates.rlq && report->local_metrics.quality_estimates.rlq <= 50) { @@ -169,6 +176,23 @@ static reporting_session_report_t * update_report(LinphoneCall * call, int stats 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); + + + report->remote_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); + if (10 <= report->remote_metrics.quality_estimates.rlq + && report->remote_metrics.quality_estimates.rlq <= 50) { + report->remote_metrics.quality_estimates.moslq = report->remote_metrics.quality_estimates.rlq / 10.f; + } else { + report->remote_metrics.quality_estimates.moslq = -1; + } + report->remote_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); + if (10 <= report->remote_metrics.quality_estimates.rcq + && report->remote_metrics.quality_estimates.rcq <= 50) { + report->remote_metrics.quality_estimates.moscq = report->remote_metrics.quality_estimates.rcq / 10.f; + } else { + report->remote_metrics.quality_estimates.moscq = -1; + } + return report; } @@ -179,7 +203,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off 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); char * jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate); - char * gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density); + // char * gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density); char * moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq); char * moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq); @@ -209,12 +233,12 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_STR_TO_BUFFER(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); APPEND_STR_TO_BUFFER(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); - append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:"); - append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); - append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); - APPEND_STR_TO_BUFFER(buffer, size, offset, " GLD=%s", gap_loss_density_str); - append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_Duration); - append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); + // append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:"); + // append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); + // append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); + // APPEND_STR_TO_BUFFER(buffer, size, offset, " GLD=%s", gap_loss_density_str); + // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_Duration); + // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); append_to_buffer(buffer, size, offset, "\r\nDelay:"); append_to_buffer(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay); @@ -249,7 +273,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off free(timpstamps_stop_str); free(network_packet_loss_rate_str); free(jitter_buffer_discard_rate_str); - free(gap_loss_density_str); + // free(gap_loss_density_str); free(moslq_str); free(moscq_str); } @@ -280,21 +304,19 @@ void linphone_reporting_publish(LinphoneCall* call, int stats_type) { append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id); - if (report->info.local_group != NULL) append_to_buffer(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); - if (report->info.remote_group != NULL) append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); + APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); + APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); - if (report->info.local_mac_addr != NULL) append_to_buffer(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); + APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); - if (report->info.remote_mac_addr != NULL) append_to_buffer(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); + APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); - if (report->dialog_id != NULL) { - append_to_buffer(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); - } + APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); content.data = buffer; @@ -340,7 +362,7 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { // rtcp_XR_stat_summary_get_lost_packets(block); // rtcp_XR_stat_summary_get_dup_packets(block); // rtcp_XR_stat_summary_get_min_jitter(block); - metrics->jitter_buffer.max = rtcp_XR_stat_summary_get_max_jitter(block); + // rtcp_XR_stat_summary_get_max_jitter(block); // rtcp_XR_stat_summary_get_mean_jitter(block); // rtcp_XR_stat_summary_get_dev_jitter(block); // rtcp_XR_stat_summary_get_min_ttl_or_hl(block); @@ -349,7 +371,7 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { // rtcp_XR_stat_summary_get_dev_ttl_or_hl(block); break; case RTCP_XR_VOIP_METRICS: - addr->ssrc = rtcp_XR_voip_metrics_get_ssrc(block); + // rtcp_XR_voip_metrics_get_ssrc(block); // rtcp_XR_voip_metrics_get_loss_rate(block); // rtcp_XR_voip_metrics_get_discard_rate(block); // rtcp_XR_voip_metrics_get_burst_density(block); diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 7e5831212..5b17dfec8 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -70,13 +70,13 @@ typedef struct reporting_content_metrics { // 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; + // 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 { From a9e94795f4e12f4cce88155023fd4ffe9caf135a Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 10 Apr 2014 17:13:50 +0200 Subject: [PATCH 10/25] Quality reporting: fix submit report time moment --- coreapi/linphonecall.c | 2 ++ coreapi/linphonecore.c | 4 ++-- coreapi/quality_reporting.c | 33 +++++++++++++++++++-------------- coreapi/quality_reporting.h | 6 +++--- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d1e2d15b7..60baf03ff 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -804,6 +804,8 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); if (cstate==LinphoneCallReleased){ + linphone_reporting_publish(call); + if (call->op!=NULL) { /*transfer the last error so that it can be obtained even in Released state*/ if (call->non_op_error.reason==SalReasonNone){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9468189f8..13ab2027d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3470,9 +3470,9 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ /*stop ringing*/ linphone_core_stop_ringing(lc); - linphone_reporting_publish(call, LINPHONE_CALL_STATS_AUDIO); + linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO); if (call->videostream!=NULL){ - linphone_reporting_publish(call, LINPHONE_CALL_STATS_VIDEO); + linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO); } linphone_call_stop_media_streams(call); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index ff8ada7e9..1dd413041 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,10 +31,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * TODO / REMINDER LIST ****************************************************************************/ // place pour appeler la fonction submit - // only if call succeeded - // executed AFTER BYE's "OK" response has been received - // si c l'autre qui raccroche on envoi pas les données là + // only if call succeeded and ran + // TO_CHECK: executed AFTER BYE's "OK" response has been received + // memory leaks + char* strdup + // si l'autre en face a pas activé le partage de rtcp xr, on a pas de paquets du tout ? faut rien faire dans ce cas ? // si aucune data d'une catégorie est renseigné, ne pas mettre la section dans le paquet // stats // valeur pour "expires" ? @@ -99,7 +100,8 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } -static reporting_session_report_t * update_report(LinphoneCall * call, int stats_type) { +reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type) { + printf("linphone_reporting_call_stats_updated\n"); int count; reporting_session_report_t * report = call->reports[stats_type]; MediaStream stream; @@ -237,7 +239,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off // append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); // append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); // APPEND_STR_TO_BUFFER(buffer, size, offset, " GLD=%s", gap_loss_density_str); - // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_Duration); + // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration); // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); append_to_buffer(buffer, size, offset, "\r\nDelay:"); @@ -278,21 +280,14 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off free(moscq_str); } -void linphone_reporting_publish(LinphoneCall* call, int stats_type) { +static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; - reporting_session_report_t *report = update_report(call, stats_type); size_t offset = 0; size_t size = 2048; char * buffer; - // Somehow the reporting was not created, hence no need to go further - if (report == NULL) { - PRINT("STATS ARE NULL!"); - return; - } - buffer = (char *) ms_malloc(size); content.type = ms_strdup("application"); @@ -330,7 +325,6 @@ void linphone_reporting_publish(LinphoneCall* call, int stats_type) { linphone_address_destroy(addr); } - void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; @@ -397,3 +391,14 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { } } } + +void linphone_reporting_publish(LinphoneCall* call) { + printf("linphone_reporting_publish\n"); + if (call->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { + reporting_publish(call, call->reports[LINPHONE_CALL_STATS_AUDIO]); + } + + if (call->reports[LINPHONE_CALL_STATS_VIDEO] != NULL) { + reporting_publish(call, call->reports[LINPHONE_CALL_STATS_VIDEO]); + } +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 5b17dfec8..1c4a3ca4d 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -74,7 +74,7 @@ typedef struct reporting_content_metrics { // int burst_loss_density; // int burst_duration; // float gap_loss_density; - // int gap_Duration; + // int gap_duration; // int min_gap_threshold; // } burst_gap_loss; @@ -136,8 +136,8 @@ typedef struct reporting_session_report { char * dialog_id; // optional } reporting_session_report_t; - -void linphone_reporting_publish(LinphoneCall* call, int stats_type); +reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type); +void linphone_reporting_publish(LinphoneCall* call); void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); #ifdef __cplusplus } From a1c1f3013e62bb550860b8125203a5e5f383c5a5 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 11 Apr 2014 11:30:02 +0200 Subject: [PATCH 11/25] Quality reporting: verify values before adding them to the report --- coreapi/linphonecall.c | 7 +- coreapi/linphonecore.c | 5 - coreapi/private.h | 4 +- coreapi/quality_reporting.c | 318 +++++++++++++++++++++--------------- coreapi/quality_reporting.h | 1 + 5 files changed, 193 insertions(+), 142 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 60baf03ff..feb96ee1c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -483,6 +483,9 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->owns_call_log=TRUE; call->camera_enabled=TRUE; + call->log->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); + call->log->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); + linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); @@ -1851,7 +1854,6 @@ 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->reports[LINPHONE_CALL_STATS_AUDIO]=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); @@ -1981,7 +1983,6 @@ 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->reports[LINPHONE_CALL_STATS_VIDEO]=ms_new0(reporting_session_report_t,1); if (used_pt!=-1){ VideoStreamDir dir=VideoStreamSendRecv; @@ -2206,6 +2207,7 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ void linphone_call_stop_audio_stream(LinphoneCall *call) { if (call->audiostream!=NULL) { + linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]); rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); @@ -2234,6 +2236,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { void linphone_call_stop_video_stream(LinphoneCall *call) { #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ + linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO); media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]); rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 13ab2027d..1d23a929a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3470,11 +3470,6 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ /*stop ringing*/ linphone_core_stop_ringing(lc); - linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO); - if (call->videostream!=NULL){ - linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO); - } - linphone_call_stop_media_streams(call); #ifdef BUILD_UPNP diff --git a/coreapi/private.h b/coreapi/private.h index 4d32a23e6..d92371a5a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -116,6 +116,8 @@ struct _LinphoneCallLog{ float quality; 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]; bool_t video_enabled; }; @@ -193,8 +195,6 @@ struct _LinphoneCall struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; - reporting_session_report_t * reports[2]; - MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; LinphoneCallParams params; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 1dd413041..920455ac7 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // TO_CHECK: executed AFTER BYE's "OK" response has been received // memory leaks + char* strdup + // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). // si l'autre en face a pas activé le partage de rtcp xr, on a pas de paquets du tout ? faut rien faire dans ce cas ? // si aucune data d'une catégorie est renseigné, ne pas mettre la section dans le paquet // stats @@ -100,10 +101,153 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } + +#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) +#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement + +static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, reporting_content_metrics_t rm) { + char * timestamps_start_str = NULL; + char * timestamps_stop_str = NULL; + char * network_packet_loss_rate_str = NULL; + char * jitter_buffer_discard_rate_str = NULL; + // char * gap_loss_density_str = NULL; + char * moslq_str = NULL; + char * moscq_str = NULL; + + if (rm.timestamps.start > 0) + timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start); + if (rm.timestamps.stop > 0) + timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop); + + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256)); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256)); + // IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density)); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); + + append_to_buffer(buffer, size, offset, "Timestamps:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str); + + append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); + APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); + APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1); + APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1); + // append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets); + // append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec); + // append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); + APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state); + + append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); + + append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); + + // append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:"); + // append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); + // append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str); + // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration); + // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); + + append_to_buffer(buffer, size, offset, "\r\nDelay:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); + // APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); + + append_to_buffer(buffer, size, offset, "\r\nSignal:"); + APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127); + APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127); + // append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss); + + append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg); + // append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg); + // append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); + // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg); + // 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); +} + +static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { + LinphoneContent content = {0}; + LinphoneAddress *addr; + int expires = 3600; + size_t offset = 0; + size_t size = 2048; + char * buffer; + + 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", report->info.call_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); + append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id); + + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); + + append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); + append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); + + append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); + append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); + + content.data = buffer; + + // for debug purpose only + PRINT(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); +} + reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type) { printf("linphone_reporting_call_stats_updated\n"); int count; - reporting_session_report_t * report = call->reports[stats_type]; + reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream stream; const MSQualityIndicator * qi = NULL; const PayloadType * payload; @@ -198,135 +342,8 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int return report; } -#define APPEND_STR_TO_BUFFER(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg); - -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); - char * jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate); - // char * gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density); - char * moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq); - char * moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq); - - append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s", - timpstamps_start_str, timpstamps_stop_str); - - append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); - append_to_buffer(buffer, size, offset, " PT=%d", rm.session_description.payload_type); - APPEND_STR_TO_BUFFER(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); - append_to_buffer(buffer, size, offset, " SR=%d", rm.session_description.sample_rate); - append_to_buffer(buffer, size, offset, " FD=%d", rm.session_description.frame_duration); - // append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets); - // append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec); - // append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec); - APPEND_STR_TO_BUFFER(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); - append_to_buffer(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state); - - append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); - append_to_buffer(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive); - append_to_buffer(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate); - append_to_buffer(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal); - append_to_buffer(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max); - append_to_buffer(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max); - - append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); - APPEND_STR_TO_BUFFER(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); - APPEND_STR_TO_BUFFER(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); - - // append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:"); - // append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density); - // append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " GLD=%s", gap_loss_density_str); - // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration); - // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); - - append_to_buffer(buffer, size, offset, "\r\nDelay:"); - append_to_buffer(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay); - append_to_buffer(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay); - // append_to_buffer(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay); - append_to_buffer(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay); - append_to_buffer(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter); - append_to_buffer(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter); - - append_to_buffer(buffer, size, offset, "\r\nSignal:"); - append_to_buffer(buffer, size, offset, " SL=%d", rm.signal.level); - append_to_buffer(buffer, size, offset, " NL=%d", rm.signal.noise_level); - // append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss); - - append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); - append_to_buffer(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg); - append_to_buffer(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg); - // append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg); - // append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg); - APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSLQ=%s", moslq_str); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg); - APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSCQ=%s", moscq_str); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg); - // APPEND_STR_TO_BUFFER(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg); - append_to_buffer(buffer, size, offset, "\r\n"); - - free(timpstamps_start_str); - free(timpstamps_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); -} - -static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { - LinphoneContent content = {0}; - LinphoneAddress *addr; - int expires = 3600; - size_t offset = 0; - size_t size = 2048; - char * buffer; - - 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", report->info.call_id); - append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id); - append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); - append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id); - - APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); - APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); - append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); - APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); - append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); - APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); - - append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); - append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); - - append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); - append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); - APPEND_STR_TO_BUFFER(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); - - content.data = buffer; - - // for debug purpose only - PRINT(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); -} - void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { - reporting_session_report_t * report = call->reports[stats_type]; + reporting_session_report_t * report = call->log->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; reporting_addr_t * addr = NULL; @@ -394,11 +411,46 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { void linphone_reporting_publish(LinphoneCall* call) { printf("linphone_reporting_publish\n"); - if (call->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { - reporting_publish(call, call->reports[LINPHONE_CALL_STATS_AUDIO]); + if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { + reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); } - if (call->reports[LINPHONE_CALL_STATS_VIDEO] != NULL) { - reporting_publish(call, call->reports[LINPHONE_CALL_STATS_VIDEO]); + if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL + && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]); } } + +reporting_session_report_t * linphone_reporting_new() { + int i; + reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1); + + reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics}; + for (i = 0; i < 2; i++) { + metrics[i]->session_description.payload_type = -1; + metrics[i]->session_description.sample_rate = -1; + metrics[i]->session_description.frame_duration = -1; + + metrics[i]->packet_loss.network_packet_loss_rate = -1; + metrics[i]->packet_loss.jitter_buffer_discard_rate = -1; + + metrics[i]->session_description.packet_loss_concealment = -1; + + metrics[i]->jitter_buffer.adaptive = -1; + metrics[i]->jitter_buffer.rate = -1; + metrics[i]->jitter_buffer.nominal = -1; + metrics[i]->jitter_buffer.max = -1; + metrics[i]->jitter_buffer.abs_max = -1; + + metrics[i]->delay.round_trip_delay = -1; + metrics[i]->delay.end_system_delay = -1; + // metrics[i]->delay.one_way_delay = -1; + metrics[i]->delay.symm_one_way_delay = -1; + metrics[i]->delay.interarrival_jitter = -1; + metrics[i]->delay.mean_abs_jitter = -1; + + metrics[i]->signal.level = 127; + metrics[i]->signal.noise_level = 127; + } + return rm; +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 1c4a3ca4d..a59b1b8db 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -136,6 +136,7 @@ typedef struct reporting_session_report { char * dialog_id; // optional } reporting_session_report_t; +reporting_session_report_t * linphone_reporting_new(); reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type); void linphone_reporting_publish(LinphoneCall* call); void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); From 05b75f760962f6815011b53cb089003f589a1762 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 11 Apr 2014 15:35:21 +0200 Subject: [PATCH 12/25] Quality reporting: store struct in LinphoneLog instead of LinphoneCall, and added new/destroy methods --- coreapi/linphonecall.c | 3 - coreapi/linphonecore.c | 6 ++ coreapi/quality_reporting.c | 202 ++++++++++++++++++------------------ coreapi/quality_reporting.h | 3 +- 4 files changed, 111 insertions(+), 103 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index feb96ee1c..b64cacca2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -483,9 +483,6 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, call->owns_call_log=TRUE; call->camera_enabled=TRUE; - call->log->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); - call->log->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); - linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1d23a929a..af627ad4c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -128,6 +128,9 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro cl->to=to; cl->status=LinphoneCallAborted; /*default status*/ cl->quality=-1; + + cl->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); + cl->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); return cl; } @@ -391,6 +394,9 @@ void linphone_call_log_destroy(LinphoneCallLog *cl){ if (cl->to!=NULL) linphone_address_destroy(cl->to); if (cl->refkey!=NULL) ms_free(cl->refkey); if (cl->call_id) ms_free(cl->call_id); + if (cl->reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_AUDIO]); + if (cl->reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_VIDEO]); + ms_free(cl); } diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 920455ac7..25ac63438 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -25,6 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "sal/sal.h" + +#include "ortp/rtpsession.h" + #include /*************************************************************************** @@ -34,28 +37,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // only if call succeeded and ran // TO_CHECK: executed AFTER BYE's "OK" response has been received - // memory leaks + char* strdup // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). - // si l'autre en face a pas activé le partage de rtcp xr, on a pas de paquets du tout ? faut rien faire dans ce cas ? - // si aucune data d'une catégorie est renseigné, ne pas mettre la section dans le paquet - // stats - // valeur pour "expires" ? - // packet_loss_concealment - // jitter buffer rate / adaptive - // jitter_buffer_discard_rate; - // network_packet_loss_rate - // vérifier les valeurs par défaut etc. - // ip local potientellement vide - // remote : ip, port, timestamps, session desc - // dialog id ? + + // cgdb: pourquoi pas de breakpoint dans mon fichier? + // remote: session desc pourquoi c'est null + // Jehan: dialog id ? --> local / remote tag pas accessible + // à voir : + // Simon: ip remote vide + // valeur pour "expires" ? // video : que se passe t-il si on arrete / resume la vidéo (new stream) // valeurs instanannées : moyenne ? valeur extreme ? // à qui / comment on envoit ? (collector@sip.linphone.com ?) // only if this is a linphone account? - -#define PRINT2(x, f) printf(#x ": " #f "\n", x) -#define PRINT(x) PRINT2(x, "%s") + // ip local potientellement vide + // rlq: il faut un algo // since printf family functions are LOCALE dependent, float separator may differ // depending on the user's locale (LC_NUMERIC env var). @@ -145,7 +141,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15); + // APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); @@ -235,7 +231,7 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r content.data = buffer; // for debug purpose only - PRINT(content.data); + printf("%s\n", content.data); content.size = strlen((char*)content.data); @@ -250,9 +246,14 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream stream; const MSQualityIndicator * qi = NULL; - const PayloadType * payload; + const PayloadType * local_payload; + const PayloadType * remote_payload; RtpSession * session = NULL; + SalMediaDescription * remote_smd = NULL; + SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; + // const char* from_tag; + // const char* to_tag; if (report == NULL) { ms_warning("No reporting created for this stream"); @@ -261,83 +262,90 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int if (stats_type == LINPHONE_CALL_STATS_AUDIO) { stream = call->audiostream->ms; - payload = call->current_params.audio_codec; + local_payload = call->current_params.audio_codec; + remote_payload = linphone_call_get_remote_params(call)->audio_codec; } else { stream = call->videostream->ms; - payload = call->current_params.video_codec; + local_payload = call->current_params.video_codec; + remote_payload = linphone_call_get_remote_params(call)->video_codec; } session = stream.sessions.rtp_session; qi = media_stream_get_quality_indicator(&stream); report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); - report->info.local_addr.port = rtp_session_get_local_port(session); report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); - // memcpy(report->info.remote_addr.ip, &session->rtp.rem_addr, session->rtp.rem_addrlen); - report->info.call_id = call->log->call_id; - report->info.local_group = ms_strdup_printf(_("linphone-%s"), report->info.call_id); - report->info.remote_group = ms_strdup(report->info.local_group); - for (count = 0; count < call->resultdesc->n_total_streams; ++count) { - if (call->resultdesc->streams[count].type == stats_type) { - report->info.local_addr.ip = ms_strdup(call->resultdesc->streams[count].rtp_addr); + 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); + for (count = 0; count < call->localdesc->n_total_streams; ++count) { + if (call->localdesc->streams[count].type == sal_stream_type) { + report->info.local_addr.ip = ms_strdup(call->localdesc->streams[count].rtp_addr); + report->info.local_addr.port = call->localdesc->streams[count].rtp_port; break; } } if (count == call->resultdesc->n_total_streams) { - ms_warning("Could not find the associated stream of type %d", stats_type); + ms_warning("Could not find the associated stream of type %d for local desc", sal_stream_type); + } + + remote_smd = sal_call_get_remote_media_description(call->op); + if (remote_smd != NULL) { + for (count = 0; count < remote_smd->n_total_streams; ++count) { + if (remote_smd->streams[count].type == sal_stream_type) { + report->info.remote_addr.ip = ms_strdup(remote_smd->streams[count].rtp_addr); + report->info.remote_addr.port = remote_smd->streams[count].rtp_port; + break; + } + } + } + if (remote_smd == NULL || count == remote_smd->n_total_streams) { + ms_warning("Could not find the associated stream of type %d for remote desc", sal_stream_type); } - if (payload != NULL) { - report->local_metrics.session_description.payload_type = payload->type; - report->local_metrics.session_description.payload_desc = ms_strdup(payload->mime_type); - report->local_metrics.session_description.sample_rate = payload->clock_rate; - report->local_metrics.session_description.fmtp = ms_strdup(payload->recv_fmtp); - } else { - // ... + 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); + report->local_metrics.session_description.sample_rate = local_payload->clock_rate; + report->local_metrics.session_description.fmtp = ms_strdup(local_payload->recv_fmtp); } - report->local_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); - if (10 <= report->local_metrics.quality_estimates.rlq - && report->local_metrics.quality_estimates.rlq <= 50) { - report->local_metrics.quality_estimates.moslq = report->local_metrics.quality_estimates.rlq / 10.f; - } else { - report->local_metrics.quality_estimates.moslq = -1; + 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); + report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; + report->remote_metrics.session_description.fmtp = ms_strdup(remote_payload->recv_fmtp); } - report->local_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); - if (10 <= report->local_metrics.quality_estimates.rcq - && report->local_metrics.quality_estimates.rcq <= 50) { - report->local_metrics.quality_estimates.moscq = report->local_metrics.quality_estimates.rcq / 10.f; - } else { - report->local_metrics.quality_estimates.moscq = -1; - } - + 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 = report->info.remote_id; + report->info.orig_id = ms_strdup(report->info.remote_id); + // from_tag=belle_sip_dialog_get_local_tag(call->op->dialog); + // to_tag=belle_sip_dialog_get_remote_tag(call->op->dialog); } 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 = report->info.local_id; + report->info.orig_id = ms_strdup(report->info.local_id); + // to_tag=belle_sip_dialog_get_local_tag(call->op->dialog); + // from_tag=belle_sip_dialog_get_remote_tag(call->op->dialog); } + report->dialog_id = ms_strdup_printf("%s;to-tag=%s;from-tag=%s", report->info.call_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); - report->remote_metrics.quality_estimates.rlq = ms_quality_indicator_get_lq_rating(qi); - if (10 <= report->remote_metrics.quality_estimates.rlq - && report->remote_metrics.quality_estimates.rlq <= 50) { - report->remote_metrics.quality_estimates.moslq = report->remote_metrics.quality_estimates.rlq / 10.f; - } else { - report->remote_metrics.quality_estimates.moslq = -1; - } - report->remote_metrics.quality_estimates.rcq = ms_quality_indicator_get_rating(qi); - if (10 <= report->remote_metrics.quality_estimates.rcq - && report->remote_metrics.quality_estimates.rcq <= 50) { - report->remote_metrics.quality_estimates.moscq = report->remote_metrics.quality_estimates.rcq / 10.f; - } else { - report->remote_metrics.quality_estimates.moscq = -1; - } + + // report->local_metrics.quality_estimates.rlq = + report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(qi); + + // report->local_metrics.quality_estimates.rcq = ;// + report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(qi); return report; } @@ -365,43 +373,19 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { } if (block != NULL) { switch (rtcp_XR_get_block_type(block)) { - case RTCP_XR_STAT_SUMMARY: - // rtcp_XR_stat_summary_get_flags(block); - // rtcp_XR_stat_summary_get_ssrc(block); - // rtcp_XR_stat_summary_get_begin_seq(block); - // rtcp_XR_stat_summary_get_end_seq(block); - // rtcp_XR_stat_summary_get_lost_packets(block); - // rtcp_XR_stat_summary_get_dup_packets(block); - // rtcp_XR_stat_summary_get_min_jitter(block); - // rtcp_XR_stat_summary_get_max_jitter(block); - // rtcp_XR_stat_summary_get_mean_jitter(block); - // rtcp_XR_stat_summary_get_dev_jitter(block); - // rtcp_XR_stat_summary_get_min_ttl_or_hl(block); - // rtcp_XR_stat_summary_get_max_ttl_or_hl(block); - // rtcp_XR_stat_summary_get_mean_ttl_or_hl(block); - // rtcp_XR_stat_summary_get_dev_ttl_or_hl(block); - break; case RTCP_XR_VOIP_METRICS: - // rtcp_XR_voip_metrics_get_ssrc(block); - // rtcp_XR_voip_metrics_get_loss_rate(block); - // rtcp_XR_voip_metrics_get_discard_rate(block); - // rtcp_XR_voip_metrics_get_burst_density(block); - // rtcp_XR_voip_metrics_get_gap_density(block); - // rtcp_XR_voip_metrics_get_burst_duration(block); - // rtcp_XR_voip_metrics_get_gap_duration(block); - // rtcp_XR_voip_metrics_get_round_trip_delay(block); - // rtcp_XR_voip_metrics_get_end_system_delay(block); - // rtcp_XR_voip_metrics_get_signal_level(block); - // rtcp_XR_voip_metrics_get_noise_level(block); - // rtcp_XR_voip_metrics_get_rerl(block); - // rtcp_XR_voip_metrics_get_gmin(block); - metrics->quality_estimates.rlq = rtcp_XR_voip_metrics_get_r_factor(block); + metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block); metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block); metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block); - // rtcp_XR_voip_metrics_get_rx_config(block); 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->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); + + uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); + metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; + metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; break; default: break; @@ -437,7 +421,7 @@ reporting_session_report_t * linphone_reporting_new() { metrics[i]->session_description.packet_loss_concealment = -1; metrics[i]->jitter_buffer.adaptive = -1; - metrics[i]->jitter_buffer.rate = -1; + // metrics[i]->jitter_buffer.rate = -1; metrics[i]->jitter_buffer.nominal = -1; metrics[i]->jitter_buffer.max = -1; metrics[i]->jitter_buffer.abs_max = -1; @@ -454,3 +438,23 @@ reporting_session_report_t * linphone_reporting_new() { } return rm; } + +void linphone_reporting_destroy(reporting_session_report_t * report) { + if (report->info.call_id != NULL) ms_free(report->info.call_id); + if (report->info.local_id != NULL) ms_free(report->info.local_id); + if (report->info.remote_id != NULL) ms_free(report->info.remote_id); + if (report->info.orig_id != NULL) ms_free(report->info.orig_id); + if (report->info.local_addr.ip != NULL) ms_free(report->info.local_addr.ip); + if (report->info.remote_addr.ip != NULL) ms_free(report->info.remote_addr.ip); + if (report->info.local_group != NULL) ms_free(report->info.local_group); + if (report->info.remote_group != NULL) ms_free(report->info.remote_group); + if (report->info.local_mac_addr != NULL) ms_free(report->info.local_mac_addr); + if (report->info.remote_mac_addr != NULL) ms_free(report->info.remote_mac_addr); + if (report->dialog_id != NULL) ms_free(report->dialog_id); + if (report->local_metrics.session_description.fmtp != NULL) ms_free(report->local_metrics.session_description.fmtp); + if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); + if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); + if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); + + ms_free(report); +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index a59b1b8db..b4512d05d 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -56,7 +56,7 @@ typedef struct reporting_content_metrics { // jitter buffet - optional struct { int adaptive; // constant - int rate; // 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 @@ -137,6 +137,7 @@ typedef struct reporting_session_report { } reporting_session_report_t; reporting_session_report_t * linphone_reporting_new(); +void linphone_reporting_destroy(reporting_session_report_t * report); reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type); void linphone_reporting_publish(LinphoneCall* call); void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); From 1cba3da32ddf82c67e86dc1e77451d1018ed3b7e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 14 Apr 2014 10:42:42 +0200 Subject: [PATCH 13/25] Quality reporting: fill 'from-tag' and 'to-tag' fields --- coreapi/quality_reporting.c | 19 +++++++------------ coreapi/sal.c | 4 ++++ include/sal/sal.h | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 25ac63438..d32bd451f 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -39,7 +39,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). - // cgdb: pourquoi pas de breakpoint dans mon fichier? // remote: session desc pourquoi c'est null // Jehan: dialog id ? --> local / remote tag pas accessible @@ -252,23 +251,23 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int SalMediaDescription * remote_smd = NULL; SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; - // const char* from_tag; - // const char* to_tag; - if (report == NULL) { ms_warning("No reporting created for this stream"); return NULL; } - if (stats_type == LINPHONE_CALL_STATS_AUDIO) { + if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = call->audiostream->ms; local_payload = call->current_params.audio_codec; remote_payload = linphone_call_get_remote_params(call)->audio_codec; - } else { + } else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) { stream = call->videostream->ms; local_payload = call->current_params.video_codec; remote_payload = linphone_call_get_remote_params(call)->video_codec; + } else { + return NULL; } + session = stream.sessions.rtp_session; qi = media_stream_get_quality_indicator(&stream); @@ -285,7 +284,7 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int break; } } - if (count == call->resultdesc->n_total_streams) { + if (count == call->localdesc->n_total_streams) { ms_warning("Could not find the associated stream of type %d for local desc", sal_stream_type); } @@ -321,16 +320,12 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int 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); - // from_tag=belle_sip_dialog_get_local_tag(call->op->dialog); - // to_tag=belle_sip_dialog_get_remote_tag(call->op->dialog); } 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); - // to_tag=belle_sip_dialog_get_local_tag(call->op->dialog); - // from_tag=belle_sip_dialog_get_remote_tag(call->op->dialog); } - report->dialog_id = ms_strdup_printf("%s;to-tag=%s;from-tag=%s", report->info.call_id, "", ""); + 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); diff --git a/coreapi/sal.c b/coreapi/sal.c index 6f2256ac9..d64240ef3 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -372,6 +372,10 @@ const char *sal_op_get_network_origin(const SalOp *op){ const char* sal_op_get_call_id(const SalOp *op) { return ((SalOpBase*)op)->call_id; } +char* sal_op_get_dialog_id(const SalOp *op) { + 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)); +} void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); ((SalOpBase*)b)->root=sal; diff --git a/include/sal/sal.h b/include/sal/sal.h index 1dba31f90..7ec00f596 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -572,6 +572,7 @@ const SalAddress *sal_op_get_network_origin_address(const SalOp *op); const char *sal_op_get_remote_ua(const SalOp *op); void *sal_op_get_user_pointer(const SalOp *op); const char* sal_op_get_call_id(const SalOp *op); +char* sal_op_get_dialog_id(const SalOp *op); const SalAddress* sal_op_get_service_route(const SalOp *op); void sal_op_set_service_route(SalOp *op,const SalAddress* service_route); From 40d688f569406c67bac5f5c27cef530e2ca765ad Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 14 Apr 2014 11:40:55 +0200 Subject: [PATCH 14/25] Quality reporting: add security in get_dialog_id method since dialog might be null --- coreapi/quality_reporting.c | 32 ++++++++++++++++---------------- coreapi/sal.c | 8 ++++++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index d32bd451f..e9a3cc6f1 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -33,23 +33,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST ****************************************************************************/ - // place pour appeler la fonction submit - // only if call succeeded and ran - // TO_CHECK: executed AFTER BYE's "OK" response has been received + // only if call succeeded and ran (busy should NOT call this) + // TO_CHECK: executed AFTER BYE's "OK" response has been received // 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 pourquoi c'est null - // Jehan: dialog id ? --> local / remote tag pas accessible - + // remote: session desc null parce que linphone_call_get_remote_params le remplit pas + // à voir : // Simon: ip remote vide + // ip local potientellement vide // valeur pour "expires" ? + // à voir ++ : // video : que se passe t-il si on arrete / resume la vidéo (new stream) // valeurs instanannées : moyenne ? valeur extreme ? // à qui / comment on envoit ? (collector@sip.linphone.com ?) // only if this is a linphone account? - // ip local potientellement vide // rlq: il faut un algo // since printf family functions are LOCALE dependent, float separator may differ @@ -244,7 +243,7 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int int count; reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream stream; - const MSQualityIndicator * qi = NULL; + // const MSQualityIndicator * qi = NULL; const PayloadType * local_payload; const PayloadType * remote_payload; RtpSession * session = NULL; @@ -258,18 +257,17 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = call->audiostream->ms; - local_payload = call->current_params.audio_codec; - remote_payload = linphone_call_get_remote_params(call)->audio_codec; + local_payload = linphone_call_params_get_used_audio_codec(&call->current_params); + remote_payload = linphone_call_params_get_used_audio_codec(linphone_call_get_remote_params(call)); } else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) { stream = call->videostream->ms; - local_payload = call->current_params.video_codec; - remote_payload = linphone_call_get_remote_params(call)->video_codec; + local_payload = linphone_call_params_get_used_video_codec(&call->current_params); + remote_payload = linphone_call_params_get_used_video_codec(linphone_call_get_remote_params(call)); } else { return NULL; } session = stream.sessions.rtp_session; - qi = media_stream_get_quality_indicator(&stream); report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); @@ -325,6 +323,7 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int report->info.local_id = linphone_address_as_string(call->log->from); report->info.orig_id = ms_strdup(report->info.local_id); } + report->dialog_id = sal_op_get_dialog_id(call->op); report->local_metrics.timestamps.start = call->log->start_date_time; @@ -336,11 +335,11 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int + // qi = media_stream_get_quality_indicator(&stream); // report->local_metrics.quality_estimates.rlq = - report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(qi); - + // report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(qi); // report->local_metrics.quality_estimates.rcq = ;// - report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(qi); + // report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(qi); return report; } @@ -390,6 +389,7 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { void linphone_reporting_publish(LinphoneCall* call) { printf("linphone_reporting_publish\n"); + 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 d64240ef3..a3ec66b45 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -373,8 +373,12 @@ const char* sal_op_get_call_id(const SalOp *op) { return ((SalOpBase*)op)->call_id; } char* sal_op_get_dialog_id(const SalOp *op) { - 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)); + if (op->dialog != NULL) { + 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; + } void __sal_op_init(SalOp *b, Sal *sal){ memset(b,0,sizeof(SalOpBase)); From a8ba7b7993615f7adc8f05631e4066caf02616f1 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 14 Apr 2014 16:31:46 +0200 Subject: [PATCH 15/25] Quality reporting: fix IP/port fields --- coreapi/linphonecall.c | 15 ++- coreapi/quality_reporting.c | 193 ++++++++++++++++++++---------------- coreapi/quality_reporting.h | 3 +- 3 files changed, 121 insertions(+), 90 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b64cacca2..db3b000ab 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -773,7 +773,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const return; } } - ms_message("Call %p: moving from state %s to %s",call,linphone_call_state_to_string(call->state), linphone_call_state_to_string(cstate)); @@ -801,10 +800,16 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const call->media_start_time=time(NULL); } + if (cstate == LinphoneCallStreamsRunning) { + linphone_reporting_update_ip(call); + } + if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); if (cstate==LinphoneCallReleased){ - linphone_reporting_publish(call); + + if (call->log->status == LinphoneCallSuccess) + linphone_reporting_publish(call); if (call->op!=NULL) { /*transfer the last error so that it can be obtained even in Released state*/ @@ -2754,7 +2759,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); - linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); + if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) { @@ -2765,7 +2771,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse evd->packet = NULL; call->stats[LINPHONE_CALL_STATS_VIDEO].updated = LINPHONE_CALL_STATS_SENT_RTCP_UPDATE; update_local_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO],(MediaStream*)call->videostream); - linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); + if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) + linphone_reporting_call_stats_updated(call, LINPHONE_CALL_STATS_VIDEO); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]); } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index e9a3cc6f1..aee3d7b44 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -33,21 +33,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST ****************************************************************************/ - // only if call succeeded and ran (busy should NOT call this) + // TO_CHECK: only if call succeeded and ran (busy should NOT call this) // TO_CHECK: executed AFTER BYE's "OK" response has been received // 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 - // à voir : - // Simon: ip remote vide - // ip local potientellement vide - // valeur pour "expires" ? + // payload distant supposons que c les meme que locaux pour l'instant + // verifier char* avant assignation + // abstraction audio video + // tests liblinphonetester + // valgrind --leakcheck=full + // configurable global publish_call_statistics linphone_proxy_config_set_statistics_collector enable_collector // à voir ++ : // video : que se passe t-il si on arrete / resume la vidéo (new stream) // valeurs instanannées : moyenne ? valeur extreme ? - // à qui / comment on envoit ? (collector@sip.linphone.com ?) // only if this is a linphone account? // rlq: il faut un algo @@ -196,7 +197,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { LinphoneContent content = {0}; LinphoneAddress *addr; - int expires = 3600; + int expires = -1; size_t offset = 0; size_t size = 2048; char * buffer; @@ -229,7 +230,7 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r content.data = buffer; // for debug purpose only - printf("%s\n", content.data); + printf("%s\n", (char*) content.data); content.size = strlen((char*)content.data); @@ -238,82 +239,83 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r linphone_address_destroy(addr); } -reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type) { - printf("linphone_reporting_call_stats_updated\n"); - int count; - reporting_session_report_t * report = call->log->reports[stats_type]; - MediaStream stream; - // const MSQualityIndicator * qi = NULL; - const PayloadType * local_payload; - const PayloadType * remote_payload; - RtpSession * session = NULL; - SalMediaDescription * remote_smd = NULL; - SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; - if (report == NULL) { - ms_warning("No reporting created for this stream"); - return NULL; - } - - if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { - stream = call->audiostream->ms; - local_payload = linphone_call_params_get_used_audio_codec(&call->current_params); - remote_payload = linphone_call_params_get_used_audio_codec(linphone_call_get_remote_params(call)); - } else if (stats_type == LINPHONE_CALL_STATS_VIDEO && call->videostream != NULL) { - stream = call->videostream->ms; - local_payload = linphone_call_params_get_used_video_codec(&call->current_params); - remote_payload = linphone_call_params_get_used_video_codec(linphone_call_get_remote_params(call)); - } else { - return NULL; - } - - 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); - 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); - for (count = 0; count < call->localdesc->n_total_streams; ++count) { - if (call->localdesc->streams[count].type == sal_stream_type) { - report->info.local_addr.ip = ms_strdup(call->localdesc->streams[count].rtp_addr); - report->info.local_addr.port = call->localdesc->streams[count].rtp_port; - break; - } - } - if (count == call->localdesc->n_total_streams) { - ms_warning("Could not find the associated stream of type %d for local desc", sal_stream_type); - } - - remote_smd = sal_call_get_remote_media_description(call->op); +static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * remote_smd, SalStreamType sal_stream_type) { if (remote_smd != NULL) { + int count; for (count = 0; count < remote_smd->n_total_streams; ++count) { if (remote_smd->streams[count].type == sal_stream_type) { - report->info.remote_addr.ip = ms_strdup(remote_smd->streams[count].rtp_addr); - report->info.remote_addr.port = remote_smd->streams[count].rtp_port; - break; + return &remote_smd->streams[count]; + } + } + if (remote_smd == NULL || count == remote_smd->n_total_streams) { + ms_warning("Could not find the associated stream of type %d for remote desc", sal_stream_type); + } + } + + return NULL; +} + +static void reporting_update_ip(LinphoneCall * call, int stats_type) { + SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; + if (call->log->reports[stats_type] != NULL) { + const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); + const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_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); + } + + if (remote_desc != NULL) { + // port is always stored in stream description struct + call->log->reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; + + // 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); + } else { + call->log->reports[stats_type]->info.remote_addr.ip = ms_strdup(sal_call_get_remote_media_description(call->op)->addr); } } } - if (remote_smd == NULL || count == remote_smd->n_total_streams) { - ms_warning("Could not find the associated stream of type %d for remote desc", sal_stream_type); +} + +void linphone_reporting_update_ip(LinphoneCall * call) { + printf("linphone_reporting_update_remote_ip\n"); + + // 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 + + reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO); + + if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + reporting_update_ip(call, LINPHONE_CALL_STATS_VIDEO); } - - 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); - report->local_metrics.session_description.sample_rate = local_payload->clock_rate; - report->local_metrics.session_description.fmtp = ms_strdup(local_payload->recv_fmtp); +} + +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 SalMediaDescription * remote_media_desc = sal_call_get_remote_media_description(call->op); + const PayloadType * local_payload = NULL; + const PayloadType * remote_payload = NULL; + const SalStreamDescription * remote_desc = NULL; + SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; + 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; } - 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); - report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; - report->remote_metrics.session_description.fmtp = ms_strdup(remote_payload->recv_fmtp); - } - + 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); + 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); @@ -332,42 +334,62 @@ reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int //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); + + 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); + } 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)); + } + 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); + } - // qi = media_stream_get_quality_indicator(&stream); - // report->local_metrics.quality_estimates.rlq = - // report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(qi); - // report->local_metrics.quality_estimates.rcq = ;// - // report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(qi); + 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); + report->local_metrics.session_description.sample_rate = local_payload->clock_rate; + report->local_metrics.session_description.fmtp = ms_strdup(local_payload->recv_fmtp); + } - return report; + 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); + report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; + report->remote_metrics.session_description.fmtp = ms_strdup(remote_payload->recv_fmtp); + } } void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; - reporting_addr_t * addr = NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { metrics = &report->remote_metrics; - addr = &report->info.remote_addr; if (rtcp_is_XR(stats.received_rtcp) == TRUE) { block = stats.received_rtcp; } } else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) { metrics = &report->local_metrics; - addr = &report->info.local_addr; if (rtcp_is_XR(stats.sent_rtcp) == TRUE) { block = stats.sent_rtcp; } } if (block != NULL) { switch (rtcp_XR_get_block_type(block)) { - case RTCP_XR_VOIP_METRICS: + case RTCP_XR_VOIP_METRICS: { metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block); metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block); metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block); @@ -381,8 +403,9 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; break; - default: + } default: { break; + } } } } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index b4512d05d..f3d311ad9 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -138,7 +138,8 @@ typedef struct reporting_session_report { reporting_session_report_t * linphone_reporting_new(); void linphone_reporting_destroy(reporting_session_report_t * report); -reporting_session_report_t * linphone_reporting_update(LinphoneCall * call, int stats_type); +void linphone_reporting_update(LinphoneCall * call, int stats_type); +void linphone_reporting_update_ip(LinphoneCall * call); void linphone_reporting_publish(LinphoneCall* call); void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); #ifdef __cplusplus From 6e385691285a63e706f0dd1f7a29190aaade044e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 14 Apr 2014 16:36:06 +0200 Subject: [PATCH 16/25] Quality reporting: remove unused variables --- coreapi/quality_reporting.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index aee3d7b44..84a14e9f5 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -300,11 +300,8 @@ 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 SalMediaDescription * remote_media_desc = sal_call_get_remote_media_description(call->op); const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; - const SalStreamDescription * remote_desc = NULL; - SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; const LinphoneCallParams * local_params = linphone_call_get_current_params(call); const LinphoneCallParams * remote_params = linphone_call_get_remote_params(call); if (report == NULL) { From 0762b56a36125e6976e5a7fefef2edb3a61a4748 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 15 Apr 2014 10:43:03 +0200 Subject: [PATCH 17/25] 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 From 424d75b2652b7fd57af21dd93e945437c88fbab2 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 15 Apr 2014 11:04:12 +0200 Subject: [PATCH 18/25] Quality reporting: release content after publishing it to avoid memory leaks --- coreapi/private.h | 1 + coreapi/quality_reporting.c | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 94605e506..efc622b31 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -812,6 +812,7 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d void linphone_call_create_op(LinphoneCall *call); int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer); void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); +void linphone_content_uninit(LinphoneContent * obj); LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref); SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc); SalReason linphone_reason_to_sal(LinphoneReason reason); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 58727acb7..075f9ebe1 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -40,11 +40,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // 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 - // range 0 - 255 au lieu de 0 - 5 metrics->quality_estimates.rcq, metrics->quality_estimates.moslq, metrics->quality_estimates.moscq); // abstraction audio video - // valgrind --leakcheck=full // tests liblinphonetester // à voir ++ : // video : que se passe t-il si on arrete / resume la vidéo (new stream) @@ -254,6 +251,8 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r } else { ms_warning("Asked to submit reporting statistics but no collector address found"); } + + linphone_content_uninit(&content); } From 929fbffe1a62c30766ee117f88a7d85cadfa7a9c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 15 Apr 2014 16:54:39 +0200 Subject: [PATCH 19/25] Quality reporting: add unit tests --- coreapi/quality_reporting.c | 32 ++++++------ tester/call_tester.c | 98 ++++++++++++++++++++++++++++++++++++- tester/rcfiles/marie_rc | 2 + 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 075f9ebe1..ed21890f9 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -46,8 +46,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // à 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 + // #define PRINTF printf + #define PRINTF(...) /*************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -108,7 +109,7 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con #define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) #define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement -static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, reporting_content_metrics_t rm) { +static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { char * timestamps_start_str = NULL; char * timestamps_stop_str = NULL; char * network_packet_loss_rate_str = NULL; @@ -200,10 +201,11 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moscq_str); } -static void reporting_publish(LinphoneCall* call, reporting_session_report_t * report) { +static void reporting_publish(const LinphoneCall* call, const reporting_session_report_t * report) { + PRINTF("static reporting_publish\n"); + LinphoneContent content = {0}; LinphoneAddress *addr; - const char * addr_str; int expires = -1; size_t offset = 0; size_t size = 2048; @@ -238,24 +240,21 @@ static void reporting_publish(LinphoneCall* call, reporting_session_report_t * r content.size = strlen((char*)content.data); - - - addr_str = call->dest_proxy->reg_statistics_collector; - if (addr_str != NULL) { - addr = linphone_address_new(addr_str); + addr = linphone_address_new(call->dest_proxy->reg_statistics_collector); + if (addr != NULL) { linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); linphone_address_destroy(addr); // for debug purpose only - printf("%s\n", (char*) content.data); + PRINTF("%s\n", (char*) content.data); } else { ms_warning("Asked to submit reporting statistics but no collector address found"); + PRINTF("Asked to submit reporting statistics but no collector address found\n"); } linphone_content_uninit(&content); } - static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * remote_smd, SalStreamType sal_stream_type) { if (remote_smd != NULL) { int count; @@ -298,7 +297,7 @@ static void reporting_update_ip(LinphoneCall * call, int stats_type) { } } -static bool_t reporting_enabled(LinphoneCall * call) { +static bool_t reporting_enabled(const LinphoneCall * call) { return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy)); } @@ -307,7 +306,7 @@ void linphone_reporting_update_ip(LinphoneCall * call) { // - 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"); + PRINTF("linphone_reporting_update_remote_ip\n"); if (! reporting_enabled(call)) return; @@ -326,7 +325,7 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - printf("linphone_reporting_call_stats_updated type=%d\n", stats_type); + PRINTF("linphone_reporting_call_stats_updated type=%d\n", stats_type); if (! reporting_enabled(call)) return; @@ -432,11 +431,12 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { } void linphone_reporting_publish(LinphoneCall* call) { - printf("linphone_reporting_publish\n"); + PRINTF("linphone_reporting_publish\n"); - if (! reporting_enabled(call)) + 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/tester/call_tester.c b/tester/call_tester.c index 3e8ef9475..999dc0d77 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1877,6 +1877,98 @@ static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb() call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE); } +void create_call_for_statistics_tests( + LinphoneCoreManager* marie, + LinphoneCoreManager* pauline, + LinphoneCall** call_marie, + LinphoneCall** call_pauline) { + CU_ASSERT_TRUE(call(pauline,marie)); + *call_marie = linphone_core_get_current_call(marie->lc); + *call_pauline = linphone_core_get_current_call(pauline->lc); + CU_ASSERT_PTR_NOT_NULL(*call_marie); + CU_ASSERT_PTR_NOT_NULL(*call_pauline); +} + +static void statistics_not_used_without_config() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline); + + // marie has stats collection enabled since pauline has not + CU_ASSERT_TRUE(linphone_proxy_config_send_statistics_enabled(call_marie->dest_proxy)); + CU_ASSERT_FALSE(linphone_proxy_config_send_statistics_enabled(call_pauline->dest_proxy)); + + CU_ASSERT_EQUAL(strcmp("sip:collector@sip.linphone.org", + linphone_proxy_config_get_statistics_collector(call_marie->dest_proxy)), 0); + + // this field should be already filled + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->info.local_addr.ip); + CU_ASSERT_PTR_NULL(call_pauline->log->reports[0]->info.local_addr.ip); + + // but not this one since it is updated at the end of call + CU_ASSERT_PTR_NULL(call_marie->log->reports[0]->dialog_id); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void statistics_not_sent_if_call_not_started() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallLog* out_call_log; + LinphoneCall* out_call; + + linphone_core_set_max_calls(pauline->lc,0); + out_call = linphone_core_invite(marie->lc,"pauline"); + linphone_call_ref(out_call); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallError,1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + + if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { + CU_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data)); + CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted); + } + linphone_call_unref(out_call); + + // wait a few time... + wait_for(marie->lc,NULL,NULL,0); + // since the callee was busy, there shouldn't be no publish to do + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void statistics_sent_at_call_termination() { + // int return_code = -1; + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline); + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1)); + + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); + + // now dialog id should be filled + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id); + + // PUBLISH submission to the collector should be ok + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); // failing since server side is not implemented + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + #ifdef VIDEO_ENABLED #endif @@ -1931,7 +2023,10 @@ test_t call_tests[] = { { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, - { "Call redirected by callee", call_redirect} + { "Call redirected by callee", call_redirect}, + { "Call statistics not used if no config", statistics_not_used_without_config}, + { "Call statistics not sent if call did not start", statistics_not_sent_if_call_not_started}, + { "Call statistics sent if call ended normally", statistics_sent_at_call_termination}, }; test_suite_t call_test_suite = { @@ -1941,4 +2036,3 @@ test_suite_t call_test_suite = { sizeof(call_tests) / sizeof(call_tests[0]), call_tests }; - diff --git a/tester/rcfiles/marie_rc b/tester/rcfiles/marie_rc index 7b7645800..342265158 100644 --- a/tester/rcfiles/marie_rc +++ b/tester/rcfiles/marie_rc @@ -22,6 +22,8 @@ reg_expires=3600 reg_sendregister=1 publish=0 dial_escape_plus=0 +reg_statistics_collector=sip:collector@sip.linphone.org +send_statistics=1 [friend_0] url="Paupoche" From e159b4fa17746a874620ff92786e6321118f7e2a Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 17 Apr 2014 10:57:55 +0200 Subject: [PATCH 20/25] Quality reporting: do not add remote metrics if no stats are filled --- coreapi/quality_reporting.c | 51 +++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index ed21890f9..fb838c566 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -47,8 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // video : que se passe t-il si on arrete / resume la vidéo (new stream) // valeurs instanannées : moyenne ? valeur extreme ? // rlq: il faut un algo - // #define PRINTF printf - #define PRINTF(...) + #define PRINTF(...) do { if (getenv("LINPHONE_QR_DEBUG") != NULL) printf(__VA_ARGS__); } while (FALSE) /*************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -104,10 +103,44 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con } -#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) -#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) -#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) -#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement +#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (FALSE &&arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (FALSE &&inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (FALSE&&cond) append_to_buffer(buffer, size, offset, fmt, arg) +#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (FALSE&&inf <= num && num <= sup) statement + +static bool_t are_metrics_filled(const reporting_content_metrics_t rm) { + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, return TRUE); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, return TRUE); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, return TRUE); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, return TRUE); + + // since these are values from local metrics, do not check them + // if (rm.session_description.payload_type != -1) return TRUE; + // if (rm.session_description.payload_desc != NULL) return TRUE; + // if (rm.session_description.sample_rate != -1) return TRUE; + if (rm.session_description.frame_duration != -1) return TRUE; + // if (rm.session_description.fmtp != NULL) return TRUE; + if (rm.session_description.packet_loss_concealment != -1) return TRUE; + + IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, return TRUE); + IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE); + + IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, return TRUE); + + if (rm.signal.level != 127) return TRUE; + if (rm.signal.noise_level != 127) return TRUE; + + IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, return TRUE); + IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, return TRUE); + + return FALSE; +} static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { char * timestamps_start_str = NULL; @@ -232,8 +265,10 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); - append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); - append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); + if (are_metrics_filled(report->remote_metrics)) { + append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); + append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); + } APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); content.data = buffer; From c94afb09587dc24f4347d0c1ff52ac2e76e192b0 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 17 Apr 2014 12:03:32 +0200 Subject: [PATCH 21/25] Quality reporting: add stream type in stats and remove debug test stuff --- coreapi/quality_reporting.c | 86 ++++++++++++++----------------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index fb838c566..998837963 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -24,35 +24,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore.h" #include "private.h" #include "sal/sal.h" - - #include "ortp/rtpsession.h" #include /*************************************************************************** * TODO / REMINDER LIST - ****************************************************************************/ - // 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). - - // 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 - // à voir ++ : - // video : que se passe t-il si on arrete / resume la vidéo (new stream) - // valeurs instanannées : moyenne ? valeur extreme ? - // rlq: il faut un algo - #define PRINTF(...) do { if (getenv("LINPHONE_QR_DEBUG") != NULL) printf(__VA_ARGS__); } while (FALSE) + ****************************************************************************/ + // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). + // range 0 - 255 instead of 0 - 5 for metrics->quality_estimates.rcq, metrics->quality_estimates.moslq, metrics->quality_estimates.moscq + // Know issue: if call is stopped to early, IP are invalid + // to discuss + // video: what happens if doing stop/resume? + // one time value: average? worst value? + // rlq value: need algo to compute it /*************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ -#define strass(dest, src) {\ +#define STR_REASSIGN(dest, src) {\ if (dest != NULL) \ ms_free(dest); \ dest = src; \ @@ -103,10 +93,10 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con } -#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (FALSE &&arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) -#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (FALSE &&inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) -#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (FALSE&&cond) append_to_buffer(buffer, size, offset, fmt, arg) -#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (FALSE&&inf <= num && num <= sup) statement +#define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) +#define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) +#define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement static bool_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, return TRUE); @@ -114,7 +104,7 @@ static bool_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, return TRUE); IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, return TRUE); - // since these are values from local metrics, do not check them + // since these are same values than local ones, do not check them // if (rm.session_description.payload_type != -1) return TRUE; // if (rm.session_description.payload_desc != NULL) return TRUE; // if (rm.session_description.sample_rate != -1) return TRUE; @@ -235,8 +225,6 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off } static void reporting_publish(const LinphoneCall* call, const reporting_session_report_t * report) { - PRINTF("static reporting_publish\n"); - LinphoneContent content = {0}; LinphoneAddress *addr; int expires = -1; @@ -279,12 +267,8 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ if (addr != NULL) { 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"); - PRINTF("Asked to submit reporting statistics but no collector address found\n"); } linphone_content_uninit(&content); @@ -315,7 +299,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; - strass(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); + STR_REASSIGN(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); } if (remote_desc != NULL) { @@ -324,9 +308,9 @@ 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) { - strass(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); + STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); } else { - strass(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); + STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); } } } @@ -341,8 +325,6 @@ void linphone_reporting_update_ip(LinphoneCall * call) { // - 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; @@ -360,26 +342,26 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - 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)); + STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); + STR_REASSIGN(report->info.local_group, ms_strdup_printf(_("linphone-%s-%s-%s"), (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), + linphone_core_get_user_agent_name(), report->info.call_id)); + STR_REASSIGN(report->info.remote_group, ms_strdup_printf(_("linphone-%s-%s-%s"), (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), + linphone_call_get_remote_user_agent(call), report->info.call_id)); if (call->dir == LinphoneCallIncoming) { - 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)); + STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_id)); } else { - 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)); + STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_id)); } - strass(report->dialog_id, sal_op_get_dialog_id(call->op)); + STR_REASSIGN(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); @@ -408,16 +390,16 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { if (local_payload != NULL) { report->local_metrics.session_description.payload_type = local_payload->type; - strass(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); + 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; - strass(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp)); + 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; - strass(report->remote_metrics.session_description.payload_desc, ms_strdup(remote_payload->mime_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; - strass(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp)); + STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp)); } } @@ -466,8 +448,6 @@ 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; From 2551648d0dab1c759fa858edfb25f4bda746bc79 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 17 Apr 2014 15:20:20 +0200 Subject: [PATCH 22/25] Quality reporting: update collector sip address to test server instead of the production one --- tester/rcfiles/marie_rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/rcfiles/marie_rc b/tester/rcfiles/marie_rc index 342265158..60fa3d118 100644 --- a/tester/rcfiles/marie_rc +++ b/tester/rcfiles/marie_rc @@ -22,7 +22,7 @@ reg_expires=3600 reg_sendregister=1 publish=0 dial_escape_plus=0 -reg_statistics_collector=sip:collector@sip.linphone.org +reg_statistics_collector=sip:collector@sip.example.org send_statistics=1 [friend_0] From e21cc4af9d4b6ea4056569e248f928dc30f8a5d7 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 17 Apr 2014 16:33:02 +0200 Subject: [PATCH 23/25] Quality reporting: do not publish report if we hung up too early (empty local IP address) --- coreapi/quality_reporting.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 998837963..441957736 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -232,8 +232,15 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ size_t size = 2048; char * buffer; - buffer = (char *) ms_malloc(size); + // if the call was hungup too early, we might have invalid IPs information + // in that case, we abort the report since it's not useful data + if (strlen(report->info.local_addr.ip) == 0 || strlen(report->info.remote_addr.ip) == 0) { + ms_warning("The call was hang up too early (duration: %d sec) and IP could " + "not be retrieved so dropping this report", linphone_call_get_duration(call)); + return; + } + buffer = (char *) ms_malloc(size); content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); From f3efcb12864bba9c35aac38257724380f449eb9b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 17 Apr 2014 16:58:50 +0200 Subject: [PATCH 24/25] Quality reporting: fix unit tests, and remove some trailing spaces --- coreapi/linphonecall.c | 26 +++--- coreapi/linphonecore.c | 166 ++++++++++++++++++------------------ coreapi/presence.c | 4 +- coreapi/private.h | 2 +- coreapi/proxy.c | 64 +++++++------- coreapi/quality_reporting.c | 28 +++--- coreapi/quality_reporting.h | 12 +-- coreapi/sal.c | 16 ++-- include/sal/sal.h | 4 +- tester/call_tester.c | 108 +++++++++++------------ 10 files changed, 215 insertions(+), 215 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index db3b000ab..f26ebdac9 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -399,7 +399,7 @@ static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){ int tried_port; int existing_port; bool_t already_used=FALSE; - + for(offset=0;offset<100;offset+=2){ tried_port=base_port+offset; already_used=FALSE; @@ -485,10 +485,10 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, linphone_core_get_audio_port_range(call->core, &min_port, &max_port); port_config_set(call,0,min_port,max_port); - + linphone_core_get_video_port_range(call->core, &min_port, &max_port); port_config_set(call,1,min_port,max_port); - + linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); } @@ -781,7 +781,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const Indeed it does not change the state of the call (still paused or running)*/ call->state=cstate; } - + if (cstate==LinphoneCallEnd || cstate==LinphoneCallError){ switch(call->non_op_error.reason){ case SalReasonDeclined: @@ -1304,7 +1304,7 @@ const char *linphone_call_params_get_session_name(const LinphoneCallParams *cp){ /** * Set the session name of the media session (ie in SDP). Subject from the SIP message (which is different) can be set using linphone_call_params_set_custom_header(). * @param cp the call parameters. - * @param name the session name + * @param name the session name **/ void linphone_call_params_set_session_name(LinphoneCallParams *cp, const char *name){ if (cp->session_name){ @@ -1454,17 +1454,17 @@ static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ SalMediaDescription *remote; bool_t has_video=FALSE; - + if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ if (incoming_offer){ remote=sal_call_get_remote_media_description(call->op); has_video=linphone_core_media_description_contains_video_stream(remote); }else has_video=call->params.has_video; - + _linphone_call_prepare_ice_for_stream(call,0,TRUE); if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE); /*start ICE gathering*/ - if (incoming_offer) + if (incoming_offer) linphone_core_update_ice_from_remote_media_description(call,remote); if (!ice_session_candidates_gathered(call->ice_session)){ if (call->audiostream->ms.state==MSStreamInitialized) @@ -1539,7 +1539,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); - + _linphone_call_prepare_ice_for_stream(call,0,FALSE); } @@ -1551,7 +1551,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0); int dscp=linphone_core_get_video_dscp(lc); const char *display_filter=linphone_core_get_video_display_filter(lc); - + if (call->sessions[1].rtp_session==NULL){ call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6); }else{ @@ -1961,7 +1961,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; - + /* look for savp stream first */ const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpSavp,SalVideo); @@ -1983,7 +1983,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; 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); if (used_pt!=-1){ @@ -2147,7 +2147,7 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript SalStreamDescription *old_stream; SalStreamDescription *new_stream; const SalStreamDescription *local_st_desc; - + local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index af627ad4c..b0d1dff8e 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -614,7 +614,7 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_set_play_file(lc,lp_config_get_string(lc->config,"sound","hold_music",PACKAGE_SOUND_DIR "/" HOLD_MUSIC)); lc->sound_conf.latency=0; -#ifndef __ios +#ifndef __ios tmp=TRUE; #else tmp=FALSE; /* on iOS we have builtin echo cancellation.*/ @@ -633,7 +633,7 @@ static void sound_config_read(LinphoneCore *lc) /*just parse requested stream feature once at start to print out eventual errors*/ linphone_core_get_audio_features(lc); - + _linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); } @@ -647,7 +647,7 @@ static void certificates_config_read(LinphoneCore *lc) #endif linphone_core_set_root_ca(lc,rootca); linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); - linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); + linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); } static void sip_config_read(LinphoneCore *lc) @@ -670,12 +670,12 @@ static void sip_config_read(LinphoneCore *lc) } linphone_core_enable_ipv6(lc,ipv6); memset(&tr,0,sizeof(tr)); - + tr.udp_port=lp_config_get_int(lc->config,"sip","sip_port",5060); tr.tcp_port=lp_config_get_int(lc->config,"sip","sip_tcp_port",5060); /*we are not listening inbound connection for tls, port has no meaning*/ tr.tls_port=lp_config_get_int(lc->config,"sip","sip_tls_port",LC_SIP_TRANSPORT_RANDOM); - + certificates_config_read(lc); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); @@ -710,7 +710,7 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0); linphone_core_set_in_call_timeout(lc,tmp); - + tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4); linphone_core_set_delayed_timeout(lc,tmp); @@ -982,8 +982,8 @@ static void video_config_read(LinphoneCore *lc){ int capture, display, self_view; int automatic_video=1; #endif - const char *str; -#ifdef VIDEO_ENABLED + const char *str; +#ifdef VIDEO_ENABLED LinphoneVideoPolicy vpol; memset(&vpol, 0, sizeof(LinphoneVideoPolicy)); #endif @@ -1046,7 +1046,7 @@ bool_t linphone_core_tunnel_available(void){ /** * Enable adaptive rate control. - * + * * @ingroup media_parameters * * Adaptive rate control consists in using RTCP feedback provided information to dynamically @@ -1060,7 +1060,7 @@ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled /** * Returns whether adaptive rate control is enabled. - * + * * @ingroup media_parameters * * See linphone_core_enable_adaptive_rate_control(). @@ -1080,7 +1080,7 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc){ * calls (within SDP messages) so that the remote end can have * sufficient knowledge to properly configure its audio & video * codec output bitrate to not overflow available bandwidth. - * + * * @ingroup media_parameters * * @param lc the LinphoneCore object @@ -1166,7 +1166,7 @@ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ * Set audio packetization time linphone will send (in absence of requirement from peer) * A value of 0 stands for the current codec default packetization time. * - * + * * @ingroup media_parameters **/ int linphone_core_get_upload_ptime(LinphoneCore *lc){ @@ -1187,14 +1187,14 @@ const char * linphone_core_get_version(void){ static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *const_pt, int number, const char *recv_fmtp){ PayloadType *pt; - + #ifdef ANDROID if (const_pt->channels==2){ ms_message("Stereo %s codec not supported on this platform.",const_pt->mime_type); return; } #endif - + pt=payload_type_clone(const_pt); if (number==-1){ /*look for a free number */ @@ -1258,10 +1258,10 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const static void misc_config_read(LinphoneCore *lc) { LpConfig *config=lc->config; const char *uuid; - + lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15); lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS); - + uuid=lp_config_get_string(config,"misc","uuid",NULL); if (!uuid){ char tmp[64]; @@ -1297,12 +1297,12 @@ static void linphone_core_start(LinphoneCore * lc) { void linphone_configuring_terminated(LinphoneCore *lc, LinphoneConfiguringState state, const char *message) { if (lc->vtable.configuring_status) lc->vtable.configuring_status(lc, state, message); - + if (state == LinphoneConfiguringSuccessful) { if (linphone_core_is_provisioning_transient(lc) == TRUE) linphone_core_set_provisioning_uri(lc, NULL); } - + linphone_core_start(lc); } @@ -1349,7 +1349,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab linphone_core_assign_payload_type(lc,&payload_type_mp4v,99,"profile-level-id=3"); linphone_core_assign_payload_type(lc,&payload_type_h264,102,"profile-level-id=42801F"); linphone_core_assign_payload_type(lc,&payload_type_vp8,103,NULL); - + linphone_core_assign_payload_type(lc,&payload_type_theora,97,NULL); linphone_core_assign_payload_type(lc,&payload_type_x_snow,-1,NULL); /* due to limited space in SDP, we have to disable this h264 line which is normally no more necessary */ @@ -1379,7 +1379,7 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab linphone_core_assign_payload_type(lc,&payload_type_opus,-1,"useinbandfec=1; usedtx=0; cbr=1"); linphone_core_assign_payload_type(lc,&payload_type_isac,-1,NULL); linphone_core_handle_static_payloads(lc); - + ms_init(); /* create a mediastreamer2 event queue and set it as global */ /* This allows to run event's callback in linphone_core_iterate() */ @@ -1393,13 +1393,13 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->network_last_check = 0; lc->network_last_status = FALSE; - + lc->http_provider = belle_sip_stack_create_http_provider(sal_get_belle_sip_stack(lc->sal), "0.0.0.0"); lc->http_verify_policy = belle_tls_verify_policy_new(); belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy); - + certificates_config_read(lc); - + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); if (remote_provisioning_uri == NULL) { linphone_configuring_terminated(lc, LinphoneConfiguringSkipped, NULL); @@ -1944,7 +1944,7 @@ static int apply_transports(LinphoneCore *lc){ /*first of all invalidate all current registrations so that we can register again with new transports*/ __linphone_core_invalidate_registers(lc); - + if (lc->sip_conf.ipv6_enabled) anyaddr="::0"; else @@ -2216,7 +2216,7 @@ void linphone_core_iterate(LinphoneCore *lc){ int elapsed; bool_t one_second_elapsed=FALSE; const char *remote_provisioning_uri = NULL; - + if (linphone_core_get_global_state(lc) == LinphoneGlobalStartup) { if (sal_get_root_ca(lc->sal)) { belle_tls_verify_policy_t *tls_policy = belle_tls_verify_policy_new(); @@ -2227,7 +2227,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (lc->vtable.display_status) lc->vtable.display_status(lc, _("Configuring")); linphone_core_set_state(lc, LinphoneGlobalConfiguring, "Configuring"); - + remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); if (remote_provisioning_uri) { int err = linphone_remote_provisioning_download_and_apply(lc, remote_provisioning_uri); @@ -2250,7 +2250,7 @@ void linphone_core_iterate(LinphoneCore *lc){ if (ecs==LinphoneEcCalibratorDone){ int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); int margin=len/2; - + lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0)); } else if (ecs == LinphoneEcCalibratorFailed) { lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/ @@ -2363,7 +2363,7 @@ void linphone_core_iterate(LinphoneCore *lc){ /** * Interpret a call destination as supplied by the user, and returns a fully qualified * LinphoneAddress. - * + * * @ingroup call_control * * A sip address should look like DisplayName . @@ -2382,7 +2382,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) LinphoneProxyConfig *proxy=lc->default_proxy; char *tmpurl; LinphoneAddress *uri; - + if (*url=='\0') return NULL; if (is_enum(url,&enum_domain)){ @@ -2432,7 +2432,7 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) if (uri!=NULL){ return uri; } - + return NULL; } @@ -2470,7 +2470,7 @@ const char * linphone_core_get_route(LinphoneCore *lc){ * Start a new call as a consequence of a transfer request received from a call. * This function is for advanced usage: the execution of transfers is automatically managed by the LinphoneCore. However if an application * wants to have control over the call parameters for the new call, it should call this function immediately during the LinphoneCallRefered notification. - * @see LinphoneCoreVTable::call_state_changed + * @see LinphoneCoreVTable::call_state_changed * @param lc the LinphoneCore * @param call a call that has just been notified about LinphoneCallRefered state event. * @param params the call parameters to be applied to the new call. @@ -2479,13 +2479,13 @@ const char * linphone_core_get_route(LinphoneCore *lc){ LinphoneCall * linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ LinphoneCallParams *cp=params ? linphone_call_params_copy(params) : linphone_core_create_default_call_parameters(lc); LinphoneCall *newcall; - + if (call->state!=LinphoneCallPaused){ ms_message("Automatically pausing current call to accept transfer."); _linphone_core_pause_call(lc,call); call->was_automatically_paused=TRUE; } - + if (!params){ cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/ } @@ -2525,7 +2525,7 @@ void linphone_core_notify_refer_state(LinphoneCore *lc, LinphoneCall *referer, L nodes with the basic SIP routing policy in order to get a workable system. */ - + static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneAddress *dest){ MSList *ret=NULL; const char *local_route=linphone_proxy_config_get_route(proxy); @@ -2820,7 +2820,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const bool_t defer = FALSE; linphone_core_preempt_sound_resources(lc); - + if(!linphone_core_can_we_add_call(lc)){ if (lc->vtable.display_warning) lc->vtable.display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); @@ -2852,7 +2852,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); call->log->start_date_time=time(NULL); linphone_call_init_media_streams(call); - + if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { /* Defer the start of the call after the ICE gathering process. */ if (linphone_call_prepare_ice(call,FALSE)==1) @@ -2884,7 +2884,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const defer = TRUE; } } - + if (defer==FALSE) linphone_core_start_invite(lc,call,NULL); if (real_url!=NULL) ms_free(real_url); @@ -2897,7 +2897,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. - * + * * It is possible to follow the progress of the transfer provided that transferee sends notification about it. * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. @@ -2929,7 +2929,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * @param lc linphone core object * @param call a running call you want to transfer * @param dest a running call whose remote person will receive the transfer - * + * * @ingroup call_control * * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. @@ -2937,7 +2937,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * This method will send a transfer request to the transfered person. The phone of the transfered is then * expected to automatically call to the destination of the transfer. The receiver of the transfer will then automatically * close the call with us (the 'dest' call). - * + * * It is possible to follow the progress of the transfer provided that transferee sends notification about it. * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. @@ -2962,7 +2962,7 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){ int i; if (md->n_active_streams==0) return FALSE; - + for(i=0;in_active_streams;i++){ const SalStreamDescription *sd=&md->streams[i]; if (sd->proto!=SalProtoRtpSavp){ @@ -3035,11 +3035,11 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallIncomingReceived){ /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ linphone_call_set_contact_op(call); - + if (propose_early_media || ringback_tone!=NULL){ linphone_core_accept_early_media(lc,call); }else sal_call_notify_ringing(call->op,FALSE); - + if (sal_call_get_replaces(call->op)!=NULL && lp_config_get_int(lc->config,"sip","auto_answer_replacing_calls",1)){ linphone_core_accept_call(lc,call); } @@ -3065,7 +3065,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* call, const LinphoneCallParams* params) { if (call->state==LinphoneCallIncomingReceived){ SalMediaDescription* md; - + /*try to be best-effort in giving real local or routable contact address for 100Rel case*/ linphone_call_set_contact_op(call); @@ -3076,7 +3076,7 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* sal_call_set_local_media_description ( call->op,call->localdesc ); sal_op_set_sent_custom_header ( call->op,params->custom_headers ); } - + sal_call_notify_ringing(call->op,TRUE); linphone_call_set_state(call,LinphoneCallIncomingEarlyMedia,"Incoming call early media"); @@ -3206,15 +3206,15 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho /** * @ingroup call_control * When receiving a #LinphoneCallUpdatedByRemote state notification, prevent LinphoneCore from performing an automatic answer. - * + * * When receiving a #LinphoneCallUpdatedByRemote state notification (ie an incoming reINVITE), the default behaviour of * LinphoneCore is to automatically answer the reINIVTE with call parameters unchanged. * However when for example when the remote party updated the call to propose a video stream, it can be useful - * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during + * to prompt the user before answering. This can be achieved by calling linphone_core_defer_call_update() during * the call state notifiacation, to deactivate the automatic answer that would just confirm the audio but reject the video. * Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer * the reINVITE, with eventually video enabled in the LinphoneCallParams argument. - * + * * @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal. **/ int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){ @@ -3420,7 +3420,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, sal_call_set_local_media_description(call->op,call->localdesc); sal_op_set_sent_custom_header(call->op,params->custom_headers); } - + /*give a chance a set card prefered sampling frequency*/ if (call->localdesc->streams[0].max_rate>0) { ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate); @@ -3429,7 +3429,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (lc->sound_conf.capt_sndcard) ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate); } - + if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } @@ -3547,9 +3547,9 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) /** * Decline a pending incoming call, with a reason. - * + * * @ingroup call_control - * + * * @param lc the linphone core * @param call the LinphoneCall, must be in the IncomingReceived state. * @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy @@ -3683,12 +3683,12 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ LinphoneCall *current_call; - + if (linphone_core_is_in_conference(lc)){ linphone_core_leave_conference(lc); return; } - + current_call=linphone_core_get_current_call(lc); if(current_call != NULL){ ms_message("Pausing automatically the current call."); @@ -3707,7 +3707,7 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ char temp[255]={0}; const char *subject="Call resuming"; - + if(call->state!=LinphoneCallPaused ){ ms_warning("we cannot resume a call that has not been established and paused before"); return -1; @@ -3722,7 +3722,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ } call->was_automatically_paused=FALSE; - + /* Stop playing music immediately. If remote side is a conference it prevents the participants to hear it while the 200OK comes back.*/ if (call->audiostream) audio_stream_play(call->audiostream, NULL); @@ -3758,7 +3758,7 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad * @param lc * @param remote_address * @return the LinphoneCall of the call if found - * + * * @ingroup call_control */ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ @@ -4361,7 +4361,7 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){ /** * Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server. - * + * * @ingroup initializing **/ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ @@ -4478,7 +4478,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ audio_stream_mute_rtp(st,val); } - + } } @@ -4564,7 +4564,7 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ if (server) lc->net_conf.stun_server=ms_strdup(server); else lc->net_conf.stun_server=NULL; - + /* each time the stun server is changed, we must clean the resolved cached addrinfo*/ if (lc->net_conf.stun_addrinfo){ freeaddrinfo(lc->net_conf.stun_addrinfo); @@ -4574,7 +4574,7 @@ void linphone_core_set_stun_server(LinphoneCore *lc, const char *server){ if (lc->net_conf.stun_server){ linphone_core_resolve_stun_server(lc); } - + if (linphone_core_ready(lc)) lp_config_set_string(lc->config,"net","stun_server",lc->net_conf.stun_server); } @@ -4631,7 +4631,7 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) char ipstring [INET6_ADDRSTRLEN]; if (lc->net_conf.nat_address==NULL) return NULL; - + if (parse_hostname_to_addr (lc->net_conf.nat_address, &ss, &ss_len, 5060)<0) { return lc->net_conf.nat_address; } @@ -5000,7 +5000,7 @@ int linphone_core_set_static_picture(LinphoneCore *lc, const char *path) { const char *linphone_core_get_static_picture(LinphoneCore *lc) { const char *path=NULL; #ifdef VIDEO_ENABLED - path=ms_static_image_get_default_image(); + path=ms_static_image_get_default_image(); #else ms_warning("Video support not compiled."); #endif @@ -5075,7 +5075,7 @@ static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned lon LinphoneCall *call; MSList *elem; #endif - + if (id!=0 && id!=-1) { ms_error("Invalid use of unset_video_window_id()"); return; @@ -5239,7 +5239,7 @@ static MSVideoSizeDef supported_resolutions[]={ #if !TARGET_OS_MAC || TARGET_OS_IPHONE /* OS_MAC is 1 for iPhone, but we need QVGA */ { { MS_VIDEO_SIZE_QVGA_W, MS_VIDEO_SIZE_QVGA_H } , "qvga" }, #endif - { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, + { { MS_VIDEO_SIZE_QCIF_W, MS_VIDEO_SIZE_QCIF_H } , "qcif" }, { { 0,0 } , NULL } }; @@ -5484,7 +5484,7 @@ void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ def.frequencies[0]=620; def.interval=250; def.repeat_count=3; - + break; default: ms_warning("Unhandled tone id."); @@ -5550,7 +5550,7 @@ int linphone_core_get_mtu(const LinphoneCore *lc){ * Sets the maximum transmission unit size in bytes. * This information is useful for sending RTP packets. * Default value is 1500. - * + * * @ingroup media_parameters **/ void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ @@ -5644,7 +5644,7 @@ void sip_config_uninit(LinphoneCore *lc) int i; sip_config_t *config=&lc->sip_conf; bool_t still_registered=TRUE; - + lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); @@ -5659,7 +5659,7 @@ void sip_config_uninit(LinphoneCore *lc) LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); linphone_proxy_config_edit(cfg); /* to unregister */ } - + ms_message("Unregistration started."); for (i=0;i<20&&still_registered;i++){ @@ -5691,7 +5691,7 @@ void sip_config_uninit(LinphoneCore *lc) ms_message("Tunnel destroyed."); } #endif - + sal_reset_transports(lc->sal); sal_unlisten_ports(lc->sal); /*to make sure no new messages are received*/ if (lc->http_provider) { @@ -5897,7 +5897,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_presence_model_unref(lc->presence_model); } linphone_core_free_payload_types(lc); - + linphone_core_message_storage_close(lc); ms_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); @@ -5906,7 +5906,7 @@ static void linphone_core_uninit(LinphoneCore *lc) static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){ // second get the list of available proxies const MSList *elem=linphone_core_get_proxy_config_list(lc); - + if (lc->network_reachable==isReachable) return; // no change, ignore. ms_message("Network state is now [%s]",isReachable?"UP":"DOWN"); @@ -5923,7 +5923,7 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu } lc->netup_time=curtime; lc->network_reachable=isReachable; - + if (!lc->network_reachable){ linphone_core_invalidate_friend_subscriptions(lc); sal_reset_transports(lc->sal); @@ -6397,7 +6397,7 @@ int linphone_core_set_media_encryption(LinphoneCore *lc, LinphoneMediaEncryption LinphoneMediaEncryption linphone_core_get_media_encryption(LinphoneCore *lc) { const char* menc = lp_config_get_string(lc->config, "sip", "media_encryption", NULL); - + if (menc == NULL) return LinphoneMediaEncryptionNone; else if (strcmp(menc, "srtp")==0) @@ -6433,10 +6433,10 @@ const char* linphone_core_get_device_identifier(const LinphoneCore *lc) { /** * Set the DSCP field for SIP signaling channel. - * + * * @ingroup network_parameters * * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ sal_set_dscp(lc->sal,dscp); @@ -6448,10 +6448,10 @@ void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp){ /** * Get the DSCP field for SIP signaling channel. - * + * * @ingroup network_parameters * * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_sip_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"sip","dscp",0x1a); @@ -6462,7 +6462,7 @@ int linphone_core_get_sip_dscp(const LinphoneCore *lc){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){ if (linphone_core_ready(lc)) @@ -6474,7 +6474,7 @@ void linphone_core_set_audio_dscp(LinphoneCore *lc, int dscp){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_audio_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","audio_dscp",0x2e); @@ -6485,12 +6485,12 @@ int linphone_core_get_audio_dscp(const LinphoneCore *lc){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ if (linphone_core_ready(lc)) lp_config_set_int_hex(lc->config,"rtp","video_dscp",dscp); - + } /** @@ -6498,7 +6498,7 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ * * @ingroup network_parameters * The DSCP defines the quality of service in IP packets. - * + * **/ int linphone_core_get_video_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","video_dscp",0); diff --git a/coreapi/presence.c b/coreapi/presence.c index 08996329f..fa4b97014 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -1467,7 +1467,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ char *tmp; LinphoneAddress *uri; LinphoneProxyConfig *cfg; - + uri=linphone_address_new(from); linphone_address_clean(uri); tmp=linphone_address_as_string(uri); @@ -1482,7 +1482,7 @@ void linphone_subscription_new(LinphoneCore *lc, SalOp *op, const char *from){ } } } - + /* check if we answer to this subscription */ if (linphone_find_friend_by_address(lc->friends,uri,&lf)!=NULL){ lf->insub=op; diff --git a/coreapi/private.h b/coreapi/private.h index efc622b31..9de726b9a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -677,7 +677,7 @@ struct _LinphoneCore bool_t use_preview_window; time_t network_last_check; - + bool_t network_last_status; bool_t ringstream_autorelease; bool_t pad[2]; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 89b61f513..a118ba50a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -17,7 +17,7 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #include "linphonecore.h" #include "sipsetup.h" #include "lpconfig.h" @@ -31,7 +31,7 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ MSList *elem; int i; if (!linphone_core_ready(lc)) return; - + for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=ms_list_next(elem),i++){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; linphone_proxy_config_write_to_config_file(lc->config,cfg,i); @@ -49,7 +49,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob 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; - + memset(obj, 0, sizeof(LinphoneProxyConfig)); obj->magic = linphone_proxy_config_magic; obj->expires = lc ? lp_config_get_default_int(lc->config, "proxy", "reg_expires", 3600) : 3600; @@ -88,7 +88,7 @@ LinphoneProxyConfig * linphone_core_create_proxy_config(LinphoneCore *lc) { /** * Destroys a proxy config. - * + * * @note: LinphoneProxyConfig that have been removed from LinphoneCore with * linphone_core_remove_proxy_config() must not be freed. **/ @@ -127,10 +127,10 @@ bool_t linphone_proxy_config_is_registered(const LinphoneProxyConfig *obj){ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char *server_addr){ LinphoneAddress *addr=NULL; char *modified=NULL; - + if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); obj->reg_proxy=NULL; - + if (server_addr!=NULL && strlen(server_addr)>0){ if (strstr(server_addr,"sip:")==NULL && strstr(server_addr,"sips:")==NULL){ modified=ms_strdup_printf("sip:%s",server_addr); @@ -153,7 +153,7 @@ int linphone_proxy_config_set_server_addr(LinphoneProxyConfig *obj, const char * /** * Sets the user identity as a SIP address. * - * This identity is normally formed with display name, username and domain, such + * This identity is normally formed with display name, username and domain, such * as: * Alice * The REGISTER messages will have from and to set to this identity. @@ -301,14 +301,14 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ LinphoneAddress *ret=NULL; LinphoneAddress *proxy=linphone_address_new(obj->reg_proxy); const char *host; - + if (proxy==NULL) return NULL; host=linphone_address_get_domain(proxy); if (host!=NULL){ int localport = -1; const char *localip = NULL; LinphoneAddress *contact=linphone_address_new(obj->reg_identity); - + linphone_address_clean(contact); if (obj->contact_params) { @@ -378,7 +378,7 @@ void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj){ /** - * Sets a dialing prefix to be automatically prepended when inviting a number with + * Sets a dialing prefix to be automatically prepended when inviting a number with * linphone_core_invite(); * This dialing prefix shall usually be the country code of the country where the user is living. * @@ -394,7 +394,7 @@ void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char /** * Returns dialing prefix. * - * + * **/ const char *linphone_proxy_config_get_dial_prefix(const LinphoneProxyConfig *cfg){ return cfg->dial_prefix; @@ -435,7 +435,7 @@ void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, co if (addr) linphone_address_destroy(addr); } else { - if (cfg->reg_statistics_collector != NULL) + if (cfg->reg_statistics_collector != NULL) ms_free(cfg->reg_statistics_collector); cfg->reg_statistics_collector = ms_strdup(collector); linphone_address_destroy(addr); @@ -458,7 +458,7 @@ typedef struct dial_plan{ char ccc[8]; /*country calling code*/ int nnl; /*maximum national number length*/ const char * icp; /*international call prefix, ex: 00 in europe*/ - + }dial_plan_t; /* TODO: fill with information for all countries over the world*/ @@ -743,7 +743,7 @@ static void lookup_dial_plan(const char *ccc, dial_plan_t *plan){ static bool_t is_a_phone_number(const char *username){ const char *p; for(p=username;*p!='\0';++p){ - if (isdigit(*p) || + if (isdigit(*p) || *p==' ' || *p=='.' || *p=='-' || @@ -771,12 +771,12 @@ static char *flatten_number(const char *number){ static void replace_plus(const char *src, char *dest, size_t destlen, const char *icp){ int i=0; - + if (icp && src[0]=='+' && (destlen>(i=strlen(icp))) ){ src++; strcpy(dest,icp); } - + for(;(idial_prefix==NULL || proxy->dial_prefix[0]=='\0'){ /*no prefix configured, nothing else to do*/ strncpy(result,flatten,result_len); @@ -859,7 +859,7 @@ void linphone_proxy_config_set_realm(LinphoneProxyConfig *cfg, const char *realm int linphone_proxy_config_send_publish(LinphoneProxyConfig *proxy, LinphonePresenceModel *presence){ int err=0; - + if (proxy->state==LinphoneRegistrationOk || proxy->state==LinphoneRegistrationCleared){ if (proxy->publish_op==NULL){ proxy->publish_op=sal_op_new(proxy->lc->sal); @@ -1050,7 +1050,7 @@ void linphone_core_set_default_proxy(LinphoneCore *lc, LinphoneProxyConfig *conf lc->default_proxy=config; if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL)); -} +} void linphone_core_set_default_proxy_index(LinphoneCore *lc, int index){ if (index<0) linphone_core_set_default_proxy(lc,NULL); @@ -1124,7 +1124,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config const char *proxy; LinphoneProxyConfig *cfg; char key[50]; - + sprintf(key,"proxy_%i",index); if (!lp_config_has_section(config,key)){ @@ -1133,12 +1133,12 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config cfg=linphone_proxy_config_new(); - identity=lp_config_get_string(config,key,"reg_identity",NULL); + identity=lp_config_get_string(config,key,"reg_identity",NULL); proxy=lp_config_get_string(config,key,"reg_proxy",NULL); - + linphone_proxy_config_set_identity(cfg,identity); linphone_proxy_config_set_server_addr(cfg,proxy); - + tmp=lp_config_get_string(config,key,"reg_route",NULL); if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); @@ -1147,19 +1147,19 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config 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)); - + linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600))); linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); - + linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0))); linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL))); - + tmp=lp_config_get_string(config,key,"type",NULL); - if (tmp!=NULL && strlen(tmp)>0) + if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault))); @@ -1198,7 +1198,7 @@ static void linphone_proxy_config_activate_sip_setup(LinphoneProxyConfig *cfg){ ms_error("Could not retrieve proxy uri !"); } } - + } SipSetup *linphone_proxy_config_get_sip_setup(LinphoneProxyConfig *cfg){ @@ -1213,7 +1213,7 @@ static bool_t can_register(LinphoneProxyConfig *cfg){ LinphoneCore *lc=cfg->lc; #ifdef BUILD_UPNP if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp){ - if(lc->sip_conf.register_only_when_upnp_is_ok && + if(lc->sip_conf.register_only_when_upnp_is_ok && (lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) { return FALSE; } @@ -1369,7 +1369,7 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) { void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){ LinphoneCore *lc=cfg->lc; bool_t update_friends=FALSE; - + if (cfg->state!=state || state==LinphoneRegistrationOk) { /*allow multiple notification of LinphoneRegistrationOk for refreshing*/ ms_message("Proxy config [%p] for identity [%s] moving from state [%s] to [%s]" , cfg, linphone_proxy_config_get_identity(cfg), @@ -1380,7 +1380,7 @@ void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrat || (state!=LinphoneRegistrationOk && cfg->state==LinphoneRegistrationOk); } cfg->state=state; - + if (update_friends){ linphone_core_update_friends_subscriptions(lc,cfg,TRUE); } diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 441957736..a415824e4 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST - ****************************************************************************/ + ****************************************************************************/ // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). // range 0 - 255 instead of 0 - 5 for metrics->quality_estimates.rcq, metrics->quality_estimates.moslq, metrics->quality_estimates.moscq // Know issue: if call is stopped to early, IP are invalid @@ -115,7 +115,7 @@ static bool_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, return TRUE); IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, return TRUE); IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE); IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, return TRUE); IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, return TRUE); @@ -141,9 +141,9 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off char * moslq_str = NULL; char * moscq_str = NULL; - if (rm.timestamps.start > 0) + if (rm.timestamps.start > 0) timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start); - if (rm.timestamps.stop > 0) + if (rm.timestamps.stop > 0) timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop); IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256)); @@ -173,7 +173,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off // APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); @@ -184,7 +184,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off // append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration); // APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str); // append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration); - // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); + // append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold); append_to_buffer(buffer, size, offset, "\r\nDelay:"); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535); @@ -256,10 +256,10 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); - + append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); - + if (are_metrics_filled(report->remote_metrics)) { append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); @@ -302,7 +302,7 @@ static void reporting_update_ip(LinphoneCall * call, int stats_type) { if (call->log->reports[stats_type] != NULL) { const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_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; @@ -332,7 +332,7 @@ void linphone_reporting_update_ip(LinphoneCall * call) { // - 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 - if (! reporting_enabled(call)) + if (! reporting_enabled(call)) return; reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO); @@ -349,7 +349,7 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - if (! reporting_enabled(call)) + if (! reporting_enabled(call)) return; STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); @@ -376,7 +376,7 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { //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 case if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = &call->audiostream->ms; @@ -417,7 +417,7 @@ 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)) + if (! reporting_enabled(call)) return; if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { @@ -463,7 +463,7 @@ void linphone_reporting_publish(LinphoneCall* call) { reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); } - if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL + if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index f3d311ad9..c817feba9 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -57,7 +57,7 @@ typedef struct reporting_content_metrics { struct { int adaptive; // constant // int rate; // constant - int nominal; // no may vary during the call <- average? worst score? + 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; @@ -68,10 +68,10 @@ typedef struct reporting_content_metrics { float jitter_buffer_discard_rate; //idem } packet_loss; - // burst gap loss - optional + // burst gap loss - optional // (no) currently not implemented // struct { - // int burst_loss_density; + // int burst_loss_density; // int burst_duration; // float gap_loss_density; // int gap_duration; @@ -90,7 +90,7 @@ typedef struct reporting_content_metrics { // signal - optional struct { - int level; // no - vary + int level; // no - vary int noise_level; // no - vary // int residual_echo_return_loss; } signal; @@ -101,7 +101,7 @@ typedef struct reporting_content_metrics { 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; // int extro; @@ -114,7 +114,7 @@ typedef struct reporting_content_metrics { // char * qoestalg; } quality_estimates; } reporting_content_metrics_t; - + typedef struct reporting_session_report { struct { char * call_id; diff --git a/coreapi/sal.c b/coreapi/sal.c index e42c124cc..5404210f3 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -17,9 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/** +/** This header files defines the Signaling Abstraction Layer. - The purpose of this layer is too allow experiment different call signaling + The purpose of this layer is too allow experiment different call signaling protocols and implementations under linphone, for example SIP, JINGLE... **/ #ifdef HAVE_CONFIG_H @@ -39,7 +39,7 @@ const char* sal_transport_to_string(SalTransport transport) { default: { ms_fatal("Unexpected transport [%i]",transport); return NULL; - } + } } } @@ -409,17 +409,17 @@ void __sal_op_free(SalOp *op){ sal_address_destroy(b->to_address); b->to_address=NULL; } - + if (b->service_route){ sal_address_destroy(b->service_route); b->service_route=NULL; } - + if (b->origin_address){ sal_address_destroy(b->origin_address); b->origin_address=NULL; } - + if (b->from) { ms_free(b->from); b->from=NULL; @@ -624,7 +624,7 @@ static int line_get_value(const char *input, const char *key, char *value, size_ int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){ int read=0; - + do{ if (line_get_value(data,key,value,value_size,&read)) return TRUE; @@ -634,7 +634,7 @@ int sal_lines_get_value(const char *data, const char *key, char *value, size_t v } int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){ - return body->type && body->subtype + return body->type && body->subtype && strcmp(body->type,type)==0 && strcmp(body->subtype,subtype)==0; } diff --git a/include/sal/sal.h b/include/sal/sal.h index 7ec00f596..b6356350a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -17,9 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/** +/** This header files defines the Signaling Abstraction Layer. - The purpose of this layer is too allow experiment different call signaling + The purpose of this layer is too allow experiment different call signaling protocols and implementations under linphone, for example SIP, JINGLE... **/ diff --git a/tester/call_tester.c b/tester/call_tester.c index 999dc0d77..51fb39859 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -103,10 +103,10 @@ void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreMana c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); - + CU_ASSERT_PTR_NOT_NULL(c1); CU_ASSERT_PTR_NOT_NULL(c2); - + if (!c1 || !c2) return; for (i=0; i<24 /*=12s need at least one exchange of SR to maybe 10s*/; i++) { @@ -316,7 +316,7 @@ static void cancelled_call(void) { static void disable_all_codecs_except_one(LinphoneCore *lc, const char *mime){ const MSList *elem=linphone_core_get_audio_codecs(lc); PayloadType *pt; - + for(;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; linphone_core_enable_payload_type(lc,pt,FALSE); @@ -351,7 +351,7 @@ static void call_with_dns_time_out(void) { LinphoneCoreManager* marie = linphone_core_manager_new2( "empty_rc", FALSE); LCSipTransports transport = {9773,0,0,0}; int i; - + linphone_core_set_sip_transports(marie->lc,&transport); linphone_core_iterate(marie->lc); sal_set_dns_timeout(marie->lc->sal,0); @@ -359,7 +359,7 @@ static void call_with_dns_time_out(void) { for(i=0;i<10;i++){ ms_usleep(200000); linphone_core_iterate(marie->lc); - } + } CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingInit,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallOutgoingProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); @@ -372,21 +372,21 @@ static void early_cancelled_call(void) { LinphoneCoreManager* pauline = linphone_core_manager_new2( "empty_rc",FALSE); LinphoneCall* out_call = linphone_core_invite_address(pauline->lc,marie->identity); - + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallOutgoingInit,1)); linphone_core_terminate_call(pauline->lc,out_call); - + /*since everything is executed in a row, no response can be received from the server, thus the CANCEL cannot be sent. It will ring at Marie's side.*/ - + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); - + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallEnd,1); - + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallIncomingReceived,1)); /* now the CANCEL should have been sent and the the call at marie's side should terminate*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallReleased,1)); linphone_core_manager_destroy(marie); @@ -426,7 +426,7 @@ static void early_declined_call(void) { CU_ASSERT_TRUE(wait_for_until(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallError,1,33000)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallError,1); /* FIXME http://git.linphone.org/mantis/view.php?id=757 - + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call),LinphoneReasonBusy); */ if (ms_list_size(linphone_core_get_call_logs(pauline->lc))>0) { @@ -466,7 +466,7 @@ static void call_declined(void) { static void call_terminated_by_caller(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - + CU_ASSERT_TRUE(call(pauline,marie)); /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); @@ -480,7 +480,7 @@ static void call_terminated_by_caller(void) { static void call_with_no_sdp(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - + linphone_core_enable_sdp_200_ack(marie->lc,TRUE); CU_ASSERT_TRUE(call(marie,pauline)); @@ -500,7 +500,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); - + CU_ASSERT_PTR_NOT_NULL(c1); CU_ASSERT_PTR_NOT_NULL(c2); @@ -522,12 +522,12 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee static void _call_with_ice(bool_t random_ports) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); - + if (random_ports){ linphone_core_set_audio_port(marie->lc,-1); linphone_core_set_video_port(marie->lc,-1); @@ -541,9 +541,9 @@ static void _call_with_ice(bool_t random_ports) { /*wait for the ICE reINVITE to complete*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); - + liblinphone_tester_check_rtcp(marie,pauline); /*then close the call*/ linphone_core_terminate_all_calls(pauline->lc); @@ -581,17 +581,17 @@ static void call_with_custom_headers(void) { ms_free(tmp); linphone_address_destroy(marie->identity); marie->identity=marie_identity; - + params=linphone_core_create_default_call_parameters(marie->lc); linphone_call_params_add_custom_header(params,"Weather","bad"); linphone_call_params_add_custom_header(params,"Working","yes"); - + CU_ASSERT_TRUE(call_with_caller_params(pauline,marie,params)); linphone_call_params_destroy(params); - + call_marie=linphone_core_get_current_call(marie->lc); call_pauline=linphone_core_get_current_call(pauline->lc); - + CU_ASSERT_PTR_NOT_NULL(call_marie); CU_ASSERT_PTR_NOT_NULL(call_pauline); @@ -752,12 +752,12 @@ static void call_with_video_added(void) { static void call_with_video_added_random_ports(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - + linphone_core_set_audio_port(marie->lc,-1); linphone_core_set_video_port(marie->lc,-1); linphone_core_set_audio_port(pauline->lc,-1); linphone_core_set_video_port(pauline->lc,-1); - + CU_ASSERT_TRUE(call(pauline,marie)); CU_ASSERT_TRUE(add_video(pauline,marie)); @@ -848,17 +848,17 @@ static void _call_with_media_relay(bool_t random_ports) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); - + if (random_ports){ linphone_core_set_audio_port(marie->lc,-1); linphone_core_set_video_port(marie->lc,-1); linphone_core_set_audio_port(pauline->lc,-1); linphone_core_set_video_port(pauline->lc,-1); } - + CU_ASSERT_TRUE(call(pauline,marie)); liblinphone_tester_check_rtcp(pauline,marie); - + #ifdef VIDEO_ENABLED CU_ASSERT_TRUE(add_video(pauline,marie)); liblinphone_tester_check_rtcp(pauline,marie); @@ -944,7 +944,7 @@ static void call_with_privacy2(void) { LinphoneProxyConfig* pauline_proxy; params=linphone_core_create_default_call_parameters(pauline->lc); linphone_call_params_set_privacy(params,LinphonePrivacyId); - + linphone_core_get_default_proxy(pauline->lc,&pauline_proxy); linphone_proxy_config_edit(pauline_proxy); linphone_proxy_config_enable_register(pauline_proxy,FALSE); @@ -1151,7 +1151,7 @@ static void encrypted_call(LinphoneMediaEncryption mode) { CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),mode); CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),mode); - if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP + if (linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP && linphone_core_get_media_encryption(pauline->lc) == LinphoneMediaEncryptionZRTP) { /*check SAS*/ CU_ASSERT_STRING_EQUAL(linphone_call_get_authentication_token(linphone_core_get_current_call(pauline->lc)) @@ -1233,7 +1233,7 @@ static void srtp_ice_call(void) { /*wait for ice to found the direct path*/ CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_IframeDecoded,1)); #endif - + /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); @@ -1258,19 +1258,19 @@ static void early_media_call(void) { CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingEarlyMedia,1); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1); - + wait_for_until(pauline->lc,marie->lc,NULL,0,1000); - + /*added because a bug related to early-media caused the Connected state to be reached two times*/ CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected,1); - + /*just to sleep*/ linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); - - + + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -1287,7 +1287,7 @@ static void early_media_call_with_ringing(void){ /* Marie calls Pauline, and after the call has rung, transitions to an early_media session */ - + /*use playfile for callee to avoid locking on capture card*/ linphone_core_use_files (pauline->lc,TRUE); snprintf(hellopath,sizeof(hellopath), "%s/sounds/hello8000.wav", liblinphone_tester_file_prefix); @@ -1323,7 +1323,7 @@ static void early_media_call_with_ringing(void){ ms_list_free(lcs); - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -1446,9 +1446,9 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallPaused,1,2000)); /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); - + CU_ASSERT_PTR_NOT_NULL(linphone_call_get_transfer_target_call(marie_calling_pauline)); - + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallIncomingReceived,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,2000)); @@ -1458,11 +1458,11 @@ static void simple_call_transfer(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallStreamsRunning,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallConnected,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - + marie_calling_laure=linphone_core_get_current_call(marie->lc); CU_ASSERT_PTR_NOT_NULL_FATAL(marie_calling_laure); CU_ASSERT_TRUE(linphone_call_get_transferer_call(marie_calling_laure)==marie_calling_pauline); - + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallConnected,1,2000)); /*terminate marie to pauline call*/ @@ -1496,11 +1496,11 @@ static void unattended_call_transfer(void) { linphone_core_transfer_call(marie->lc,pauline_called_by_marie,laure_identity); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); - + /*marie ends the call */ linphone_core_terminate_call(marie->lc,pauline_called_by_marie); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); - + /*Pauline starts the transfer*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); @@ -1537,21 +1537,21 @@ static void unattended_call_transfer_with_error(void) { linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user"); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000)); - + /*Pauline starts the transfer*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000)); /* and immediately get an error*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000)); - + /*the error must be reported back to marie*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000)); /*and pauline should resume the call automatically*/ CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallResuming,1,2000)); - + /*and call should be resumed*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallStreamsRunning,1,2000)); - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); ms_list_free(lcs); @@ -1705,7 +1705,7 @@ static void call_established_with_rejected_incoming_reinvite(void) { LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); - + /*wait for ACK to be transmitted before going to reINVITE*/ wait_for_until(marie->lc,pauline->lc,NULL,0,1000); @@ -1750,7 +1750,7 @@ static void call_redirect(void){ /* Marie calls Pauline, which will redirect the call to Laure via a 302 */ - + /*use playfile for callee to avoid locking on capture card*/ linphone_core_use_files (pauline->lc,TRUE); linphone_core_use_files (laure->lc,TRUE); @@ -1788,7 +1788,7 @@ static void call_redirect(void){ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,1000)); ms_list_free(lcs); - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); @@ -1901,7 +1901,7 @@ static void statistics_not_used_without_config() { CU_ASSERT_TRUE(linphone_proxy_config_send_statistics_enabled(call_marie->dest_proxy)); CU_ASSERT_FALSE(linphone_proxy_config_send_statistics_enabled(call_pauline->dest_proxy)); - CU_ASSERT_EQUAL(strcmp("sip:collector@sip.linphone.org", + CU_ASSERT_EQUAL(strcmp("sip:collector@sip.example.org", linphone_proxy_config_get_statistics_collector(call_marie->dest_proxy)), 0); // this field should be already filled @@ -1935,7 +1935,7 @@ static void statistics_not_sent_if_call_not_started() { // wait a few time... wait_for(marie->lc,NULL,NULL,0); - // since the callee was busy, there shouldn't be no publish to do + // since the callee was busy, there shouldn't be no publish to do CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); @@ -1964,7 +1964,7 @@ static void statistics_sent_at_call_termination() { // PUBLISH submission to the collector should be ok CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); // failing since server side is not implemented - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } From 0470d0523a20b66a668eddcae1cdac5e574fcbeb Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 18 Apr 2014 09:13:48 +0200 Subject: [PATCH 25/25] Quality reporting: update comments and fix mos_cq mos_lq values --- coreapi/quality_reporting.c | 30 +++++++++++++++--------------- tester/call_tester.c | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index a415824e4..fb64a4b28 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,10 +31,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST ****************************************************************************/ - // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). - // range 0 - 255 instead of 0 - 5 for metrics->quality_estimates.rcq, metrics->quality_estimates.moslq, metrics->quality_estimates.moscq - // Know issue: if call is stopped to early, IP are invalid // to discuss + // For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). + // moslq == moscq // video: what happens if doing stop/resume? // one time value: average? worst value? // rlq value: need algo to compute it @@ -281,17 +280,17 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ linphone_content_uninit(&content); } -static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * remote_smd, SalStreamType sal_stream_type) { - if (remote_smd != NULL) { - int count; - for (count = 0; count < remote_smd->n_total_streams; ++count) { - if (remote_smd->streams[count].type == sal_stream_type) { - return &remote_smd->streams[count]; +static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { + int count; + if (smd != NULL) { + for (count = 0; count < smd->n_total_streams; ++count) { + if (smd->streams[count].type == sal_stream_type) { + return &smd->streams[count]; } } - if (remote_smd == NULL || count == remote_smd->n_total_streams) { - ms_warning("Could not find the associated stream of type %d for remote desc", sal_stream_type); - } + } + if (smd == NULL || count == smd->n_total_streams) { + ms_warning("Could not find the associated stream of type %d", sal_stream_type); } return NULL; @@ -377,7 +376,7 @@ 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 + // 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); @@ -435,8 +434,9 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { switch (rtcp_XR_get_block_type(block)) { case RTCP_XR_VOIP_METRICS: { metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block); - metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block); - metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block); + metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq = 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); diff --git a/tester/call_tester.c b/tester/call_tester.c index 51fb39859..b7c6f8861 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1935,7 +1935,7 @@ static void statistics_not_sent_if_call_not_started() { // wait a few time... wait_for(marie->lc,NULL,NULL,0); - // since the callee was busy, there shouldn't be no publish to do + // since the callee was busy, there should be no publish to do CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); @@ -1963,7 +1963,7 @@ static void statistics_sent_at_call_termination() { // PUBLISH submission to the collector should be ok CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); // failing since server side is not implemented + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline);