diff --git a/configure.ac b/configure.ac index 5fe32ef33..7c231b20a 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,28 @@ else echo "GTK interface compilation is disabled." fi +AC_ARG_ENABLE(notify, + [ --enable-notify=[yes/no] Enable libnotify support [default=yes]], + [case "${enableval}" in + yes) notify=true ;; + no) notify=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-notify) ;; + esac],[notify=true]) + +dnl conditionnal build of the notify library +if test "$gtk_ui" = "true" ; then + if test "$notify" = "true"; then + PKG_CHECK_MODULES([NOTIFY], [libnotify >= 0.7.0 ], [found_notify=yes], foo=bar) + case "$found_notify" in + yes) + AC_SUBST(NOTIFY_CFLAGS) + AC_SUBST(NOTIFY_LIBS) + AC_DEFINE([HAVE_NOTIFY],[1],[NOTIFY support]) + esac + else + echo "Libnotify support is disabled." + fi +fi dnl os-specific problems not handled by existing macros. case "$host_os" in diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 1f00b1995..a49c1a968 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -195,7 +195,8 @@ static void call_received(SalOp *h){ ms_message("the local ring is already started"); } }else{ - /*TODO : play a tone within the context of the current call */ + /* play a tone within the context of the current call */ + linphone_core_play_tone(lc); } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index b042a1398..bf656c810 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2313,7 +2313,6 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call) ms_message("ring stopped"); lc->ringstream=NULL; } - linphone_core_get_default_proxy(lc,&cfg); dest_proxy=cfg; dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to); @@ -2369,6 +2368,11 @@ static void terminate_call(LinphoneCore *lc, LinphoneCall *call){ ring_stop(lc->ringstream); lc->ringstream=NULL; } + + /*stop any dtmf tone still playing */ + ms_message("test"); + linphone_core_stop_dtmf(lc); + linphone_call_stop_media_streams(call); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Call ended") ); @@ -3684,6 +3688,25 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } +/** + * @ingroup media_parameters + * Plays a repeated tone to the local user until next further call to #linphone_core_stop_dtmf() + * @param lc #LinphoneCore +**/ +void linphone_core_play_tone(LinphoneCore *lc){ + MSFilter *f=get_dtmf_gen(lc); + MSDtmfGenCustomTone def; + if (f==NULL){ + ms_error("No dtmf generator at this time !"); + return; + } + def.duration=300; + def.frequency=500; + def.amplitude=1; + def.interval=800; + ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); +} + /** * @ingroup media_parameters * diff --git a/coreapi/private.h b/coreapi/private.h index bb1fb883b..47592514f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -210,6 +210,8 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg); +void linphone_core_play_tone(LinphoneCore *lc); + void linphone_call_init_media_streams(LinphoneCall *call); void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone); void linphone_call_stop_media_streams(LinphoneCall *call); diff --git a/gtk/Makefile.am b/gtk/Makefile.am index c51234eb3..56ac4a336 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -49,7 +49,7 @@ linphone_SOURCES= \ linphone_LDADD=$(ORTP_LIBS) \ $(MEDIASTREAMER_LIBS) \ $(top_builddir)/coreapi/liblinphone.la \ - $(LIBGTK_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) + $(LIBGTK_LIBS) $(NOTIFY_LIBS) $(LIBGTKMAC_LIBS) $(INTLLIBS) if BUILD_WIN32 diff --git a/gtk/main.c b/gtk/main.c index e8313628f..ac4e632aa 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -36,6 +36,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define chdir _chdir #endif +#ifdef HAVE_NOTIFY +#include +#endif + #define LINPHONE_ICON "linphone.png" const char *this_program_ident_string="linphone_ident_string=" LINPHONE_VERSION; @@ -56,6 +60,7 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to); static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); +static void linphone_gtk_status_icon_set_blinking(gboolean val); static gboolean verbose=0; @@ -622,6 +627,24 @@ static void completion_add_text(GtkEntry *entry, const char *text){ save_uri_history(); } + +static void linphone_gtk_show_main_window(){ + GtkWidget *w=linphone_gtk_get_main_window(); + LinphoneCore *lc=linphone_gtk_get_core(); + if (linphone_core_video_enabled(lc)){ + linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview", + VIDEOSELFVIEW_DEFAULT)); + } + gtk_widget_show(w); + gtk_window_present(GTK_WINDOW(w)); +} + +static void linphone_gtk_show(LinphoneCore *lc){ +#ifndef HAVE_NOTIFY + linphone_gtk_show_main_window(); +#endif +} + void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ GtkWidget *mw=linphone_gtk_get_main_window(); if (linphone_core_get_calls(linphone_gtk_get_core())==NULL){ @@ -749,6 +772,7 @@ void linphone_gtk_answer_clicked(GtkWidget *button){ if (call){ linphone_core_pause_all_calls(linphone_gtk_get_core()); linphone_core_accept_call(linphone_gtk_get_core(),call); + linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */ } } @@ -759,7 +783,7 @@ void linphone_gtk_enable_video(GtkWidget *w){ gtk_widget_set_sensitive(selfview_item,val); if (val){ linphone_core_enable_video_preview(linphone_gtk_get_core(), - linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT)); + linphone_gtk_get_ui_config_int("videoselfview",VIDEOSELFVIEW_DEFAULT)); }else{ linphone_core_enable_video_preview(linphone_gtk_get_core(),FALSE); } @@ -783,21 +807,6 @@ void linphone_gtk_used_identity_changed(GtkWidget *w){ if (sel) g_free(sel); } -static void linphone_gtk_show_main_window(){ - GtkWidget *w=linphone_gtk_get_main_window(); - LinphoneCore *lc=linphone_gtk_get_core(); - if (linphone_core_video_enabled(lc)){ - linphone_core_enable_video_preview(lc,linphone_gtk_get_ui_config_int("videoselfview", - VIDEOSELFVIEW_DEFAULT)); - } - gtk_widget_show(w); - gtk_window_present(GTK_WINDOW(w)); -} - -static void linphone_gtk_show(LinphoneCore *lc){ - linphone_gtk_show_main_window(); -} - static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){ linphone_gtk_show_friends(); } @@ -938,6 +947,54 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) if (w) linphone_gtk_call_log_update(w); } +#ifdef HAVE_NOTIFY +static void make_notification(const char *title, const char *body){ + NotifyNotification *n; + n = notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON)); + if (n && !notify_notification_show(n,NULL)) + ms_error("Failed to send notification."); +} + +#endif + +static void linphone_gtk_notify(LinphoneCall *call, const char *msg){ +#ifdef HAVE_NOTIFY + if (!notify_is_initted()) + if (!notify_init ("Linphone")) ms_error("Libnotify failed to init."); +#endif + if (!call) { +#ifdef HAVE_NOTIFY + if (!notify_notification_show(notify_notification_new("Linphone",msg,NULL),NULL)) + ms_error("Failed to send notification."); +#else + linphone_gtk_show_main_window(); +#endif + } else if (!gtk_window_is_active((GtkWindow*)linphone_gtk_get_main_window())) { +#ifdef HAVE_NOTIFY + char *body=NULL; + char *remote=call!=NULL ? linphone_call_get_remote_address_as_string(call) : NULL; + switch(linphone_call_get_state(call)){ + case LinphoneCallError: + make_notification(_("Call error"),body=g_markup_printf_escaped("%s\n%s",msg,remote)); + break; + case LinphoneCallEnd: + make_notification(_("Call ended"),body=g_markup_printf_escaped("%s",remote)); + break; + case LinphoneCallIncomingReceived: + make_notification(_("Incoming call"),body=g_markup_printf_escaped("%s",remote)); + break; + case LinphoneCallPausedByRemote: + make_notification(_("Call paused"),body=g_markup_printf_escaped("by %s",remote)); + break; + default: + break; + } + if (body) g_free(body); + if (remote) g_free(remote); +#endif + } +} + static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){ switch(cs){ case LinphoneCallOutgoingInit: @@ -954,10 +1011,12 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call break; case LinphoneCallEnd: linphone_gtk_in_call_view_terminate(call,NULL); + linphone_gtk_status_icon_set_blinking(FALSE); break; case LinphoneCallIncomingReceived: linphone_gtk_create_in_call_view (call); linphone_gtk_in_call_view_set_incoming(call,!all_other_calls_paused (call,linphone_core_get_calls(lc))); + linphone_gtk_status_icon_set_blinking(TRUE); if (auto_answer) { linphone_call_ref(call); g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer ,call); @@ -974,10 +1033,12 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call break; case LinphoneCallConnected: linphone_gtk_enable_hold_button (call,TRUE,TRUE); + linphone_gtk_status_icon_set_blinking(FALSE); break; default: break; } + linphone_gtk_notify(call, msg); linphone_gtk_update_call_buttons (call); } @@ -1060,18 +1121,49 @@ static GtkStatusIcon *icon=NULL; static void linphone_gtk_init_status_icon(){ const char *icon_path=linphone_gtk_get_ui_config("icon",LINPHONE_ICON); + const char *call_icon_path=linphone_gtk_get_ui_config("start_call_icon","startcall-green.png"); GdkPixbuf *pbuf=create_pixbuf(icon_path); GtkWidget *menu=create_icon_menu(); const char *title; + title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone")); icon=gtk_status_icon_new_from_pixbuf(pbuf); - g_object_unref(G_OBJECT(pbuf)); + gtk_status_icon_set_name(icon,title); g_signal_connect_swapped(G_OBJECT(icon),"activate",(GCallback)linphone_gtk_show_main_window,linphone_gtk_get_main_window()); g_signal_connect(G_OBJECT(icon),"popup-menu",(GCallback)icon_popup_menu,NULL); - title=linphone_gtk_get_ui_config("title",_("Linphone - a video internet phone")); gtk_status_icon_set_tooltip(icon,title); gtk_status_icon_set_visible(icon,TRUE); g_object_set_data(G_OBJECT(icon),"menu",menu); g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)gtk_widget_destroy,menu); + g_object_set_data(G_OBJECT(icon),"icon",pbuf); + g_object_weak_ref(G_OBJECT(icon),(GWeakNotify)g_object_unref,pbuf); + pbuf=create_pixbuf(call_icon_path); + g_object_set_data(G_OBJECT(icon),"call_icon",pbuf); +} + +static gboolean do_icon_blink(GtkStatusIcon *gi){ + GdkPixbuf *call_icon=g_object_get_data(G_OBJECT(gi),"call_icon"); + GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(gi),"icon"); + GdkPixbuf *cur_icon=gtk_status_icon_get_pixbuf(gi); + if (cur_icon==call_icon){ + gtk_status_icon_set_from_pixbuf(gi,normal_icon); + }else{ + gtk_status_icon_set_from_pixbuf(gi,call_icon); + } + return TRUE; +} + +static void linphone_gtk_status_icon_set_blinking(gboolean val){ + guint tout; + tout=(unsigned)GPOINTER_TO_INT(g_object_get_data(G_OBJECT(icon),"timeout")); + if (val && tout==0){ + tout=g_timeout_add(1000,(GSourceFunc)do_icon_blink,icon); + g_object_set_data(G_OBJECT(icon),"timeout",GINT_TO_POINTER(tout)); + }else if (!val && tout!=0){ + GdkPixbuf *normal_icon=g_object_get_data(G_OBJECT(icon),"icon"); + g_source_remove(tout); + g_object_set_data(G_OBJECT(icon),"timeout",NULL); + gtk_status_icon_set_from_pixbuf(icon,normal_icon); + } } void linphone_gtk_load_identities(void){ @@ -1348,9 +1440,11 @@ void linphone_gtk_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){ static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to){ - GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget( + GtkEntry * uri_bar =GTK_ENTRY(linphone_gtk_get_widget( linphone_gtk_get_main_window(), "uribar")); - linphone_gtk_show_main_window(); + char *text; + linphone_gtk_notify(NULL,(text=ms_strdup_printf(_("We are transferred to %s"),refer_to))); + g_free(text); gtk_entry_set_text(uri_bar, refer_to); linphone_gtk_start_call(linphone_gtk_get_main_window()); } @@ -1359,16 +1453,19 @@ static void linphone_gtk_check_soundcards(){ const char **devices=linphone_core_get_sound_devices(linphone_gtk_get_core()); if (devices==NULL || devices[0]==NULL){ linphone_gtk_display_something(GTK_MESSAGE_WARNING, - _("No sound cards have been detected on this computer.\n" - "You won't be able to send or receive audio calls.")); + _("No sound cards have been detected on this computer.\n" + "You won't be able to send or receive audio calls.")); } } static void linphone_gtk_quit(void){ gdk_threads_leave(); - linphone_gtk_destroy_log_window(); - linphone_core_destroy(the_core); - linphone_gtk_log_uninit(); + linphone_gtk_destroy_log_window(); + linphone_core_destroy(the_core); + linphone_gtk_log_uninit(); +#ifdef HAVE_NOTIFY + notify_uninit(); +#endif } #ifdef HAVE_GTK_OSX diff --git a/gtk/main.ui b/gtk/main.ui index ea9c596b0..7a57073ac 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -2,6 +2,66 @@ + + False + + + True + False + 0 + none + + + True + False + 12 + + + True + False + + + True + False + + + True + True + 0 + + + + + + + + True + True + True + False + + + + True + True + 2 + + + + + + + + + True + False + <b>Callee name</b> + True + + + + + False @@ -90,7 +150,6 @@ True False - spread Mute @@ -106,6 +165,20 @@ 0 + + + Merge to conference + True + True + False + + + + True + True + 1 + + Pause @@ -118,7 +191,7 @@ False False - 1 + 2 diff --git a/mediastreamer2 b/mediastreamer2 index 90be72f66..a73e55293 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 90be72f669f3c5067c571b0f29f22eda21166006 +Subproject commit a73e55293ed2b551cf12bfc85d812fa659fb25da