]> sjero.net Git - linphone/blob - gtk/incall_view.c
Merge remote-tracking branch 'origin/master' into dev_gtk_new_ui
[linphone] / gtk / incall_view.c
1 /*
2 linphone, gtk-glade interface.
3 Copyright (C) 2009  Simon MORLAT (simon.morlat@linphone.org)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19 /*
20 *  C Implementation: incall_frame
21 *
22 * Description: 
23 *
24 *
25 * Author: Simon Morlat <simon.morlat@linphone.org>, (C) 2009
26 *
27 *
28 */
29
30 #include "linphone.h"
31
32
33 gboolean linphone_gtk_use_in_call_view(){
34         static int val=-1;
35         if (val==-1) val=linphone_gtk_get_ui_config_int("use_incall_view",1);
36         return val;
37 }
38
39 LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf){
40         LinphoneCore *lc=linphone_gtk_get_core();
41         GtkWidget *main_window=linphone_gtk_get_main_window ();
42         GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
43         const MSList *calls=linphone_core_get_calls(lc);
44         if (is_conf) *is_conf=FALSE;
45         if (!linphone_gtk_use_in_call_view() || ms_list_size(calls)==1){
46                 if (calls) return (LinphoneCall*)calls->data;
47         }else{
48                 int idx=gtk_notebook_get_current_page (notebook);
49                 GtkWidget *page=gtk_notebook_get_nth_page(notebook,idx);
50                 if (page!=NULL){
51                         LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call");
52                         if (call==NULL){
53                                 if (page==g_object_get_data(G_OBJECT(main_window),"conference_tab")){
54                                         if (is_conf)
55                                                 *is_conf=TRUE;
56                                         return NULL;
57                                 }
58                         }
59                         return call;
60                 }
61         }
62         return NULL;
63 }
64
65 static GtkWidget *make_tab_header(int number){
66         GtkWidget *w=gtk_hbox_new (FALSE,0);
67         GtkWidget *i=create_pixmap ("status-green.png");
68         GtkWidget *l;
69         gchar *text=g_strdup_printf(_("Call #%i"),number);
70         l=gtk_label_new (text);
71         gtk_box_pack_start (GTK_BOX(w),i,FALSE,FALSE,0);
72         gtk_box_pack_end(GTK_BOX(w),l,TRUE,TRUE,0);
73         gtk_widget_show_all(w);
74         return w;
75 }
76
77 static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){
78         GtkWidget *container=linphone_gtk_get_widget(callview,"in_call_animation");
79         GList *elem=gtk_container_get_children(GTK_CONTAINER(container));
80         GtkWidget *image;
81         
82         if (!is_stock){
83                 if (image_name==NULL){
84                         gtk_widget_hide(container);
85                 }
86                 image=create_pixmap(image_name);
87         }else
88                 image=gtk_image_new_from_stock(image_name,GTK_ICON_SIZE_DIALOG);
89         if (elem)
90                 gtk_widget_destroy((GtkWidget*)elem->data);
91         gtk_widget_show(image);
92         gtk_container_add(GTK_CONTAINER(container),image);
93         gtk_widget_show_all(container);
94 }
95
96 static void linphone_gtk_in_call_set_animation_spinner(GtkWidget *callview){
97 #if GTK_CHECK_VERSION(2,20,0)
98         GtkWidget *container=linphone_gtk_get_widget(callview,"in_call_animation");
99         GList *elem=gtk_container_get_children(GTK_CONTAINER(container));
100         GtkWidget *spinner=gtk_spinner_new();
101         if (elem)
102                 gtk_widget_destroy((GtkWidget*)elem->data);
103         gtk_widget_show(spinner);
104         gtk_container_add(GTK_CONTAINER(container),spinner);
105         gtk_widget_set_size_request(spinner, 20,20);
106         gtk_spinner_start(GTK_SPINNER(spinner));
107 #endif
108 }
109
110 static void linphone_gtk_transfer_call(LinphoneCall *dest_call){
111         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
112         if (call) linphone_core_transfer_call_to_another(linphone_gtk_get_core(),call,dest_call);
113 }
114
115 static void transfer_button_clicked(GtkWidget *button, gpointer call_ref){
116         GtkWidget *menu_item;
117         GtkWidget *menu=gtk_menu_new();
118         LinphoneCall *call=(LinphoneCall*)call_ref;
119         LinphoneCore *lc=linphone_gtk_get_core();
120         const MSList *elem=linphone_core_get_calls(lc);
121         
122         for(;elem!=NULL;elem=elem->next){
123                 LinphoneCall *other_call=(LinphoneCall*)elem->data;
124                 GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(other_call);
125                 if (other_call!=call){
126                         int call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_view),"call_index"));
127                         char *remote_uri=linphone_call_get_remote_address_as_string (other_call);
128                         char *text=g_strdup_printf(_("Transfer to call #%i with %s"),call_index,remote_uri);
129                         menu_item=gtk_image_menu_item_new_with_label(text);
130                         ms_free(remote_uri);
131                         g_free(text);
132                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),create_pixmap("status-green.png"));
133                         gtk_widget_show(menu_item);
134                         gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
135                         g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_transfer_call,other_call);
136                 }
137         }
138         gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,
139                 gtk_get_current_event_time());
140         gtk_widget_show(menu);
141 }
142
143 void linphone_gtk_enable_transfer_button(LinphoneCore *lc, gboolean value){
144         const MSList *elem=linphone_core_get_calls(lc);
145         for(;elem!=NULL;elem=elem->next){
146                 LinphoneCall *call=(LinphoneCall*)elem->data;
147                 GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call);
148                 GtkWidget *box=linphone_gtk_get_widget (call_view,"mute_pause_buttons");
149                 GtkWidget *button=(GtkWidget*)g_object_get_data(G_OBJECT(box),"transfer");
150                 if (button && value==FALSE){
151                         gtk_widget_destroy(button);
152                         button=NULL;
153                 }else if (!button && value==TRUE){
154                         button=gtk_button_new_with_label (_("Transfer"));
155                         //gtk_button_set_image_position(GTK_BUTTON(button),GTK_POS_BOTTOM);
156                         gtk_button_set_image(GTK_BUTTON(button),gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,GTK_ICON_SIZE_BUTTON));
157                         g_signal_connect(G_OBJECT(button),"clicked",(GCallback)transfer_button_clicked,call);
158                         gtk_widget_show_all(button);
159                         gtk_container_add(GTK_CONTAINER(box),button);
160                 }
161                 g_object_set_data(G_OBJECT(box),"transfer",button);
162         }
163 }
164
165 static void conference_button_clicked(GtkWidget *button, gpointer call_ref){
166         linphone_core_add_all_to_conference(linphone_gtk_get_core());
167         //linphone_core_add_to_conference(linphone_gtk_get_core(),(LinphoneCall*)call_ref);
168         gtk_widget_set_sensitive(button,FALSE);
169 }
170
171 void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){
172         const MSList *elem=linphone_core_get_calls(lc);
173         for(;elem!=NULL;elem=elem->next){
174                 LinphoneCall *call=(LinphoneCall*)elem->data;
175                 GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call);
176                 GtkWidget *box=linphone_gtk_get_widget (call_view,"mute_pause_buttons");
177                 GtkWidget *button=(GtkWidget*)g_object_get_data(G_OBJECT(box),"conference");
178                 if (button && value==FALSE){
179                         gtk_widget_destroy(button);
180                         button=NULL;
181                 }else if (!button && value==TRUE){
182                         button=gtk_button_new_with_label (_("Conference"));
183                         //gtk_button_set_image_position(GTK_BUTTON(button),GTK_POS_BOTTOM);
184                         gtk_button_set_image(GTK_BUTTON(button),gtk_image_new_from_stock (GTK_STOCK_ADD,GTK_ICON_SIZE_BUTTON));
185                         g_signal_connect(G_OBJECT(button),"clicked",(GCallback)conference_button_clicked,call);
186                         gtk_widget_show_all(button);
187                         gtk_container_add(GTK_CONTAINER(box),button);
188                 }
189                 g_object_set_data(G_OBJECT(box),"conference",button);
190         }
191 }
192
193 static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){
194         const LinphoneCallParams *params=linphone_call_get_current_params(call);
195         if (params){
196                 const PayloadType *acodec=linphone_call_params_get_used_audio_codec(params);
197                 const PayloadType *vcodec=linphone_call_params_get_used_video_codec(params);
198                 GtkWidget *acodec_ui=linphone_gtk_get_widget(callstats,"audio_codec");
199                 GtkWidget *vcodec_ui=linphone_gtk_get_widget(callstats,"video_codec");
200                 if (acodec){
201                         
202                         char tmp[64]={0};
203                         snprintf(tmp,sizeof(tmp)-1,"%s/%i/%i",acodec->mime_type,acodec->clock_rate,acodec->channels);
204                         gtk_label_set_label(GTK_LABEL(acodec_ui),tmp);
205                 }else gtk_label_set_label(GTK_LABEL(acodec_ui),_("Not used"));
206                 if (vcodec){
207                         gtk_label_set_label(GTK_LABEL(vcodec_ui),vcodec->mime_type);
208                 }else gtk_label_set_label(GTK_LABEL(vcodec_ui),_("Not used"));
209         }
210 }
211
212 static const char *ice_state_to_string(LinphoneIceState ice_state){
213         switch(ice_state){
214                 case LinphoneIceStateNotActivated:
215                         return _("ICE not activated");
216                 case LinphoneIceStateFailed:
217                         return _("ICE failed");
218                 case LinphoneIceStateInProgress:
219                         return _("ICE in progress");
220                 case LinphoneIceStateReflexiveConnection:
221                         return _("Going through one or more NATs");
222                 case LinphoneIceStateHostConnection:
223                         return _("Direct");
224                 case LinphoneIceStateRelayConnection:
225                         return _("Through a relay server");
226         }
227         return "invalid";
228 }
229
230 static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
231         const LinphoneCallStats *as=linphone_call_get_audio_stats(call);
232         const LinphoneCallStats *vs=linphone_call_get_video_stats(call);
233         LinphoneIceState ice_state=as->ice_state;
234         gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
235                 as->download_bandwidth,as->upload_bandwidth);
236         gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
237         g_free(tmp);
238         tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
239                 vs->download_bandwidth,vs->upload_bandwidth);
240         gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
241         g_free(tmp);
242         gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"media_connectivity")),ice_state_to_string(ice_state));
243 }
244
245 static gboolean refresh_call_stats(GtkWidget *callstats){
246         LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(callstats),"call");
247         switch (linphone_call_get_state(call)){
248                 case LinphoneCallError:
249                 case LinphoneCallEnd:
250                 case LinphoneCallReleased:
251                         gtk_widget_destroy(callstats);
252                         return FALSE;
253                 break;
254                 case LinphoneCallStreamsRunning:
255                         _refresh_call_stats(callstats,call);
256                 break;
257                 default:
258                 break;
259         }
260         return TRUE;
261 }
262
263 static void on_call_stats_destroyed(GtkWidget *call_view){
264         GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(call_view),"call_stats");
265         LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(call_stats),"call");
266         g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_stats),"tid")));
267         g_object_set_data(G_OBJECT(call_view),"call_stats",NULL);
268         linphone_call_unref(call);
269 }
270
271 static void linphone_gtk_show_call_stats(LinphoneCall *call){
272         GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
273         GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(w),"call_stats");
274         if (call_stats==NULL){
275                 guint tid;
276                 call_stats=linphone_gtk_create_window("call_statistics");
277                 g_object_set_data(G_OBJECT(w),"call_stats",call_stats);
278                 g_object_set_data(G_OBJECT(call_stats),"call",linphone_call_ref(call));
279                 tid=g_timeout_add(1000,(GSourceFunc)refresh_call_stats,call_stats);
280                 g_object_set_data(G_OBJECT(call_stats),"tid",GINT_TO_POINTER(tid));
281                 g_signal_connect_swapped(G_OBJECT(call_stats),"destroy",(GCallback)on_call_stats_destroyed,(gpointer)w);
282                 show_used_codecs(call_stats,call);
283                 refresh_call_stats(call_stats);
284                 gtk_widget_show(call_stats);
285         }
286         
287 }
288
289 void linphone_gtk_create_in_call_view(LinphoneCall *call){
290         GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame");
291         GtkWidget *main_window=linphone_gtk_get_main_window ();
292         GtkNotebook *notebook=(GtkNotebook *)linphone_gtk_get_widget(main_window,"viewswitch");
293         static int call_index=1;
294         int idx;
295
296         if (ms_list_size(linphone_core_get_calls(linphone_gtk_get_core()))==1){
297                 /*this is the only call at this time */
298                 call_index=1;
299         }
300         g_object_set_data(G_OBJECT(call_view),"call",call);
301         g_object_set_data(G_OBJECT(call_view),"call_index",GINT_TO_POINTER(call_index));
302
303         linphone_call_set_user_pointer (call,call_view);
304         linphone_call_ref(call);
305         gtk_notebook_append_page (notebook,call_view,make_tab_header(call_index));
306         gtk_widget_show(call_view);
307         idx = gtk_notebook_page_num(notebook, call_view);
308         gtk_notebook_set_current_page(notebook, idx);
309         call_index++;
310         linphone_gtk_enable_hold_button (call,FALSE,TRUE);
311         linphone_gtk_enable_mute_button(
312                                         GTK_BUTTON(linphone_gtk_get_widget(call_view,"incall_mute")),FALSE);
313         
314         GtkWidget *button=linphone_gtk_get_widget(call_view,"terminate_call");
315         GtkWidget *image=create_pixmap("stopcall-red.png");
316         gtk_button_set_label(GTK_BUTTON(button),_("Stop"));
317         gtk_button_set_image(GTK_BUTTON(button),image);
318         gtk_widget_show(image);
319         g_signal_connect_swapped(G_OBJECT(linphone_gtk_get_widget(call_view,"quality_indicator")),"button-press-event",(GCallback)linphone_gtk_show_call_stats,call);
320
321 }
322
323 static void video_button_clicked(GtkWidget *button, LinphoneCall *call){
324         gboolean adding=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"adding_video"));
325         LinphoneCore *lc=linphone_call_get_core(call);
326         LinphoneCallParams *params=linphone_call_params_copy(linphone_call_get_current_params(call));
327         gtk_widget_set_sensitive(button,FALSE);
328         linphone_call_params_enable_video(params,adding);
329         linphone_core_update_call(lc,call,params);
330         linphone_call_params_destroy(params);
331 }
332
333 void linphone_gtk_update_video_button(LinphoneCall *call){
334         GtkWidget *call_view=(GtkWidget*)linphone_call_get_user_pointer(call);
335         GtkWidget *button;
336         const LinphoneCallParams *params=linphone_call_get_current_params(call);
337         gboolean has_video=linphone_call_params_video_enabled(params);
338         if (call_view==NULL) return;
339         button=linphone_gtk_get_widget(call_view,"video_button");
340
341         gtk_button_set_image(GTK_BUTTON(button),
342            gtk_image_new_from_stock(has_video ? GTK_STOCK_REMOVE : GTK_STOCK_ADD,GTK_ICON_SIZE_BUTTON));
343         g_object_set_data(G_OBJECT(button),"adding_video",GINT_TO_POINTER(!has_video));
344         if (!linphone_core_video_supported(linphone_call_get_core(call))){
345                 gtk_widget_set_sensitive(button,FALSE);
346                 return;
347         }
348         if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"signal_connected"))==0){
349                 g_signal_connect(G_OBJECT(button),"clicked",(GCallback)video_button_clicked,call);
350                 g_object_set_data(G_OBJECT(button),"signal_connected",GINT_TO_POINTER(1));
351         }
352         gtk_widget_set_sensitive(button,linphone_call_get_state(call)==LinphoneCallStreamsRunning);
353 }
354
355 void linphone_gtk_remove_in_call_view(LinphoneCall *call){
356         GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call);
357         GtkWidget *main_window=linphone_gtk_get_main_window ();
358         GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch");
359         gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
360         int idx;
361         g_return_if_fail(w!=NULL);
362         idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w);
363         gtk_notebook_remove_page (GTK_NOTEBOOK(nb),idx);
364         gtk_widget_destroy(w);
365         if (in_conf){
366                 linphone_gtk_unset_from_conference(call);
367         }
368         linphone_call_set_user_pointer (call,NULL);
369         linphone_call_unref(call);
370         call=linphone_core_get_current_call(linphone_gtk_get_core());
371         if (call==NULL){
372                 if (linphone_core_is_in_conference(linphone_gtk_get_core())){
373                         /*show the conference*/
374                         gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),
375                                             g_object_get_data(G_OBJECT(main_window),"conference_tab")));
376                 }else gtk_notebook_set_current_page(GTK_NOTEBOOK(nb), 0);
377         }else{
378                 /*show the active call*/
379                 gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),gtk_notebook_page_num(GTK_NOTEBOOK(nb),
380                                                                                      linphone_call_get_user_pointer(call)));
381         }
382 }
383
384 static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){
385         const char *displayname=NULL;
386         const char *id;
387         char *uri_label;
388         displayname=linphone_address_get_display_name(from);
389         id=linphone_address_as_string_uri_only(from);
390         
391         if (displayname!=NULL){
392                 uri_label=g_markup_printf_escaped("<span size=\"large\">%s</span>\n<i>%s</i>", 
393                         displayname,id);
394         }else
395                 uri_label=g_markup_printf_escaped("<span size=\"large\"><i>%s</i></span>\n",id);
396         gtk_label_set_markup(GTK_LABEL(label),uri_label);
397         g_free(uri_label);
398 }
399
400 void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){
401         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
402         GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
403         GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
404         GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
405         
406         gtk_label_set_markup(GTK_LABEL(status),_("<b>Calling...</b>"));
407         display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
408         
409         gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
410         linphone_gtk_in_call_set_animation_spinner(callview);
411 }
412
413 void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call){
414         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
415         GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
416         GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
417         GtkWidget *answer_button;
418         GtkWidget *image;
419
420         gtk_label_set_markup(GTK_LABEL(status),_("<b>Incoming call</b>"));
421         gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel"));
422         gtk_widget_hide(linphone_gtk_get_widget(callview,"mute_pause_buttons"));
423         display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
424
425         answer_button=linphone_gtk_get_widget(callview,"accept_call");
426         image=create_pixmap (linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"));
427         gtk_button_set_label(GTK_BUTTON(answer_button),_("Answer"));
428         gtk_button_set_image(GTK_BUTTON(answer_button),image);
429         gtk_widget_show(image);
430         
431         image=create_pixmap (linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"));
432         gtk_button_set_image(GTK_BUTTON(linphone_gtk_get_widget(callview,"decline_call")),image);
433         gtk_widget_show(image);
434         
435         linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_DIALOG_INFO,TRUE);
436 }
437
438 static void rating_to_color(float rating, GdkColor *color){
439         const char *colorname="grey";
440         if (rating>=4.0)
441                 colorname="green";
442         else if (rating>=3.0)
443                 colorname="white";
444         else if (rating>=2.0)
445                 colorname="yellow";
446         else if (rating>=1.0)
447                 colorname="orange";
448         else if (rating>=0)
449                 colorname="red";
450         if (!gdk_color_parse(colorname,color)){
451                 g_warning("Fail to parse color %s",colorname);
452         }
453 }
454
455 static const char *rating_to_text(float rating){
456         if (rating>=4.0)
457                 return _("good");
458         if (rating>=3.0)
459                 return _("average");
460         if (rating>=2.0)
461                 return _("poor");
462         if (rating>=1.0)
463                 return _("very poor");
464         if (rating>=0)
465                 return _("too bad");
466         return _("unavailable");
467 }
468
469 static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){
470         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
471         GtkWidget *qi=linphone_gtk_get_widget(callview,"quality_indicator");
472         float rating=linphone_call_get_current_quality(call);
473         GdkColor color;
474         gchar tmp[50];
475         linphone_gtk_in_call_view_update_duration(call);
476         if (rating>=0){
477                 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),rating/5.0);
478                 snprintf(tmp,sizeof(tmp),"%.1f (%s)",rating,rating_to_text(rating));
479                 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),tmp);
480         }else{
481                 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),0);
482                 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),_("unavailable"));
483         }
484         rating_to_color(rating,&color);
485         gtk_widget_modify_bg(qi,GTK_STATE_NORMAL,&color);
486         return TRUE;
487 }
488
489
490
491 typedef struct _volume_ctx{
492         GtkWidget *widget;
493         get_volume_t get_volume;
494         void *data;
495         float last_value;
496 }volume_ctx_t;
497
498 #define UNSIGNIFICANT_VOLUME (-26)
499 #define SMOOTH 0.15
500
501 static gboolean update_audio_meter(volume_ctx_t *ctx){
502         float volume_db=ctx->get_volume(ctx->data);
503         float frac=(volume_db-UNSIGNIFICANT_VOLUME)/(float)(-UNSIGNIFICANT_VOLUME+3.0);
504         if (frac<0) frac=0;
505         if (frac>1.0) frac=1.0;
506         if (frac<ctx->last_value){
507                 frac=(frac*SMOOTH)+(ctx->last_value*(1-SMOOTH));
508         }
509         ctx->last_value=frac;
510         //g_message("volume_db=%f, frac=%f",volume_db,frac);
511         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ctx->widget),frac);
512         return TRUE;
513 }
514
515 static void on_audio_meter_destroy(guint task_id){
516         g_source_remove(task_id);
517 }
518
519 void linphone_gtk_init_audio_meter(GtkWidget *w, get_volume_t get_volume, void *data){
520         guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id"));
521         if (task_id==0){
522                 volume_ctx_t *ctx=g_new(volume_ctx_t,1);
523                 ctx->widget=w;
524                 ctx->get_volume=get_volume;
525                 ctx->data=data;
526                 ctx->last_value=0;
527                 g_object_set_data_full(G_OBJECT(w),"ctx",ctx,g_free);
528                 task_id=g_timeout_add(50,(GSourceFunc)update_audio_meter,ctx);
529                 g_object_set_data_full(G_OBJECT(w),"task_id",GINT_TO_POINTER(task_id),(GDestroyNotify)on_audio_meter_destroy);
530         }
531 }
532
533 void linphone_gtk_uninit_audio_meter(GtkWidget *w){
534         guint task_id=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"task_id"));
535         if (task_id!=0){
536                 g_object_set_data(G_OBJECT(w),"ctx",NULL);
537                 g_object_set_data(G_OBJECT(w),"task_id",NULL);
538         }
539 }
540
541 void linphone_gtk_in_call_view_enable_audio_view(LinphoneCall *call, gboolean val){
542         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
543         GtkWidget *audio_view=linphone_gtk_get_widget(callview,"incall_audioview");
544         //GtkWidget *mic=linphone_gtk_get_widget(callview,"incall_mic_icon");
545         GtkWidget *spk=linphone_gtk_get_widget(callview,"incall_spk_icon");
546         GtkWidget *mic_level=linphone_gtk_get_widget(callview,"mic_audiolevel");
547         GtkWidget *spk_level=linphone_gtk_get_widget(callview,"spk_audiolevel");
548         GdkPixbuf *pbuf;
549         //gtk_image_set_from_pixbuf(GTK_IMAGE(mic),(pbuf=create_pixbuf("mic_active.png")));
550         //g_object_unref(pbuf);
551         if (val){
552                 gtk_image_set_from_pixbuf(GTK_IMAGE(spk),(pbuf=create_pixbuf("speaker.png")));
553                 g_object_unref(pbuf);
554                 linphone_gtk_init_audio_meter(mic_level,(get_volume_t)linphone_call_get_record_volume,call);
555                 linphone_gtk_init_audio_meter(spk_level,(get_volume_t)linphone_call_get_play_volume,call);
556                 gtk_widget_show_all(audio_view);
557         }else{
558                 linphone_gtk_uninit_audio_meter(mic_level);
559                 linphone_gtk_uninit_audio_meter(spk_level);
560                 gtk_widget_hide(audio_view);
561         }
562 }
563
564 void linphone_gtk_auth_token_verified_clicked(GtkButton *button){
565         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
566         if (call){
567                 linphone_call_set_authentication_token_verified(call,!linphone_call_get_authentication_token_verified(call));
568         }
569 }
570
571 void linphone_gtk_in_call_view_show_encryption(LinphoneCall *call){
572         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
573         GtkWidget *encryption_box=linphone_gtk_get_widget(callview,"encryption_box");
574         GtkWidget *label=linphone_gtk_get_widget(callview,"encryption_label");
575         GtkWidget *status_icon=linphone_gtk_get_widget(callview,"encryption_status_icon");
576         GtkWidget *verify_button=linphone_gtk_get_widget(callview,"encryption_verify_button");
577         LinphoneMediaEncryption me=linphone_call_params_get_media_encryption(linphone_call_get_current_params(call));
578         bool_t verified=linphone_call_get_authentication_token_verified(call);
579         switch(me){
580                 case LinphoneMediaEncryptionSRTP:
581                         gtk_widget_show_all(encryption_box);
582                         gtk_label_set_markup(GTK_LABEL(label),_("Secured by SRTP"));
583                         gtk_widget_hide(status_icon);
584                         gtk_widget_hide(verify_button);
585                 break;
586                 case LinphoneMediaEncryptionZRTP:
587                 {
588                         gchar *text=g_strdup_printf(_("Secured by ZRTP - [auth token: %s]"),linphone_call_get_authentication_token(call));
589                         gtk_label_set_markup(GTK_LABEL(label),text);
590                         g_free(text);
591                         gtk_image_set_from_stock(GTK_IMAGE(status_icon),
592                                                   verified ? GTK_STOCK_APPLY : GTK_STOCK_DIALOG_WARNING,GTK_ICON_SIZE_MENU);
593                         gtk_button_set_label(GTK_BUTTON(verify_button),
594                                              verified ? _("Set unverified") : _("Set verified"));
595                         gtk_widget_show_all(encryption_box);
596                 }       
597                 break;
598                 default:
599                         gtk_widget_hide_all(encryption_box);
600         }
601 }
602
603 void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
604         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
605         GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
606         GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri");
607         GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
608         guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
609         gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
610         GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats");
611         
612         display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
613
614         gtk_widget_set_visible(linphone_gtk_get_widget(callview,"mute_pause_buttons"),!in_conf);
615         gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
616         gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("<b>In call</b>"));
617
618         gtk_label_set_text(GTK_LABEL(duration),_("00::00::00"));
619         linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PLAY,TRUE);
620         linphone_gtk_enable_mute_button(
621                                         GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),!in_conf);
622         if (taskid==0){
623                 taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call);
624                 g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid));
625         }
626         linphone_gtk_in_call_view_enable_audio_view(call, !in_conf);
627         linphone_gtk_in_call_view_show_encryption(call);
628         if (in_conf) linphone_gtk_set_in_conference(call);
629         if (call_stats) show_used_codecs(call_stats,call);
630 }
631
632 void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
633         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
634         GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
635         gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
636         gtk_label_set_markup(GTK_LABEL(status),_("<b>Paused call</b>"));
637         linphone_gtk_in_call_set_animation_image(callview,GTK_STOCK_MEDIA_PAUSE,TRUE);
638 }
639
640 void linphone_gtk_in_call_view_update_duration(LinphoneCall *call){
641         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
642         GtkWidget *duration_label=linphone_gtk_get_widget(callview,"in_call_duration");
643         int duration=linphone_call_get_duration(call);
644         char tmp[256]={0};
645         int seconds=duration%60;
646         int minutes=(duration/60)%60;
647         int hours=duration/3600;
648         snprintf(tmp,sizeof(tmp)-1,_("%02i::%02i::%02i"),hours,minutes,seconds);
649         gtk_label_set_text(GTK_LABEL(duration_label),tmp);
650 }
651
652 static gboolean in_call_view_terminated(LinphoneCall *call){
653         linphone_gtk_remove_in_call_view(call);
654         return FALSE;
655 }
656
657 void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_msg){
658         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
659         GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status");
660         guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
661         gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));    
662
663         if ((callview==NULL) || (status==NULL)) return;
664         if (error_msg==NULL)
665                 gtk_label_set_markup(GTK_LABEL(status),_("<b>Call ended.</b>"));
666         else{
667                 char *msg=g_markup_printf_escaped("<span color=\"red\"><b>%s</b></span>",error_msg);
668                 gtk_label_set_markup(GTK_LABEL(status),msg);
669                 g_free(msg);
670         }
671         linphone_gtk_in_call_set_animation_image(callview,
672                    linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png"),FALSE);
673         
674         gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel"));
675         gtk_widget_hide(linphone_gtk_get_widget(callview,"incall_audioview"));
676         gtk_widget_hide(linphone_gtk_get_widget(callview,"terminate_call"));
677         gtk_widget_hide(linphone_gtk_get_widget(callview,"video_button"));
678         linphone_gtk_enable_mute_button(
679                 GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE);
680         linphone_gtk_enable_hold_button(call,FALSE,TRUE);
681         
682         if (taskid!=0) g_source_remove(taskid);
683         g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call);
684         if (in_conf)
685                 linphone_gtk_terminate_conference_participant(call);
686 }
687
688 void linphone_gtk_in_call_view_set_transfer_status(LinphoneCall *call,LinphoneCallState cstate){
689         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call);
690         if (callview){
691                 GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
692                 const char *transfer_status="unknown";
693                 switch(cstate){
694                         case LinphoneCallOutgoingProgress:
695                                 transfer_status=_("Transfer in progress");
696                         break;
697                         case LinphoneCallConnected:
698                                 transfer_status=_("Transfer done.");
699                         break;
700                         case LinphoneCallError:
701                                 transfer_status=_("Transfer failed.");
702                         break;
703                         default:
704                         break;
705                 }
706                 gtk_label_set_text(GTK_LABEL(duration),transfer_status);
707         }
708 }
709
710 void linphone_gtk_draw_mute_button(GtkButton *button, gboolean active){
711         g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
712         if (active){
713                 GtkWidget *image=create_pixmap("mic_muted.png");
714                 /*gtk_button_set_label(GTK_BUTTON(button),_("Unmute"));*/
715                 if (image!=NULL) {
716                         gtk_button_set_image(GTK_BUTTON(button),image);
717                         gtk_widget_show(image);
718                 }
719         }else{
720                 GtkWidget *image=create_pixmap("mic_active.png");
721                 /*gtk_button_set_label(GTK_BUTTON(button),_("Mute"));*/
722                 if (image!=NULL) {
723                         gtk_button_set_image(GTK_BUTTON(button),image);
724                         gtk_widget_show(image);
725                 }
726         }
727 }
728
729 void linphone_gtk_mute_clicked(GtkButton *button){
730         int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active"));
731         linphone_core_mute_mic(linphone_gtk_get_core(),!active);
732         linphone_gtk_draw_mute_button(button,!active);
733 }
734
735 void linphone_gtk_enable_mute_button(GtkButton *button, gboolean sensitive)
736 {
737         /*gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);*/
738         gtk_widget_set_visible(GTK_WIDGET(button),sensitive);
739         linphone_gtk_draw_mute_button(button,FALSE);
740 }
741
742 void linphone_gtk_draw_hold_button(GtkButton *button, gboolean active){
743         g_object_set_data(G_OBJECT(button),"active",GINT_TO_POINTER(active));
744         if (active){
745                 GtkWidget *image=create_pixmap("hold_off.png");
746                 gtk_button_set_label(GTK_BUTTON(button),_("Resume"));
747                 if (image!=NULL) {
748                         gtk_button_set_image(GTK_BUTTON(button),image);
749                         gtk_widget_show(image);
750                 }
751         }else{
752                 GtkWidget *image=create_pixmap("hold_on.png");
753                 gtk_button_set_label(GTK_BUTTON(button),_("Pause"));
754                 if (image!=NULL) {
755                         gtk_button_set_image(GTK_BUTTON(button),image);
756                         gtk_widget_show(image);
757                 }
758         }
759 }
760
761 void linphone_gtk_hold_clicked(GtkButton *button){
762         int active=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button),"active"));
763         LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
764         if (!call) return;
765         if(!active)
766         {
767                 linphone_core_pause_call(linphone_gtk_get_core(),call);
768         }
769         else
770         {
771                 linphone_core_resume_call(linphone_gtk_get_core(),call);
772         }
773 }
774
775 void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gboolean holdon){
776         GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call);
777         GtkWidget *button;
778         g_return_if_fail(callview!=NULL);
779         button=linphone_gtk_get_widget(callview,"hold_call");
780         gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
781         gtk_widget_set_visible(GTK_WIDGET(button),sensitive);
782         linphone_gtk_draw_hold_button(GTK_BUTTON(button),!holdon);
783 }
784
785 void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){
786         gtk_widget_destroy(call_stats);
787 }
788