Commit 4f2c73c2 authored by Simon Morlat's avatar Simon Morlat

implement call quality indicator

parent c959542f
......@@ -43,6 +43,13 @@
*
**/
/**
* @defgroup call_misc Obtaining information about a running call: sound volumes, quality indicators
*
* When a call is running, it is possible to retrieve in real time current measured volumes and quality indicator.
*
**/
/**
* @defgroup media_parameters Controlling media parameters
**/
......
......@@ -585,6 +585,17 @@ void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int
cp->audio_bw=bandwidth;
}
#ifdef VIDEO_ENABLED
/**
* Request remote side to send us a Video Fast Update.
**/
void linphone_call_send_vfu_request(LinphoneCall *call)
{
if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
sal_call_send_vfu_request(call->op);
}
#endif
/**
*
**/
......@@ -1040,16 +1051,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){
}
}
#ifdef VIDEO_ENABLED
/**
* Request remote side to send us VFU.
**/
void linphone_call_send_vfu_request(LinphoneCall *call)
{
if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
sal_call_send_vfu_request(call->op);
}
#endif
void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) {
if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){
......@@ -1089,6 +1091,11 @@ bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){
}
}
/**
* @addtogroup call_misc
* @{
**/
/**
* Returns the measured sound volume played locally (received from remote)
* It is expressed in dbm0.
......@@ -1119,6 +1126,45 @@ float linphone_call_get_record_volume(LinphoneCall *call){
return LINPHONE_VOLUME_DB_LOWEST;
}
/**
* Obtain real-time quality rating of the call
*
* Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated
* during all the duration of the call. This function returns its value at the time of the function call.
* It is expected that the rating is updated at least every 5 seconds or so.
* The rating is a floating point number comprised between 0 and 5.
*
* 4-5 = good quality <br>
* 3-4 = average quality <br>
* 2-3 = poor quality <br>
* 1-2 = very poor quality <br>
* 0-1 = can't be worse, mostly unusable <br>
*
* @returns The function returns -1 if no quality measurement is available, for example if no
* active audio stream exist. Otherwise it returns the quality rating.
**/
float linphone_call_get_current_quality(LinphoneCall *call){
if (call->audiostream){
return audio_stream_get_quality_rating(call->audiostream);
}
return -1;
}
/**
* Returns call quality averaged over all the duration of the call.
*
* See linphone_call_get_current_quality() for more details about quality measurement.
**/
float linphone_call_get_average_quality(LinphoneCall *call){
if (call->audiostream){
return audio_stream_get_average_quality_rating(call->audiostream);
}
return -1;
}
/**
* @}
**/
static void display_bandwidth(RtpSession *as, RtpSession *vs){
ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
......@@ -1171,6 +1217,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if (call->videostream!=NULL)
video_stream_iterate(call->videostream);
#endif
if (call->audiostream!=NULL)
audio_stream_iterate(call->audiostream);
if (one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
if (disconnected)
......
......@@ -255,6 +255,8 @@ LinphoneReason linphone_call_get_reason(const LinphoneCall *call);
const char *linphone_call_get_remote_user_agent(LinphoneCall *call);
float linphone_call_get_play_volume(LinphoneCall *call);
float linphone_call_get_record_volume(LinphoneCall *call);
float linphone_call_get_current_quality(LinphoneCall *call);
float linphone_call_get_average_quality(LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
/**
......
......@@ -205,7 +205,6 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus
gtk_label_set_markup(GTK_LABEL(status),_("<b>Incoming call</b>"));
gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"duration_frame"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"mute_pause_buttons"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
......@@ -228,6 +227,57 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG);
}
static void rating_to_color(float rating, GdkColor *color){
const char *colorname="grey";
if (rating>=4.0)
colorname="green";
else if (rating>=3.0)
colorname="white";
else if (rating>=2.0)
colorname="yellow";
else if (rating>=1.0)
colorname="orange";
else if (rating>=0)
colorname="red";
if (!gdk_color_parse(colorname,color)){
g_warning("Fail to parse color %s",colorname);
}
}
static const char *rating_to_text(float rating){
if (rating>=4.0)
return _("good");
if (rating>=3.0)
return _("average");
if (rating>=2.0)
return _("poor");
if (rating>=1.0)
return _("very poor");
if (rating>=0)
return _("too bad");
return _("unavailable");
}
static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *qi=linphone_gtk_get_widget(callview,"quality_indicator");
float rating=linphone_call_get_current_quality(call);
GdkColor color;
gchar tmp[50];
linphone_gtk_in_call_view_update_duration(call);
if (rating>=0){
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),rating/5.0);
snprintf(tmp,sizeof(tmp),"%.1f (%s)",rating,rating_to_text(rating));
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),tmp);
}else{
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),0);
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),_("unavailable"));
}
rating_to_color(rating,&color);
gtk_widget_modify_bg(qi,GTK_STATE_NORMAL,&color);
return TRUE;
}
void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
......@@ -235,10 +285,10 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif");
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
gtk_widget_show(linphone_gtk_get_widget(callview,"duration_frame"));
gtk_widget_show(linphone_gtk_get_widget(callview,"mute_pause_buttons"));
gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
gtk_label_set_markup(GTK_LABEL(status),_("<b>In call</b>"));
......@@ -250,6 +300,10 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG);
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE);
if (taskid==0){
taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call);
g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid));
}
}
void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
......@@ -283,6 +337,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation");
GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"));
guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
if (error_msg==NULL)
gtk_label_set_markup(GTK_LABEL(status),_("<b>Call ended.</b>"));
......@@ -299,6 +354,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE);
linphone_gtk_enable_hold_button(call,FALSE,TRUE);
if (taskid!=0) g_source_remove(taskid);
g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call);
}
......
......@@ -632,15 +632,6 @@ void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){
update_video_title();
}
static gboolean in_call_timer(){
LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core());
if (call){
linphone_gtk_in_call_view_update_duration(call);
return TRUE;
}
return FALSE;
}
static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){
for(;calls!=NULL;calls=calls->next){
LinphoneCall *call=(LinphoneCall*)calls->data;
......@@ -961,7 +952,6 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call
linphone_gtk_enable_mute_button(
GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
TRUE);
g_timeout_add(250,(GSourceFunc)in_call_timer,NULL);
break;
case LinphoneCallError:
linphone_gtk_in_call_view_terminate (call,msg);
......
This diff is collapsed.
mediastreamer2 @ 3c6e9bf1
Subproject commit ef298ba2719c94f2de563deb7a8ef441d45794fc
Subproject commit 3c6e9bf14efefa4ddd078d7b24ce46b5177da3c7
oRTP @ 6e9ac1d1
Subproject commit 7b39874dae3c514901d40cd62d648ab2f849fdff
Subproject commit 6e9ac1d1f7c60f60bd67656c92ae801c61f41b27
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