Quality reporting: add on_report_send callback to check reports content in unit tests

parent dda79c7b
......@@ -106,6 +106,7 @@ struct _LinphoneCallParams{
struct _LinphoneQualityReporting{
reporting_session_report_t * reports[2]; /**Store information on audio and video media streams (RFC 6035) */
bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/
LinphoneQualityReportingReportSendCb on_report_sent;
};
struct _LinphoneCallLog{
......@@ -860,7 +861,6 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu
const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref);
void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc);
/*****************************************************************************
* REMOTE PROVISIONING FUNCTIONS *
****************************************************************************/
......
......@@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/***************************************************************************
* TODO / REMINDER LIST
***************************************************************************
- move qos data at report's end? <-- unit test recup publish body
bug ms_debug
***************************************************************************
* END OF TODO / REMINDER LIST
****************************************************************************/
......@@ -122,19 +122,15 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) {
IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret|=METRICS_PACKET_LOSS);
IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret|=METRICS_PACKET_LOSS);
/*since these are same values than local ones, do not check them*/
/*if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION;*/
/*if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/
/*if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION;*/
/*if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/
if (rm.session_description.frame_duration != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.packet_loss_concealment != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION;
if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION;
IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret|=METRICS_JITTER_BUFFER);
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.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY);
IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY);
......@@ -337,6 +333,13 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report,
content.data = buffer;
content.size = strlen(buffer);
if (call->log->reporting.on_report_sent != NULL){
call->log->reporting.on_report_sent(
call,
(report==call->log->reporting.reports[0])?LINPHONE_CALL_STATS_AUDIO:LINPHONE_CALL_STATS_VIDEO,
&content);
}
if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){
ret=4;
} else {
......@@ -485,9 +488,9 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
if (local_payload != NULL) {
report->local_metrics.session_description.payload_type = local_payload->type;
STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type));
report->local_metrics.session_description.sample_rate = local_payload->clock_rate;
STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
if (local_payload->recv_fmtp!=NULL) STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp));
}
if (remote_payload != NULL) {
......@@ -694,3 +697,6 @@ void linphone_reporting_destroy(reporting_session_report_t * report) {
}
void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb){
call->log->reporting.on_report_sent = cb;
}
......@@ -139,6 +139,9 @@ typedef struct reporting_session_report {
time_t last_report_date;
} reporting_session_report_t;
typedef void (*LinphoneQualityReportingReportSendCb)(const LinphoneCall *call, int stream_type, const LinphoneContent *content);
reporting_session_report_t * linphone_reporting_new();
void linphone_reporting_destroy(reporting_session_report_t * report);
......@@ -194,6 +197,16 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type);
*/
void linphone_reporting_call_state_updated(LinphoneCall *call);
/**
* Setter of the #LinphoneQualityReportingReportSendCb callback method which is
* notified each time a report will be submitted to the collector, if quality
* reporting is enabled
* @param call #LinphoneCall object to consider
* @param cb #LinphoneQualityReportingReportSendCb callback function to notify
*
*/
void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb);
#ifdef __cplusplus
}
#endif
......
......@@ -22,6 +22,93 @@
#include "private.h"
#include "liblinphone_tester.h"
/*avoid crash if x is NULL on libc versions <4.5.26 */
#define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y))
void on_report_send_mandatory(const LinphoneCall *call, int stream_type, const LinphoneContent *content){
const MediaStream * ms = ((stream_type == LINPHONE_CALL_STATS_AUDIO)?&call->audiostream->ms:&call->videostream->ms);
char * body = (char *)content->data;
char * remote_metrics_start = __strstr(body, "RemoteMetrics:");
reporting_session_report_t * report = call->log->reporting.reports[stream_type];
CU_ASSERT_TRUE(
__strstr(body, "VQIntervalReport\r\n") == body ||
__strstr(body, "VQSessionReport\r\n") == body ||
__strstr(body, "VQSessionReport: CallTerm\r\n") == body
);
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "CallID:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalID:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteID:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "OrigID:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalGroup:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteGroup:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalAddr:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteAddr:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "START="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "STOP="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PT="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PD="));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SR="));
/* We should have not reached RemoteMetrics section yet */
CU_ASSERT_TRUE(!remote_metrics_start || body < remote_metrics_start);
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "DialogID:"));
if (report->remote_metrics.rtcp_sr_count&&ms->rc!=NULL){
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "AdaptiveAlg:"));
}
}
char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, char * body){
if (metrics->rtcp_xr_count){
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "JitterBuffer:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PacketLoss:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "QualityEst:"));
}
if (metrics->rtcp_sr_count){
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Delay:"));
}
return body;
}
void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, int stream_type, const LinphoneContent *content){
char * body = (char*)content->data;
char * remote_metrics_start = __strstr(body, "RemoteMetrics:");
reporting_session_report_t * report = call->log->reporting.reports[stream_type];
on_report_send_mandatory(call,stream_type,content);
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:"));
CU_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start);
}
void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, int stream_type, const LinphoneContent *content){
char * body = (char*)content->data;
reporting_session_report_t * report = call->log->reporting.reports[stream_type];
on_report_send_mandatory(call,stream_type,content);
if (report->remote_metrics.rtcp_sr_count+report->remote_metrics.rtcp_xr_count>0){
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteMetrics:"));
CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:"));
on_report_send_verify_metrics(&report->remote_metrics,body);
}
}
void on_report_send_with_rtcp_xr_both(const LinphoneCall *call, int stream_type, const LinphoneContent *content){
on_report_send_with_rtcp_xr_local(call,stream_type,content);
on_report_send_with_rtcp_xr_remote(call,stream_type,content);
}
void create_call_for_quality_reporting_tests(
LinphoneCoreManager* marie,
LinphoneCoreManager* pauline,
......@@ -42,7 +129,7 @@ static void quality_reporting_not_used_without_config() {
create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline);
// marie has stats collection enabled since pauline has not
// marie has stats collection enabled but pauline has not
CU_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy));
CU_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy));
......@@ -111,11 +198,12 @@ static void quality_reporting_not_sent_if_low_bandwidth() {
static void quality_reporting_at_call_termination() {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr");
LinphoneCall* call_marie = NULL;
LinphoneCall* call_pauline = NULL;
create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline);
linphone_reporting_set_on_report_send(call_marie, on_report_send_with_rtcp_xr_remote);
linphone_core_terminate_all_calls(marie->lc);
......@@ -128,7 +216,6 @@ static void quality_reporting_at_call_termination() {
CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc));
CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc));
// 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));
......@@ -138,12 +225,13 @@ static void quality_reporting_at_call_termination() {
}
static void quality_reporting_interval_report() {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr");
LinphoneCall* call_marie = NULL;
LinphoneCall* call_pauline = NULL;
create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline);
linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory);
linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3);
CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc));
......@@ -158,7 +246,7 @@ static void quality_reporting_interval_report() {
}
static void quality_reporting_session_report_if_video_stopped() {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* call_pauline = NULL;
LinphoneCallParams* pauline_params;
......@@ -174,6 +262,7 @@ static void quality_reporting_session_report_if_video_stopped() {
linphone_call_params_enable_video(pauline_params,TRUE);
CU_ASSERT_TRUE(call_with_params(pauline,marie,pauline_params,marie_params));
call_pauline=linphone_core_get_current_call(pauline->lc);
linphone_reporting_set_on_report_send(linphone_core_get_current_call(marie->lc), on_report_send_with_rtcp_xr_local);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0);
CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0);
......
[sip]
sip_port=-1
sip_tcp_port=-1
sip_tls_port=-1
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
composing_idle_timeout=1
[auth_info_0]
username=marie
userid=marie
passwd=secret
realm=sip.example.org
[proxy_0]
reg_proxy=sip.example.org;transport=tcp
reg_route=sip.example.org;transport=tcp;lr
reg_identity=sip:marie@sip.example.org
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
quality_reporting_collector=sip:collector@sip.example.org
quality_reporting_enabled=1
[friend_0]
url="Paupoche" <sip:pauline@sip.example.org>
pol=accept
subscribe=0
[rtp]
audio_rtp_port=8070
video_rtp_port=9072
rtcp_xr_enabled=1
rtcp_xr_rcvr_rtt_mode=all
rtcp_xr_rcvr_rtt_max_size=10000
rtcp_xr_stat_summary_enabled=1
rtcp_xr_voip_metrics_enabled=1
[video]
display=0
capture=0
show_local=0
size=vga
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture
[sound]
echocancellation=0 #to not overload cpu in case of VG
[sip]
sip_port=-1
sip_tcp_port=-1
sip_tls_port=-1
default_proxy=0
ping_with_options=0
register_only_when_network_is_up=0
composing_idle_timeout=1
[auth_info_0]
username=pauline
userid=pauline
passwd=secret
realm=sip.example.org
[proxy_0]
reg_proxy=sip2.linphone.org;transport=tls
reg_route=sip2.linphone.org;transport=tls
reg_identity=sip:pauline@sip.example.org
reg_expires=3600
reg_sendregister=1
publish=0
dial_escape_plus=0
#[friend_0]
#url="Mariette" <sip:marie@sip.example.org>
#pol=accept
#subscribe=0
[rtp]
audio_rtp_port=8090
video_rtp_port=9092
rtcp_xr_enabled=1
rtcp_xr_rcvr_rtt_mode=all
rtcp_xr_rcvr_rtt_max_size=10000
rtcp_xr_stat_summary_enabled=1
rtcp_xr_voip_metrics_enabled=1
[video]
display=0
capture=0
show_local=0
size=vga
enabled=0
self_view=0
automatically_initiate=0
automatically_accept=0
device=StaticImage: Static picture
[sound]
echocancellation=0 #to not overload cpu in case of VG
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment