Quality reporting: send session reports when video is disabled

parent 99594853
......@@ -819,6 +819,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){
void linphone_call_fix_call_parameters(LinphoneCall *call){
call->params.has_video=call->current_params.has_video;
if (call->params.media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/
call->params.media_encryption=call->current_params.media_encryption;
}
......@@ -906,17 +907,10 @@ 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==LinphoneCallEnd){
if (call->log->status == LinphoneCallSuccess)
linphone_reporting_publish_session_report(call);
}
linphone_reporting_call_state_updated(call);
if (cstate==LinphoneCallReleased){
if (call->op!=NULL) {
......
......@@ -129,8 +129,8 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro
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();
cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new();
cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new();
return cl;
}
......@@ -394,8 +394,8 @@ 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]);
if (cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]);
if (cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]);
ms_free(cl);
}
......@@ -3257,7 +3257,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
linphone_core_update_streams (lc,call,md);
linphone_call_fix_call_parameters(call);
}
if (call->state != LinphoneCallOutgoingEarlyMedia) /*don't change the state in case of outgoing early (SIP UPDATE)*/
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
return 0;
......
......@@ -103,6 +103,11 @@ struct _LinphoneCallParams{
uint8_t avpf_rr_interval;
};
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*/
};
struct _LinphoneCallLog{
struct _LinphoneCore *lc;
LinphoneCallDir dir; /**< The direction of the call*/
......@@ -119,10 +124,12 @@ 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]; /**<Quality statistics of the call (rfc6035) */
struct _LinphoneQualityReporting reporting;
bool_t video_enabled;
};
typedef struct _CallCallbackObj
{
LinphoneCallCbFunc _func;
......
......@@ -85,7 +85,7 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs
/*if we are out of memory, we add some size to buffer*/
if (ret == BELLE_SIP_BUFFER_OVERFLOW) {
/*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/
ms_warning("Buffer was too small to contain the whole report - increasing its size from %lu to %lu",
ms_warning("QualityReporting: Buffer was too small to contain the whole report - increasing its size from %lu to %lu",
(unsigned long)*buff_size, (unsigned long)*buff_size + 2048);
*buff_size += 2048;
*buff = (char *) ms_realloc(*buff, *buff_size);
......@@ -187,7 +187,7 @@ static bool_t media_report_enabled(LinphoneCall * call, int stats_type){
if (stats_type == LINPHONE_CALL_STATS_VIDEO && !linphone_call_params_video_enabled(linphone_call_get_current_params(call)))
return FALSE;
return (call->log->reports[stats_type] != NULL);
return (call->log->reporting.reports[stats_type] != NULL);
}
static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) {
......@@ -308,28 +308,30 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off
ms_free(moscq_str);
}
static void send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) {
static int send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) {
LinphoneContent content = {0};
LinphoneAddress *addr;
int expires = -1;
size_t offset = 0;
size_t size = 2048;
char * buffer;
int ret = 0;
/*if the call was hung up too early, we might have invalid IPs information
in that case, we abort the report since it's not useful data*/
if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0
|| report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) {
ms_warning("The call was hang up too early (duration: %d sec) and IP could "
ms_warning("QualityReporting: Trying to submit a %s too early (call duration: %d sec) and IP could "
"not be retrieved so dropping this report"
, report_event
, linphone_call_get_duration(call));
return;
return 1;
}
addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy));
if (addr == NULL) {
ms_warning("Asked to submit reporting statistics but no collector address found");
return;
ms_warning("QualityReporting: Asked to submit reporting statistics but no collector address found");
return 2;
}
buffer = (char *) ms_malloc(size);
......@@ -362,11 +364,14 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r
content.size = strlen(buffer);
/*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/
linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content);
if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){
ret=3;
}
linphone_address_destroy(addr);
reset_avg_metrics(report);
linphone_content_uninit(&content);
return ret;
}
static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) {
......@@ -379,7 +384,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc
}
}
ms_warning("Could not find the associated stream of type %d", sal_stream_type);
ms_warning("QualityReporting: Could not find the associated stream of type %d", sal_stream_type);
return NULL;
}
......@@ -391,19 +396,19 @@ static void 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;
STR_REASSIGN(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr));
call->log->reporting.reports[stats_type]->info.local_addr.port = local_desc->rtp_port;
STR_REASSIGN(call->log->reporting.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;
call->log->reporting.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) {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr));
} else {
STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr));
STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr));
}
}
}
......@@ -432,11 +437,12 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
const PayloadType * local_payload = NULL;
const PayloadType * remote_payload = NULL;
const LinphoneCallParams * current_params = linphone_call_get_current_params(call);
reporting_session_report_t * report = call->log->reports[stats_type];
reporting_session_report_t * report = call->log->reporting.reports[stats_type];
if (!media_report_enabled(call, stats_type))
return;
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));
......@@ -496,7 +502,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) {
}
void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) {
reporting_session_report_t * report = call->log->reports[stats_type];
reporting_session_report_t * report = call->log->reporting.reports[stats_type];
reporting_content_metrics_t * metrics = NULL;
MSQosAnalyzer *analyzer=NULL;
LinphoneCallStats stats = call->stats[stats_type];
......@@ -554,21 +560,31 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) {
}
}
static void publish_report(LinphoneCall *call, const char *event_type){
static int publish_report(LinphoneCall *call, const char *event_type){
int ret = 0;
int i;
for (i = 0; i < 2; i++){
if (media_report_enabled(call, i)){
int sndret;
linphone_reporting_update_media_info(call, i);
send_report(call, call->log->reports[i], event_type);
sndret=send_report(call, call->log->reporting.reports[i], event_type);
if (sndret>0){
ret += 10+(i+1)*sndret;
}
} else{
ret += i+1;
}
}
return ret;
}
void linphone_reporting_publish_session_report(LinphoneCall* call) {
publish_report(call, "VQSessionReport: CallTerm");
int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term) {
char * session_type = call_term?"VQSessionReport: CallTerm":"VQSessionReport";
return publish_report(call, session_type);
}
void linphone_reporting_publish_interval_report(LinphoneCall* call) {
publish_report(call, "VQIntervalReport");
int linphone_reporting_publish_interval_report(LinphoneCall* call) {
return publish_report(call, "VQIntervalReport");
}
reporting_session_report_t * linphone_reporting_new() {
......@@ -628,3 +644,35 @@ void linphone_reporting_destroy(reporting_session_report_t * report) {
ms_free(report);
}
void linphone_reporting_call_state_updated(LinphoneCall *call){
LinphoneCallState state=linphone_call_get_state(call);
bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO);
switch (state){
case LinphoneCallStreamsRunning:
if (enabled!=call->log->reporting.was_video_running){
if (enabled){
linphone_reporting_update_ip(call);
}else{
ms_message("Send midterm report with status %d",
send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport")
);
}
}else{
linphone_reporting_update_ip(call);
}
call->log->reporting.was_video_running=enabled;
break;
case LinphoneCallEnd:
if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){
ms_message("Send report with status %d",
linphone_reporting_publish_session_report(call, TRUE)
);
}
break;
default:
break;
}
}
......@@ -164,25 +164,35 @@ void linphone_reporting_update_ip(LinphoneCall * call);
* Publish a session report. This function should be called when session terminates,
* media change (codec change or session fork), session terminates due to no media packets being received.
* @param call #LinphoneCall object to consider
* @param call_term whether the call has ended or is continuing
*
* @return error code. 0 for success, positive value otherwise.
*/
void linphone_reporting_publish_session_report(LinphoneCall* call);
int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term);
/**
* Publish an interval report. This function should be used for periodic interval
* @param call #LinphoneCall object to consider
* @return error code. 0 for success, positive value otherwise.
*
*/
void linphone_reporting_publish_interval_report(LinphoneCall* call);
int linphone_reporting_publish_interval_report(LinphoneCall* call);
/**
* Update publish report data with fresh RTCP stats, if needed.
* Update publish reports with newly received RTCP-XR packets (if available).
* @param call #LinphoneCall object to consider
* @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO)
*
*/
void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type);
/**
* Update publish reports on call state change.
* @param call #LinphoneCall object to consider
*
*/
void linphone_reporting_call_state_updated(LinphoneCall *call);
#ifdef __cplusplus
}
#endif
......
......@@ -2199,11 +2199,11 @@ static void quality_reporting_not_used_without_config() {
linphone_proxy_config_get_quality_reporting_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);
CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip);
CU_ASSERT_PTR_NULL(call_pauline->log->reporting.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);
CU_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
......@@ -2247,7 +2247,7 @@ static void quality_reporting_at_call_termination() {
linphone_core_terminate_all_calls(marie->lc);
// now dialog id should be filled
CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id);
CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id);
CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000));
CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000));
......
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