Commit ceb8533c authored by Gautier Pelloux-Prayer's avatar Gautier Pelloux-Prayer
Browse files

Merge branch 'quality_reporting'

Conflicts:
	coreapi/linphonecall.c
	mediastreamer2
	tester/call_tester.c
parents b74aa1f5 0470d052
......@@ -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"
......
......@@ -203,6 +203,7 @@
<ClCompile Include="..\..\..\coreapi\offeranswer.c" />
<ClCompile Include="..\..\..\coreapi\presence.c" />
<ClCompile Include="..\..\..\coreapi\proxy.c" />
<ClCompile Include="..\..\..\coreapi\quality_reporting.c" />
<ClCompile Include="..\..\..\coreapi\sal.c" />
<ClCompile Include="..\..\..\coreapi\siplogin.c" />
<ClCompile Include="..\..\..\coreapi\sipsetup.c" />
......
......@@ -74,6 +74,7 @@ set(SOURCE_FILES
offeranswer.c
presence.c
proxy.c
quality_reporting.c
remote_provisioning.c
sal.c
siplogin.c
......
......@@ -56,6 +56,7 @@ liblinphone_la_SOURCES=\
xml2lpc.c \
lpc2xml.c \
remote_provisioning.c \
quality_reporting.c \
$(GITVERSION_FILE)
if BUILD_UPNP
......
......@@ -768,7 +768,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));
......@@ -777,6 +776,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:
......@@ -795,9 +795,17 @@ 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){
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*/
if (call->non_op_error.reason==SalReasonNone){
......@@ -1980,6 +1988,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);
if (used_pt!=-1){
VideoStreamDir dir=VideoStreamSendRecv;
MSWebCam *cam=lc->video_conf.device;
......@@ -2202,6 +2211,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);
......@@ -2230,6 +2240,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);
......@@ -2756,6 +2767,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);
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) {
......@@ -2766,6 +2779,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);
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)
......@@ -2801,6 +2816,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) {
......@@ -2811,6 +2827,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)
......
......@@ -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 <math.h>
#include <ortp/telephonyevents.h>
......@@ -127,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;
}
......@@ -390,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);
}
......
......@@ -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.
......
......@@ -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;
......
......@@ -34,6 +34,7 @@ extern "C" {
#include "linphonecore_utils.h"
#include "sal/sal.h"
#include "sipsetup.h"
#include "quality_reporting.h"
#include <belle-sip/object.h>
#include <belle-sip/dict.h>
......@@ -115,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]; /**<Quality statistics of the call (rfc6035) */
bool_t video_enabled;
};
......@@ -191,6 +194,7 @@ struct _LinphoneCall
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
MSAudioEndpoint *endpoint; /*used for conferencing*/
char *refer_to;
LinphoneCallParams params;
......@@ -399,6 +403,7 @@ struct _LinphoneProxyConfig
char *reg_proxy;
char *reg_identity;
char *reg_route;
char *reg_statistics_collector;
char *realm;
char *contact_params;
char *contact_uri_params;
......@@ -415,6 +420,7 @@ struct _LinphoneProxyConfig
bool_t publish;
bool_t dial_escape_plus;
bool_t send_publish;
bool_t send_statistics;
bool_t pad[3];
void* user_data;
time_t deletion_date;
......@@ -804,6 +810,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);
......@@ -852,11 +859,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
*/
......
......@@ -46,6 +46,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob
const char *identity = lc ? lp_config_get_default_string(lc->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));
......
/*
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"
#include "ortp/rtpsession.h"
#include <math.h>
/***************************************************************************
* TODO / REMINDER LIST
****************************************************************************/
// 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
/***************************************************************************
* END OF TODO / REMINDER LIST
****************************************************************************/
#define STR_REASSIGN(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).
static char * float_to_one_decimal_string(float f) {
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);
}
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 a 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);
}
#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);
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 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;
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;
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");
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(const LinphoneCall* call, const reporting_session_report_t * report) {
LinphoneContent content = {0};
LinphoneAddress *addr;
int expires = -1;
size_t offset = 0;
size_t size = 2048;
char * buffer;
// 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");
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);