diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b70e90600..bb35fc98c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -869,7 +869,7 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collecto /** * Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an * interval report will be sent to the collector. On call termination, a session report will be sent - * for the remaining period. Value must be 0 (disabled) or greater than 120sec to avoid overloading. + * for the remaining period. Value must be 0 (disabled) or positive. * @param[in] cfg #LinphoneProxyConfig object * @param[in] interval The interval in seconds, 0 means interval reports are disabled. */ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8faaa95cf..3772bc744 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -491,7 +491,7 @@ bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg) } void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) { - cfg->quality_reporting_interval = interval ? MAX(interval, 120) : 0; + cfg->quality_reporting_interval = interval; } int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { @@ -1216,6 +1216,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config const char *proxy; LinphoneProxyConfig *cfg; char key[50]; + int interval; sprintf(key,"proxy_%i",index); @@ -1237,7 +1238,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); - linphone_proxy_config_set_quality_reporting_interval(cfg, lp_config_get_int(config, key, "quality_reporting_interval", 0)); + interval=lp_config_get_int(config, key, "quality_reporting_interval", 0); + linphone_proxy_config_set_quality_reporting_interval(cfg, interval? MAX(interval, 120) : 0); linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 251f82b38..81241efd1 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -35,6 +35,8 @@ For codecs that are able to change sample rates, the lowest and highest sample r moslq == moscq valgrind video: what happens if doing stop/resume? +one single report <- merge audio/video? +unit test interval report rlq value: need algo to compute it 3.4 overload avoidance? @@ -111,7 +113,7 @@ static void reset_avg_metrics(reporting_session_report_t * report){ metrics[i]->delay.round_trip_delay = 0; - metrics[i]->delay.symm_one_way_delay = 0; + /*metrics[i]->delay.symm_one_way_delay = 0;*/ } report->last_report_date = ms_time(NULL); } @@ -147,15 +149,15 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY); + /*IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY);*/ IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY); IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY); if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; - if (rm.adaptive_algorithm.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.adaptive_algorithm.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.qos_analyzer.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.qos_analyzer.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); @@ -236,7 +238,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off } 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, " 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); } @@ -271,8 +273,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.adaptive_algorithm.input); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.adaptive_algorithm.output); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.qos_analyzer.output); } append_to_buffer(buffer, size, offset, "\r\n"); @@ -395,11 +397,11 @@ static bool_t is_reporting_enabled(const LinphoneCall * call) { static void qos_analyser_on_action_suggested(void *user_data, const char * input, const char * output){ reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; char * newstr = NULL; - newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.input?metrics->adaptive_algorithm.input:"", input); - STR_REASSIGN(metrics->adaptive_algorithm.input, newstr) + newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", input); + STR_REASSIGN(metrics->qos_analyzer.input, newstr) - newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.output?metrics->adaptive_algorithm.output:"", output); - STR_REASSIGN(metrics->adaptive_algorithm.output, newstr) + newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.output?metrics->qos_analyzer.output:"", output); + STR_REASSIGN(metrics->qos_analyzer.output, newstr) } void linphone_reporting_update_ip(LinphoneCall * call) { @@ -566,11 +568,13 @@ void linphone_reporting_publish_interval_report(LinphoneCall* call) { return; if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQIntervalReport"); } if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQIntervalReport"); } } @@ -625,8 +629,8 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { 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); - if (report->local_metrics.adaptive_algorithm.input != NULL) ms_free(report->local_metrics.adaptive_algorithm.input); - if (report->local_metrics.adaptive_algorithm.output != NULL) ms_free(report->local_metrics.adaptive_algorithm.output); + if (report->local_metrics.qos_analyzer.input != NULL) ms_free(report->local_metrics.qos_analyzer.input); + if (report->local_metrics.qos_analyzer.output != NULL) ms_free(report->local_metrics.qos_analyzer.output); ms_free(report); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 00fb07215..2dc888a89 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -75,7 +75,7 @@ typedef struct reporting_content_metrics { struct { int round_trip_delay; // no - vary int end_system_delay; // no - not implemented yet - int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay) + int symm_one_way_delay; // no - not implemented (depends on end_system_delay) int interarrival_jitter; // no - not implemented yet int mean_abs_jitter; // to check } delay; @@ -94,11 +94,13 @@ typedef struct reporting_content_metrics { float moscq; // no - vary or avg - voip metrics - in [0..4.9] } quality_estimates; - // adaptive algorithm - custom extension + // Quality of Service analyzer - custom extension + /* This should allow us to analysis bad network conditions and quality adaptation + on server side*/ struct { char* input; char* output; - } adaptive_algorithm; + } qos_analyzer; // for internal processing uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) diff --git a/tester/call_tester.c b/tester/call_tester.c index f1b94bbd2..7e2617ca3 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2202,7 +2202,6 @@ static void quality_reporting_not_sent_if_call_not_started() { linphone_core_manager_destroy(pauline); } static void quality_reporting_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; @@ -2228,6 +2227,27 @@ static void quality_reporting_at_call_termination() { linphone_core_manager_destroy(pauline); } +static void quality_reporting_interval_report() { + 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_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); + + // PUBLISH submission to the collector should be ok + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,15000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,15000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + #ifdef VIDEO_ENABLED /*this is call forking with early media managed at client side (not by flexisip server)*/ static void multiple_early_media(void) { @@ -2374,9 +2394,10 @@ test_t call_tests[] = { { "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 quality reporting not used if no config", quality_reporting_not_used_without_config}, - { "Call quality reporting not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, - { "Call quality reporting sent if call ended normally", quality_reporting_at_call_termination}, + { "Quality reporting not used if no config", quality_reporting_not_used_without_config}, + { "Quality reporting session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Quality reporting session report sent if call ended normally", quality_reporting_at_call_termination}, + { "Quality reporting interval report if interval is configured", quality_reporting_interval_report}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate} };