diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2012-02-21 22:18:45 +0800 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2012-02-21 23:02:29 +0800 |
commit | ba0a893b1d31cdb234bae72845e840a895b9d62a (patch) | |
tree | ebdb8e8bd18d4113c564e4716d2d01c4fbc5f232 /src | |
parent | c7dd14aef20e429135fba7c7a53a8d507b9579a3 (diff) | |
download | gsoc2013-empathy-ba0a893b1d31cdb234bae72845e840a895b9d62a.tar.gz gsoc2013-empathy-ba0a893b1d31cdb234bae72845e840a895b9d62a.tar.zst gsoc2013-empathy-ba0a893b1d31cdb234bae72845e840a895b9d62a.zip |
Drop empathy-av
So long and thanks for all the calling...
https://bugzilla.gnome.org/show_bug.cgi?id=629902
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 32 | ||||
-rw-r--r-- | src/empathy-av.c | 172 | ||||
-rw-r--r-- | src/empathy-streamed-media-factory.c | 269 | ||||
-rw-r--r-- | src/empathy-streamed-media-factory.h | 69 | ||||
-rw-r--r-- | src/empathy-streamed-media-handler.c | 903 | ||||
-rw-r--r-- | src/empathy-streamed-media-handler.h | 106 | ||||
-rw-r--r-- | src/empathy-streamed-media-window-fullscreen.c | 309 | ||||
-rw-r--r-- | src/empathy-streamed-media-window-fullscreen.h | 77 | ||||
-rw-r--r-- | src/empathy-streamed-media-window.c | 3202 | ||||
-rw-r--r-- | src/empathy-streamed-media-window.h | 65 | ||||
-rw-r--r-- | src/empathy-streamed-media-window.ui | 861 |
11 files changed, 1 insertions, 6064 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 801052877..cedac8dfa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,6 @@ bin_PROGRAMS = \ libexec_PROGRAMS = \ empathy-auth-client \ - empathy-av \ empathy-chat empathy_accounts_SOURCES = \ @@ -69,33 +68,6 @@ empathy_debugger_SOURCES = \ empathy-debugger.c \ $(NULL) -empathy_av_SOURCES = \ - empathy-av.c \ - empathy-audio-sink.c \ - empathy-audio-sink.h \ - empathy-audio-src.c \ - empathy-audio-src.h \ - empathy-streamed-media-factory.c \ - empathy-streamed-media-factory.h \ - empathy-streamed-media-handler.c \ - empathy-streamed-media-handler.h \ - empathy-streamed-media-window-fullscreen.c \ - empathy-streamed-media-window-fullscreen.h \ - empathy-streamed-media-window.c \ - empathy-streamed-media-window.h \ - empathy-video-src.c \ - empathy-video-src.h \ - empathy-video-widget.c \ - empathy-video-widget.h \ - ev-sidebar.c \ - ev-sidebar.h \ - empathy-mic-monitor.c \ - empathy-mic-monitor.h - $(NULL) - -empathy_av_CFLAGS = $(EMPATHY_AV_CFLAGS) -empathy_av_LDFLAGS = $(EMPATHY_AV_LIBS) $(LIBM) - empathy_auth_client_SOURCES = \ empathy-auth-client.c \ $(NULL) @@ -183,8 +155,7 @@ empathy_LDADD = \ check_c_sources = \ $(empathy_handwritten_source) \ - $(empathy_logs_SOURCES) \ - $(empathy_handwritten_av_source) + $(empathy_logs_SOURCES) include $(top_srcdir)/tools/check-coding-style.mk check-local: check-coding-style @@ -194,7 +165,6 @@ ui_DATA = \ empathy-accounts-dialog.ui \ empathy-call-window-fullscreen.ui \ empathy-call-window.ui \ - empathy-streamed-media-window.ui \ empathy-chat-window.ui \ empathy-chatrooms-window.ui \ empathy-ft-manager.ui \ diff --git a/src/empathy-av.c b/src/empathy-av.c deleted file mode 100644 index 70acfc4f3..000000000 --- a/src/empathy-av.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2007-2010 Collabora Ltd. - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - * - * Authors: Xavier Claessens <xclaesse@gmail.com> - * Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> - */ - -#include <config.h> - -#include <glib.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include <telepathy-glib/debug-sender.h> - -#include <libempathy-gtk/empathy-ui-utils.h> - -#include "empathy-streamed-media-window.h" -#include "empathy-streamed-media-factory.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_VOIP -#include <libempathy/empathy-debug.h> - -#include <gst/gst.h> - -/* Exit after $TIMEOUT seconds if not displaying any call window */ -#define TIMEOUT 60 - -#define EMPATHY_AV_DBUS_NAME "org.gnome.Empathy.AudioVideo" - -static GtkApplication *app = NULL; -static gboolean activated = FALSE; -static gboolean use_timer = TRUE; - -static EmpathyStreamedMediaFactory *call_factory = NULL; - -static void -new_call_handler_cb (EmpathyStreamedMediaFactory *factory, - EmpathyStreamedMediaHandler *handler, - gboolean outgoing, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *window; - - DEBUG ("Create a new StreamedMedia window"); - - window = empathy_streamed_media_window_new (handler); - - g_application_hold (G_APPLICATION (app)); - - g_signal_connect_swapped (window, "destroy", - G_CALLBACK (g_application_release), app); - - gtk_widget_show (GTK_WIDGET (window)); -} - -static void -activate_cb (GApplication *application) -{ - GError *error = NULL; - - if (activated) - return; - - activated = TRUE; - - if (!use_timer) - { - /* keep a 'ref' to the application */ - g_application_hold (G_APPLICATION (app)); - } - - g_assert (call_factory == NULL); - call_factory = empathy_streamed_media_factory_initialise (); - - g_signal_connect (G_OBJECT (call_factory), "new-streamed-media-handler", - G_CALLBACK (new_call_handler_cb), NULL); - - if (!empathy_streamed_media_factory_register (call_factory, &error)) - { - g_critical ("Failed to register Handler: %s", error->message); - g_error_free (error); - } -} - -int -main (int argc, - char *argv[]) -{ - GOptionContext *optcontext; - GOptionEntry options[] = { - { NULL } - }; -#ifdef ENABLE_DEBUG - TpDebugSender *debug_sender; -#endif - GError *error = NULL; - gint retval; - - /* Init */ - g_thread_init (NULL); - - optcontext = g_option_context_new (N_("- Empathy Audio/Video Client")); - g_option_context_add_group (optcontext, gst_init_get_option_group ()); - g_option_context_add_group (optcontext, gtk_get_option_group (TRUE)); - g_option_context_add_main_entries (optcontext, options, GETTEXT_PACKAGE); - - if (!g_option_context_parse (optcontext, &argc, &argv, &error)) { - g_print ("%s\nRun '%s --help' to see a full list of available command " - "line options.\n", - error->message, argv[0]); - g_warning ("Error in empathy-av init: %s", error->message); - return EXIT_FAILURE; - } - - g_option_context_free (optcontext); - - empathy_gtk_init (); - g_set_application_name (_("Empathy Audio/Video Client")); - - /* Make empathy and empathy-av appear as the same app in gnome-shell */ - gdk_set_program_class ("Empathy"); - gtk_window_set_default_icon_name ("empathy"); - textdomain (GETTEXT_PACKAGE); - - app = gtk_application_new (EMPATHY_AV_DBUS_NAME, G_APPLICATION_FLAGS_NONE); - g_signal_connect (app, "activate", G_CALLBACK (activate_cb), NULL); - -#ifdef ENABLE_DEBUG - /* Set up debug sender */ - debug_sender = tp_debug_sender_dup (); - g_log_set_default_handler (tp_debug_sender_log_handler, G_LOG_DOMAIN); -#endif - - if (g_getenv ("EMPATHY_PERSIST") != NULL) - { - DEBUG ("Disable timer"); - - use_timer = FALSE; - } - - /* the inactivity timeout can only be set while the application is held */ - g_application_hold (G_APPLICATION (app)); - g_application_set_inactivity_timeout (G_APPLICATION (app), TIMEOUT * 1000); - g_application_release (G_APPLICATION (app)); - - retval = g_application_run (G_APPLICATION (app), argc, argv); - - g_object_unref (app); - tp_clear_object (&call_factory); - -#ifdef ENABLE_DEBUG - g_object_unref (debug_sender); -#endif - - return retval; -} diff --git a/src/empathy-streamed-media-factory.c b/src/empathy-streamed-media-factory.c deleted file mode 100644 index 1c25ae253..000000000 --- a/src/empathy-streamed-media-factory.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * empathy-streamed-media-factory.c - Source for EmpathyStreamedMediaFactory - * Copyright (C) 2008-2011 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include <stdio.h> -#include <stdlib.h> - -#include <telepathy-glib/account-channel-request.h> -#include <telepathy-glib/simple-handler.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/util.h> - -#include <libempathy/empathy-request-util.h> -#include <libempathy/empathy-utils.h> - -#include "empathy-streamed-media-factory.h" -#include "empathy-streamed-media-handler.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_VOIP -#include <libempathy/empathy-debug.h> - -G_DEFINE_TYPE(EmpathyStreamedMediaFactory, empathy_streamed_media_factory, G_TYPE_OBJECT) - -static void handle_channels_cb (TpSimpleHandler *handler, - TpAccount *account, - TpConnection *connection, - GList *channels, - GList *requests_satisfied, - gint64 user_action_time, - TpHandleChannelsContext *context, - gpointer user_data); - -/* signal enum */ -enum -{ - NEW_STREAMED_MEDIA_HANDLER, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* private structure */ -typedef struct { - TpBaseClient *handler; - gboolean dispose_has_run; -} EmpathyStreamedMediaFactoryPriv; - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStreamedMediaFactory) - -static GObject *call_factory = NULL; - -static void -empathy_streamed_media_factory_init (EmpathyStreamedMediaFactory *obj) -{ - EmpathyStreamedMediaFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (obj, - EMPATHY_TYPE_STREAMED_MEDIA_FACTORY, EmpathyStreamedMediaFactoryPriv); - TpAccountManager *am; - - obj->priv = priv; - - am = tp_account_manager_dup (); - - priv->handler = tp_simple_handler_new_with_am (am, FALSE, FALSE, - EMPATHY_AV_BUS_NAME_SUFFIX, FALSE, handle_channels_cb, obj, NULL); - - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - NULL)); - - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE, - NULL)); - - tp_base_client_take_handler_filter (priv->handler, tp_asv_new ( - TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, G_TYPE_BOOLEAN, TRUE, - NULL)); - - tp_base_client_add_handler_capabilities_varargs (priv->handler, - "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/ice-udp", - "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/gtalk-p2p", - "org.freedesktop.Telepathy.Channel.Interface.MediaSignalling/video/h264", - NULL); - - g_object_unref (am); -} - -static GObject * -empathy_streamed_media_factory_constructor (GType type, guint n_construct_params, - GObjectConstructParam *construct_params) -{ - g_return_val_if_fail (call_factory == NULL, NULL); - - call_factory = G_OBJECT_CLASS (empathy_streamed_media_factory_parent_class)->constructor - (type, n_construct_params, construct_params); - g_object_add_weak_pointer (call_factory, (gpointer)&call_factory); - - return call_factory; -} - -static void -empathy_streamed_media_factory_finalize (GObject *object) -{ - /* free any data held directly by the object here */ - - if (G_OBJECT_CLASS (empathy_streamed_media_factory_parent_class)->finalize) - G_OBJECT_CLASS (empathy_streamed_media_factory_parent_class)->finalize (object); -} - -static void -empathy_streamed_media_factory_dispose (GObject *object) -{ - EmpathyStreamedMediaFactoryPriv *priv = GET_PRIV (object); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->handler); - - if (G_OBJECT_CLASS (empathy_streamed_media_factory_parent_class)->dispose) - G_OBJECT_CLASS (empathy_streamed_media_factory_parent_class)->dispose (object); -} - -static void -empathy_streamed_media_factory_class_init ( - EmpathyStreamedMediaFactoryClass *empathy_streamed_media_factory_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (empathy_streamed_media_factory_class); - - g_type_class_add_private (empathy_streamed_media_factory_class, - sizeof (EmpathyStreamedMediaFactoryPriv)); - - object_class->constructor = empathy_streamed_media_factory_constructor; - object_class->dispose = empathy_streamed_media_factory_dispose; - object_class->finalize = empathy_streamed_media_factory_finalize; - - signals[NEW_STREAMED_MEDIA_HANDLER] = - g_signal_new ("new-streamed-media-handler", - G_TYPE_FROM_CLASS (empathy_streamed_media_factory_class), - G_SIGNAL_RUN_LAST, 0, - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 2, EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, G_TYPE_BOOLEAN); -} - -EmpathyStreamedMediaFactory * -empathy_streamed_media_factory_initialise (void) -{ - g_return_val_if_fail (call_factory == NULL, NULL); - - return EMPATHY_STREAMED_MEDIA_FACTORY (g_object_new (EMPATHY_TYPE_STREAMED_MEDIA_FACTORY, NULL)); -} - -EmpathyStreamedMediaFactory * -empathy_streamed_media_factory_get (void) -{ - g_return_val_if_fail (call_factory != NULL, NULL); - - return EMPATHY_STREAMED_MEDIA_FACTORY (call_factory); -} - -static void -create_streamed_media_handler (EmpathyStreamedMediaFactory *factory, - EmpathyTpStreamedMedia *call) -{ - EmpathyStreamedMediaHandler *handler; - - g_return_if_fail (factory != NULL); - - handler = empathy_streamed_media_handler_new_for_channel (call); - - g_signal_emit (factory, signals[NEW_STREAMED_MEDIA_HANDLER], 0, - handler, FALSE); - - g_object_unref (handler); -} - -static void -call_status_changed_cb (EmpathyTpStreamedMedia *call, - GParamSpec *spec, - EmpathyStreamedMediaFactory *self) -{ - if (empathy_tp_streamed_media_get_status (call) <= EMPATHY_TP_STREAMED_MEDIA_STATUS_READYING) - return; - - create_streamed_media_handler (self, call); - - g_signal_handlers_disconnect_by_func (call, call_status_changed_cb, self); - g_object_unref (call); -} - -static void -handle_channels_cb (TpSimpleHandler *handler, - TpAccount *account, - TpConnection *connection, - GList *channels, - GList *requests_satisfied, - gint64 user_action_time, - TpHandleChannelsContext *context, - gpointer user_data) -{ - EmpathyStreamedMediaFactory *self = user_data; - GList *l; - - for (l = channels; l != NULL; l = g_list_next (l)) - { - TpChannel *channel = l->data; - EmpathyTpStreamedMedia *call; - - if (tp_proxy_get_invalidated (channel) != NULL) - continue; - - if (tp_channel_get_channel_type_id (channel) != - TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA) - continue; - - call = empathy_tp_streamed_media_new (account, channel); - - if (empathy_tp_streamed_media_get_status (call) <= EMPATHY_TP_STREAMED_MEDIA_STATUS_READYING) - { - /* We have to wait that the TpStreamedMedia is ready as the - * call-handler rely on it. */ - tp_g_signal_connect_object (call, "notify::status", - G_CALLBACK (call_status_changed_cb), self, 0); - continue; - } - - create_streamed_media_handler (self, call); - g_object_unref (call); - } - - tp_handle_channels_context_accept (context); -} - -gboolean -empathy_streamed_media_factory_register (EmpathyStreamedMediaFactory *self, - GError **error) -{ - EmpathyStreamedMediaFactoryPriv *priv = GET_PRIV (self); - - return tp_base_client_register (priv->handler, error); -} diff --git a/src/empathy-streamed-media-factory.h b/src/empathy-streamed-media-factory.h deleted file mode 100644 index c69073ec4..000000000 --- a/src/empathy-streamed-media-factory.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * empathy-streamed-media-factory.h - Header for EmpathyStreamedMediaFactory - * Copyright (C) 2008-2011 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __EMPATHY_STREAMED_MEDIA_FACTORY_H__ -#define __EMPATHY_STREAMED_MEDIA_FACTORY_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -typedef struct _EmpathyStreamedMediaFactory EmpathyStreamedMediaFactory; -typedef struct _EmpathyStreamedMediaFactoryClass EmpathyStreamedMediaFactoryClass; - -struct _EmpathyStreamedMediaFactoryClass { - GObjectClass parent_class; -}; - -struct _EmpathyStreamedMediaFactory { - GObject parent; - gpointer priv; -}; - -GType empathy_streamed_media_factory_get_type (void); - -/* TYPE MACROS */ -#define EMPATHY_TYPE_STREAMED_MEDIA_FACTORY \ - (empathy_streamed_media_factory_get_type ()) -#define EMPATHY_STREAMED_MEDIA_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_STREAMED_MEDIA_FACTORY, \ - EmpathyStreamedMediaFactory)) -#define EMPATHY_STREAMED_MEDIA_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_STREAMED_MEDIA_FACTORY, \ - EmpathyStreamedMediaFactoryClass)) -#define EMPATHY_IS_STREAMED_MEDIA_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_STREAMED_MEDIA_FACTORY)) -#define EMPATHY_IS_STREAMED_MEDIA_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_STREAMED_MEDIA_FACTORY)) -#define EMPATHY_STREAMED_MEDIA_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STREAMED_MEDIA_FACTORY, \ - EmpathyStreamedMediaFactoryClass)) - - -EmpathyStreamedMediaFactory *empathy_streamed_media_factory_initialise (void); - -EmpathyStreamedMediaFactory *empathy_streamed_media_factory_get (void); - -gboolean empathy_streamed_media_factory_register (EmpathyStreamedMediaFactory *self, - GError **error); - -G_END_DECLS - -#endif /* #ifndef __EMPATHY_STREAMED_MEDIA_FACTORY_H__*/ diff --git a/src/empathy-streamed-media-handler.c b/src/empathy-streamed-media-handler.c deleted file mode 100644 index a3c539773..000000000 --- a/src/empathy-streamed-media-handler.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * empathy-streamed-media-handler.c - Source for EmpathyStreamedMediaHandler - * Copyright (C) 2008-2011 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include <stdio.h> -#include <stdlib.h> - -#include <telepathy-glib/account-channel-request.h> -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> - -#include <telepathy-farsight/channel.h> -#include <telepathy-farsight/stream.h> - -#include <libempathy/empathy-utils.h> - -#include <libempathy-gtk/empathy-call-utils.h> - -#include "empathy-streamed-media-handler.h" - -#define DEBUG_FLAG EMPATHY_DEBUG_VOIP -#include <libempathy/empathy-debug.h> - -G_DEFINE_TYPE(EmpathyStreamedMediaHandler, empathy_streamed_media_handler, G_TYPE_OBJECT) - -/* signal enum */ -enum { - CONFERENCE_ADDED, - SRC_PAD_ADDED, - SINK_PAD_ADDED, - REQUEST_RESOURCE, - CLOSED, - STREAM_CLOSED, - CANDIDATES_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -enum { - PROP_TP_STREAMED_MEDIA = 1, - PROP_GST_BUS, - PROP_CONTACT, - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_SEND_AUDIO_CODEC, - PROP_SEND_VIDEO_CODEC, - PROP_RECV_AUDIO_CODECS, - PROP_RECV_VIDEO_CODECS, - PROP_AUDIO_REMOTE_CANDIDATE, - PROP_VIDEO_REMOTE_CANDIDATE, - PROP_AUDIO_LOCAL_CANDIDATE, - PROP_VIDEO_LOCAL_CANDIDATE, -}; - -/* private structure */ - -typedef struct { - gboolean dispose_has_run; - EmpathyTpStreamedMedia *call; - EmpathyContact *contact; - TfChannel *tfchannel; - gboolean initial_audio; - gboolean initial_video; - - FsCodec *send_audio_codec; - FsCodec *send_video_codec; - GList *recv_audio_codecs; - GList *recv_video_codecs; - FsCandidate *audio_remote_candidate; - FsCandidate *video_remote_candidate; - FsCandidate *audio_local_candidate; - FsCandidate *video_local_candidate; -} EmpathyStreamedMediaHandlerPriv; - -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStreamedMediaHandler) - -static void -empathy_streamed_media_handler_dispose (GObject *object) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (object); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - if (priv->contact != NULL) - g_object_unref (priv->contact); - - priv->contact = NULL; - - if (priv->tfchannel != NULL) - g_object_unref (priv->tfchannel); - - priv->tfchannel = NULL; - - if (priv->call != NULL) - { - empathy_tp_streamed_media_close (priv->call); - g_object_unref (priv->call); - } - - priv->call = NULL; - - /* release any references held by the object here */ - if (G_OBJECT_CLASS (empathy_streamed_media_handler_parent_class)->dispose) - G_OBJECT_CLASS (empathy_streamed_media_handler_parent_class)->dispose (object); -} - -static void -empathy_streamed_media_handler_finalize (GObject *object) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (object); - - fs_codec_destroy (priv->send_audio_codec); - fs_codec_destroy (priv->send_video_codec); - fs_codec_list_destroy (priv->recv_audio_codecs); - fs_codec_list_destroy (priv->recv_video_codecs); - fs_candidate_destroy (priv->audio_remote_candidate); - fs_candidate_destroy (priv->video_remote_candidate); - fs_candidate_destroy (priv->audio_local_candidate); - fs_candidate_destroy (priv->video_local_candidate); - - if (G_OBJECT_CLASS (empathy_streamed_media_handler_parent_class)->finalize) - G_OBJECT_CLASS (empathy_streamed_media_handler_parent_class)->finalize (object); -} - -static void -empathy_streamed_media_handler_init (EmpathyStreamedMediaHandler *obj) -{ - EmpathyStreamedMediaHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (obj, - EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, EmpathyStreamedMediaHandlerPriv); - - obj->priv = priv; -} - -static void -empathy_streamed_media_handler_constructed (GObject *object) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (object); - - if (priv->contact == NULL) - { - g_object_get (priv->call, "contact", &(priv->contact), NULL); - } -} - -static void -empathy_streamed_media_handler_set_property (GObject *object, - guint property_id, const GValue *value, GParamSpec *pspec) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (object); - - switch (property_id) - { - case PROP_CONTACT: - priv->contact = g_value_dup_object (value); - break; - case PROP_TP_STREAMED_MEDIA: - priv->call = g_value_dup_object (value); - break; - case PROP_INITIAL_AUDIO: - priv->initial_audio = g_value_get_boolean (value); - break; - case PROP_INITIAL_VIDEO: - priv->initial_video = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -empathy_streamed_media_handler_get_property (GObject *object, - guint property_id, GValue *value, GParamSpec *pspec) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (object); - - switch (property_id) - { - case PROP_CONTACT: - g_value_set_object (value, priv->contact); - break; - case PROP_TP_STREAMED_MEDIA: - g_value_set_object (value, priv->call); - break; - case PROP_INITIAL_AUDIO: - g_value_set_boolean (value, priv->initial_audio); - break; - case PROP_INITIAL_VIDEO: - g_value_set_boolean (value, priv->initial_video); - break; - case PROP_SEND_AUDIO_CODEC: - g_value_set_boxed (value, priv->send_audio_codec); - break; - case PROP_SEND_VIDEO_CODEC: - g_value_set_boxed (value, priv->send_video_codec); - break; - case PROP_RECV_AUDIO_CODECS: - g_value_set_boxed (value, priv->recv_audio_codecs); - break; - case PROP_RECV_VIDEO_CODECS: - g_value_set_boxed (value, priv->recv_video_codecs); - break; - case PROP_AUDIO_REMOTE_CANDIDATE: - g_value_set_boxed (value, priv->audio_remote_candidate); - break; - case PROP_VIDEO_REMOTE_CANDIDATE: - g_value_set_boxed (value, priv->video_remote_candidate); - break; - case PROP_AUDIO_LOCAL_CANDIDATE: - g_value_set_boxed (value, priv->audio_local_candidate); - break; - case PROP_VIDEO_LOCAL_CANDIDATE: - g_value_set_boxed (value, priv->video_local_candidate); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -static void -empathy_streamed_media_handler_class_init (EmpathyStreamedMediaHandlerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - g_type_class_add_private (klass, sizeof (EmpathyStreamedMediaHandlerPriv)); - - object_class->constructed = empathy_streamed_media_handler_constructed; - object_class->set_property = empathy_streamed_media_handler_set_property; - object_class->get_property = empathy_streamed_media_handler_get_property; - object_class->dispose = empathy_streamed_media_handler_dispose; - object_class->finalize = empathy_streamed_media_handler_finalize; - - param_spec = g_param_spec_object ("contact", - "contact", "The remote contact", - EMPATHY_TYPE_CONTACT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONTACT, param_spec); - - param_spec = g_param_spec_object ("tp-call", - "tp-call", "The calls channel wrapper", - EMPATHY_TYPE_TP_STREAMED_MEDIA, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TP_STREAMED_MEDIA, param_spec); - - param_spec = g_param_spec_boolean ("initial-audio", - "initial-audio", "Whether the call should start with audio", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, - param_spec); - - param_spec = g_param_spec_boolean ("initial-video", - "initial-video", "Whether the call should start with video", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - param_spec = g_param_spec_boxed ("send-audio-codec", - "send audio codec", "Codec used to encode the outgoing video stream", - FS_TYPE_CODEC, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SEND_AUDIO_CODEC, - param_spec); - - param_spec = g_param_spec_boxed ("send-video-codec", - "send video codec", "Codec used to encode the outgoing video stream", - FS_TYPE_CODEC, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SEND_VIDEO_CODEC, - param_spec); - - param_spec = g_param_spec_boxed ("recv-audio-codecs", - "recvs audio codec", "Codecs used to decode the incoming audio stream", - FS_TYPE_CODEC_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_RECV_AUDIO_CODECS, - param_spec); - - param_spec = g_param_spec_boxed ("recv-video-codecs", - "recvs video codec", "Codecs used to decode the incoming video stream", - FS_TYPE_CODEC_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_RECV_VIDEO_CODECS, - param_spec); - - param_spec = g_param_spec_boxed ("audio-remote-candidate", - "audio remote candidate", - "Remote candidate used for the audio stream", - FS_TYPE_CANDIDATE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_AUDIO_REMOTE_CANDIDATE, param_spec); - - param_spec = g_param_spec_boxed ("video-remote-candidate", - "video remote candidate", - "Remote candidate used for the video stream", - FS_TYPE_CANDIDATE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_VIDEO_REMOTE_CANDIDATE, param_spec); - - param_spec = g_param_spec_boxed ("audio-local-candidate", - "audio local candidate", - "Local candidate used for the audio stream", - FS_TYPE_CANDIDATE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_AUDIO_REMOTE_CANDIDATE, param_spec); - - param_spec = g_param_spec_boxed ("video-local-candidate", - "video local candidate", - "Local candidate used for the video stream", - FS_TYPE_CANDIDATE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_VIDEO_REMOTE_CANDIDATE, param_spec); - - signals[CONFERENCE_ADDED] = - g_signal_new ("conference-added", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, FS_TYPE_CONFERENCE); - - signals[SRC_PAD_ADDED] = - g_signal_new ("src-pad-added", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_BOOLEAN, - 2, GST_TYPE_PAD, G_TYPE_UINT); - - signals[SINK_PAD_ADDED] = - g_signal_new ("sink-pad-added", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_BOOLEAN, - 2, GST_TYPE_PAD, G_TYPE_UINT); - - signals[REQUEST_RESOURCE] = - g_signal_new ("request-resource", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, - g_signal_accumulator_true_handled, NULL, - g_cclosure_marshal_generic, - G_TYPE_BOOLEAN, 2, G_TYPE_UINT, G_TYPE_UINT); - - signals[CLOSED] = - g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 0); - - signals[STREAM_CLOSED] = - g_signal_new ("stream-closed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 1, TF_TYPE_STREAM); - - signals[CANDIDATES_CHANGED] = - g_signal_new ("candidates-changed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 1, G_TYPE_UINT); -} - -/** - * empathy_streamed_media_handler_new_for_contact: - * @contact: an #EmpathyContact - * - * Creates a new #EmpathyStreamedMediaHandler with contact @contact. - * - * Return value: a new #EmpathyStreamedMediaHandler - */ -EmpathyStreamedMediaHandler * -empathy_streamed_media_handler_new_for_contact (EmpathyContact *contact) -{ - return EMPATHY_STREAMED_MEDIA_HANDLER (g_object_new (EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, - "contact", contact, NULL)); -} - -EmpathyStreamedMediaHandler * -empathy_streamed_media_handler_new_for_channel (EmpathyTpStreamedMedia *call) -{ - return EMPATHY_STREAMED_MEDIA_HANDLER (g_object_new (EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, - "tp-call", call, - "initial-video", empathy_tp_streamed_media_is_receiving_video (call), - NULL)); -} - -static void -update_sending_codec (EmpathyStreamedMediaHandler *self, - FsCodec *codec, - FsSession *session) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - FsMediaType type; - - if (codec == NULL || session == NULL) - return; - - g_object_get (session, "media-type", &type, NULL); - - if (type == FS_MEDIA_TYPE_AUDIO) - { - priv->send_audio_codec = fs_codec_copy (codec); - g_object_notify (G_OBJECT (self), "send-audio-codec"); - } - else if (type == FS_MEDIA_TYPE_VIDEO) - { - priv->send_video_codec = fs_codec_copy (codec); - g_object_notify (G_OBJECT (self), "send-video-codec"); - } -} - -static void -update_receiving_codec (EmpathyStreamedMediaHandler *self, - GList *codecs, - FsStream *stream) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - FsSession *session; - FsMediaType type; - - if (codecs == NULL || stream == NULL) - return; - - g_object_get (stream, "session", &session, NULL); - if (session == NULL) - return; - - g_object_get (session, "media-type", &type, NULL); - - if (type == FS_MEDIA_TYPE_AUDIO) - { - priv->recv_audio_codecs = fs_codec_list_copy (codecs); - g_object_notify (G_OBJECT (self), "recv-audio-codecs"); - } - else if (type == FS_MEDIA_TYPE_VIDEO) - { - priv->recv_video_codecs = fs_codec_list_copy (codecs); - g_object_notify (G_OBJECT (self), "recv-video-codecs"); - } - - g_object_unref (session); -} - -static void -update_candidates (EmpathyStreamedMediaHandler *self, - FsCandidate *remote_candidate, - FsCandidate *local_candidate, - FsStream *stream) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - FsSession *session; - FsMediaType type; - - if (stream == NULL) - return; - - g_object_get (stream, "session", &session, NULL); - if (session == NULL) - return; - - g_object_get (session, "media-type", &type, NULL); - - if (type == FS_MEDIA_TYPE_AUDIO) - { - if (remote_candidate != NULL) - { - fs_candidate_destroy (priv->audio_remote_candidate); - priv->audio_remote_candidate = fs_candidate_copy (remote_candidate); - g_object_notify (G_OBJECT (self), "audio-remote-candidate"); - } - - if (local_candidate != NULL) - { - fs_candidate_destroy (priv->audio_local_candidate); - priv->audio_local_candidate = fs_candidate_copy (local_candidate); - g_object_notify (G_OBJECT (self), "audio-local-candidate"); - } - - g_signal_emit (G_OBJECT (self), signals[CANDIDATES_CHANGED], 0, - FS_MEDIA_TYPE_AUDIO); - } - else if (type == FS_MEDIA_TYPE_VIDEO) - { - if (remote_candidate != NULL) - { - fs_candidate_destroy (priv->video_remote_candidate); - priv->video_remote_candidate = fs_candidate_copy (remote_candidate); - g_object_notify (G_OBJECT (self), "video-remote-candidate"); - } - - if (local_candidate != NULL) - { - fs_candidate_destroy (priv->video_local_candidate); - priv->video_local_candidate = fs_candidate_copy (local_candidate); - g_object_notify (G_OBJECT (self), "video-local-candidate"); - } - - g_signal_emit (G_OBJECT (self), signals[CANDIDATES_CHANGED], 0, - FS_MEDIA_TYPE_VIDEO); - } - - g_object_unref (session); -} - -void -empathy_streamed_media_handler_bus_message (EmpathyStreamedMediaHandler *handler, - GstBus *bus, GstMessage *message) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (handler); - const GstStructure *s = gst_message_get_structure (message); - - if (priv->tfchannel == NULL) - return; - - if (s != NULL && - gst_structure_has_name (s, "farsight-send-codec-changed")) - { - const GValue *val; - FsCodec *codec; - FsSession *session; - - val = gst_structure_get_value (s, "codec"); - codec = g_value_get_boxed (val); - - val = gst_structure_get_value (s, "session"); - session = g_value_get_object (val); - - update_sending_codec (handler, codec, session); - } - else if (s != NULL && - gst_structure_has_name (s, "farsight-recv-codecs-changed")) - { - const GValue *val; - GList *codecs; - FsStream *stream; - - val = gst_structure_get_value (s, "codecs"); - codecs = g_value_get_boxed (val); - - val = gst_structure_get_value (s, "stream"); - stream = g_value_get_object (val); - - update_receiving_codec (handler, codecs, stream); - } - else if (s != NULL && - gst_structure_has_name (s, "farsight-new-active-candidate-pair")) - { - const GValue *val; - FsCandidate *remote_candidate, *local_candidate; - FsStream *stream; - - val = gst_structure_get_value (s, "remote-candidate"); - remote_candidate = g_value_get_boxed (val); - - val = gst_structure_get_value (s, "local-candidate"); - local_candidate = g_value_get_boxed (val); - - val = gst_structure_get_value (s, "stream"); - stream = g_value_get_object (val); - - update_candidates (handler, remote_candidate, local_candidate, stream); - } - - tf_channel_bus_message (priv->tfchannel, message); -} - -static void -empathy_streamed_media_handler_tf_channel_session_created_cb (TfChannel *tfchannel, - FsConference *conference, FsParticipant *participant, - EmpathyStreamedMediaHandler *self) -{ - g_signal_emit (G_OBJECT (self), signals[CONFERENCE_ADDED], 0, - GST_ELEMENT (conference)); -} - -static gboolean -src_pad_added_error_idle (gpointer data) -{ - TfStream *stream = data; - - tf_stream_error (stream, TP_MEDIA_STREAM_ERROR_MEDIA_ERROR, - "Could not link sink"); - g_object_unref (stream); - - return FALSE; -} - -static void -empathy_streamed_media_handler_tf_stream_src_pad_added_cb (TfStream *stream, - GstPad *pad, FsCodec *codec, EmpathyStreamedMediaHandler *handler) -{ - guint media_type; - gboolean retval; - - g_object_get (stream, "media-type", &media_type, NULL); - - g_signal_emit (G_OBJECT (handler), signals[SRC_PAD_ADDED], 0, - pad, media_type, &retval); - - if (!retval) - g_idle_add (src_pad_added_error_idle, g_object_ref (stream)); -} - - -static gboolean -empathy_streamed_media_handler_tf_stream_request_resource_cb (TfStream *stream, - guint direction, EmpathyTpStreamedMedia *call) -{ - gboolean ret; - guint media_type; - - g_object_get (G_OBJECT (stream), "media-type", &media_type, NULL); - - g_signal_emit (G_OBJECT (call), - signals[REQUEST_RESOURCE], 0, media_type, direction, &ret); - - return ret; -} - -static void -empathy_streamed_media_handler_tf_stream_closed_cb (TfStream *stream, - EmpathyStreamedMediaHandler *handler) -{ - g_signal_emit (handler, signals[STREAM_CLOSED], 0, stream); -} - -static void -empathy_streamed_media_handler_tf_channel_stream_created_cb (TfChannel *tfchannel, - TfStream *stream, EmpathyStreamedMediaHandler *handler) -{ - guint media_type; - GstPad *spad; - gboolean retval; - FsStream *fs_stream; - GList *codecs; - FsSession *session; - FsCodec *codec; - - g_signal_connect (stream, "src-pad-added", - G_CALLBACK (empathy_streamed_media_handler_tf_stream_src_pad_added_cb), handler); - g_signal_connect (stream, "request-resource", - G_CALLBACK (empathy_streamed_media_handler_tf_stream_request_resource_cb), - handler); - g_signal_connect (stream, "closed", - G_CALLBACK (empathy_streamed_media_handler_tf_stream_closed_cb), handler); - - g_object_get (stream, "media-type", &media_type, - "sink-pad", &spad, NULL); - - g_signal_emit (G_OBJECT (handler), signals[SINK_PAD_ADDED], 0, - spad, media_type, &retval); - - if (!retval) - tf_stream_error (stream, TP_MEDIA_STREAM_ERROR_MEDIA_ERROR, - "Could not link source"); - - /* Get sending codec */ - g_object_get (stream, "farsight-session", &session, NULL); - g_object_get (session, "current-send-codec", &codec, NULL); - - update_sending_codec (handler, codec, session); - - tp_clear_object (&session); - tp_clear_object (&codec); - - /* Get receiving codec */ - g_object_get (stream, "farsight-stream", &fs_stream, NULL); - g_object_get (fs_stream, "current-recv-codecs", &codecs, NULL); - - update_receiving_codec (handler, codecs, fs_stream); - - fs_codec_list_destroy (codecs); - tp_clear_object (&fs_stream); - - gst_object_unref (spad); -} - -static void -empathy_streamed_media_handler_tf_channel_closed_cb (TfChannel *tfchannel, - EmpathyStreamedMediaHandler *handler) -{ - g_signal_emit (G_OBJECT (handler), signals[CLOSED], 0); -} - -static void -empathy_streamed_media_handler_start_tpfs (EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - TpChannel *channel; - - g_object_get (priv->call, "channel", &channel, NULL); - - g_assert (channel != NULL); - - priv->tfchannel = tf_channel_new (channel); - - /* Set up the telepathy farsight channel */ - g_signal_connect (priv->tfchannel, "session-created", - G_CALLBACK (empathy_streamed_media_handler_tf_channel_session_created_cb), self); - g_signal_connect (priv->tfchannel, "stream-created", - G_CALLBACK (empathy_streamed_media_handler_tf_channel_stream_created_cb), self); - g_signal_connect (priv->tfchannel, "closed", - G_CALLBACK (empathy_streamed_media_handler_tf_channel_closed_cb), self); - - g_object_unref (channel); -} - -static void -empathy_streamed_media_handler_request_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - EmpathyStreamedMediaHandler *self = EMPATHY_STREAMED_MEDIA_HANDLER (user_data); - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - TpChannel *channel; - GError *error = NULL; - TpAccountChannelRequest *req = TP_ACCOUNT_CHANNEL_REQUEST (source); - TpAccount *account; - - channel = tp_account_channel_request_create_and_handle_channel_finish (req, - result, NULL, &error); - if (channel == NULL) - { - DEBUG ("Failed to create the channel: %s", error->message); - g_error_free (error); - return; - } - - account = tp_account_channel_request_get_account (req); - - priv->call = empathy_tp_streamed_media_new (account, channel); - - g_object_notify (G_OBJECT (self), "tp-call"); - - empathy_streamed_media_handler_start_tpfs (self); - - g_object_unref (channel); -} - -void -empathy_streamed_media_handler_start_call (EmpathyStreamedMediaHandler *handler, - gint64 timestamp) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (handler); - TpAccountChannelRequest *req; - TpAccount *account; - GHashTable *request; - - if (priv->call != NULL) - { - empathy_streamed_media_handler_start_tpfs (handler); - empathy_tp_streamed_media_accept_incoming_call (priv->call); - return; - } - - /* No TpStreamedMedia object (we are redialing). Request a new media channel that - * will be used to create a new EmpathyTpStreamedMedia. */ - g_assert (priv->contact != NULL); - - account = empathy_contact_get_account (priv->contact); - request = empathy_call_create_streamed_media_request ( - empathy_contact_get_id (priv->contact), - priv->initial_audio, priv->initial_video); - - req = tp_account_channel_request_new (account, request, timestamp); - - tp_account_channel_request_create_and_handle_channel_async (req, NULL, - empathy_streamed_media_handler_request_cb, handler); - - g_object_unref (req); - g_hash_table_unref (request); -} - -/** - * empathy_streamed_media_handler_stop_call: - * @handler: an #EmpathyStreamedMediaHandler - * - * Closes the #EmpathyStreamedMediaHandler's call and frees its resources. - */ -void -empathy_streamed_media_handler_stop_call (EmpathyStreamedMediaHandler *handler) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (handler); - - if (priv->call != NULL) - { - empathy_tp_streamed_media_leave (priv->call); - g_object_unref (priv->call); - } - - priv->call = NULL; -} - -/** - * empathy_streamed_media_handler_has_initial_video: - * @handler: an #EmpathyStreamedMediaHandler - * - * Return %TRUE if the call managed by this #EmpathyStreamedMediaHandler was - * created with video enabled - * - * Return value: %TRUE if the call was created as a video conversation. - */ -gboolean -empathy_streamed_media_handler_has_initial_video (EmpathyStreamedMediaHandler *handler) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (handler); - - return priv->initial_video; -} - -FsCodec * -empathy_streamed_media_handler_get_send_audio_codec (EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->send_audio_codec; -} - -FsCodec * -empathy_streamed_media_handler_get_send_video_codec (EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->send_video_codec; -} - -GList * -empathy_streamed_media_handler_get_recv_audio_codecs (EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->recv_audio_codecs; -} - -GList * -empathy_streamed_media_handler_get_recv_video_codecs (EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->recv_video_codecs; -} - -FsCandidate * -empathy_streamed_media_handler_get_audio_remote_candidate ( - EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->audio_remote_candidate; -} - -FsCandidate * -empathy_streamed_media_handler_get_audio_local_candidate ( - EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->audio_local_candidate; -} - -FsCandidate * -empathy_streamed_media_handler_get_video_remote_candidate ( - EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->video_remote_candidate; -} - -FsCandidate * -empathy_streamed_media_handler_get_video_local_candidate ( - EmpathyStreamedMediaHandler *self) -{ - EmpathyStreamedMediaHandlerPriv *priv = GET_PRIV (self); - - return priv->video_local_candidate; -} diff --git a/src/empathy-streamed-media-handler.h b/src/empathy-streamed-media-handler.h deleted file mode 100644 index ab655b8e4..000000000 --- a/src/empathy-streamed-media-handler.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * empathy-streamed-media-handler.h - Header for EmpathyStreamedMediaHandler - * Copyright (C) 2008-2009 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __EMPATHY_STREAMED_MEDIA_HANDLER_H__ -#define __EMPATHY_STREAMED_MEDIA_HANDLER_H__ - -#include <glib-object.h> - -#include <gst/gst.h> -#include <gst/farsight/fs-conference-iface.h> - -#include <libempathy/empathy-tp-streamed-media.h> -#include <libempathy/empathy-contact.h> - -G_BEGIN_DECLS - -typedef struct _EmpathyStreamedMediaHandler EmpathyStreamedMediaHandler; -typedef struct _EmpathyStreamedMediaHandlerClass EmpathyStreamedMediaHandlerClass; - -struct _EmpathyStreamedMediaHandlerClass { - GObjectClass parent_class; -}; - -struct _EmpathyStreamedMediaHandler { - GObject parent; - gpointer priv; -}; - -GType empathy_streamed_media_handler_get_type (void); - -/* TYPE MACROS */ -#define EMPATHY_TYPE_STREAMED_MEDIA_HANDLER \ - (empathy_streamed_media_handler_get_type ()) -#define EMPATHY_STREAMED_MEDIA_HANDLER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, \ - EmpathyStreamedMediaHandler)) -#define EMPATHY_STREAMED_MEDIA_HANDLER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, \ - EmpathyStreamedMediaHandlerClass)) -#define EMPATHY_IS_STREAMED_MEDIA_HANDLER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_STREAMED_MEDIA_HANDLER)) -#define EMPATHY_IS_STREAMED_MEDIA_HANDLER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_STREAMED_MEDIA_HANDLER)) -#define EMPATHY_STREAMED_MEDIA_HANDLER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, \ - EmpathyStreamedMediaHandlerClass)) - -EmpathyStreamedMediaHandler * empathy_streamed_media_handler_new_for_contact ( - EmpathyContact *contact); - -EmpathyStreamedMediaHandler * empathy_streamed_media_handler_new_for_channel ( - EmpathyTpStreamedMedia *call); - -void empathy_streamed_media_handler_start_call (EmpathyStreamedMediaHandler *handler, - gint64 timestamp); -void empathy_streamed_media_handler_stop_call (EmpathyStreamedMediaHandler *handler); - -gboolean empathy_streamed_media_handler_has_initial_video (EmpathyStreamedMediaHandler *handler); - -void empathy_streamed_media_handler_bus_message (EmpathyStreamedMediaHandler *handler, - GstBus *bus, GstMessage *message); - -FsCodec * empathy_streamed_media_handler_get_send_audio_codec ( - EmpathyStreamedMediaHandler *self); - -FsCodec * empathy_streamed_media_handler_get_send_video_codec ( - EmpathyStreamedMediaHandler *self); - -GList * empathy_streamed_media_handler_get_recv_audio_codecs ( - EmpathyStreamedMediaHandler *self); - -GList * empathy_streamed_media_handler_get_recv_video_codecs ( - EmpathyStreamedMediaHandler *self); - -FsCandidate * empathy_streamed_media_handler_get_audio_remote_candidate ( - EmpathyStreamedMediaHandler *self); - -FsCandidate * empathy_streamed_media_handler_get_audio_local_candidate ( - EmpathyStreamedMediaHandler *self); - -FsCandidate * empathy_streamed_media_handler_get_video_remote_candidate ( - EmpathyStreamedMediaHandler *self); - -FsCandidate * empathy_streamed_media_handler_get_video_local_candidate ( - EmpathyStreamedMediaHandler *self); - -G_END_DECLS - -#endif /* #ifndef __EMPATHY_STREAMED_MEDIA_HANDLER_H__*/ diff --git a/src/empathy-streamed-media-window-fullscreen.c b/src/empathy-streamed-media-window-fullscreen.c deleted file mode 100644 index caa34ffd1..000000000 --- a/src/empathy-streamed-media-window-fullscreen.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * empathy-streamed-media-window-fullscreen.c - Source for EmpathyStreamedMediaWindowFullscreen - * Copyright (C) 2009 Collabora Ltd. - * - * Some code is based on the Totem Movie Player, especially - * totem-fullscreen.c which has the following copyright: - * Copyright (C) 2001-2007 Bastien Nocera <hadess@hadess.net> - * Copyright (C) 2007 Sunil Mohan Adapa <sunilmohan@gnu.org.in> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "empathy-streamed-media-window-fullscreen.h" - -#include <gtk/gtk.h> - -#include <libempathy/empathy-utils.h> -#include <libempathy-gtk/empathy-ui-utils.h> - -/* The number of seconds for which the "leave fullscreen" popup should - be shown */ -#define FULLSCREEN_POPUP_TIMEOUT 5 - -G_DEFINE_TYPE (EmpathyStreamedMediaWindowFullscreen, empathy_streamed_media_window_fullscreen, - G_TYPE_OBJECT) - -/* private structure */ -typedef struct _EmpathyStreamedMediaWindowFullscreenPriv - EmpathyStreamedMediaWindowFullscreenPriv; - -struct _EmpathyStreamedMediaWindowFullscreenPriv -{ - EmpathyStreamedMediaWindow *parent_window; - - GtkWidget *leave_fullscreen_popup; - GtkWidget *video_widget; - - guint popup_timeout; - gboolean popup_creation_in_progress; - gboolean dispose_has_run; -}; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN, \ - EmpathyStreamedMediaWindowFullscreenPriv)) - -static void empathy_streamed_media_window_fullscreen_dispose (GObject *object); -static void empathy_streamed_media_window_fullscreen_finalize (GObject *object); - -static gboolean empathy_streamed_media_window_fullscreen_hide_popup ( - EmpathyStreamedMediaWindowFullscreen *fs); - -static void -empathy_streamed_media_window_fullscreen_set_cursor_visible ( - EmpathyStreamedMediaWindowFullscreen *fs, - gboolean show_cursor) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (fs); - GdkWindow *window; - - if (priv->video_widget == NULL) - return; - - window = gtk_widget_get_window (priv->video_widget); - - if (!show_cursor) - gdk_window_set_cursor (window, gdk_cursor_new (GDK_BLANK_CURSOR)); - else - gdk_window_set_cursor (window, NULL); -} - -static void -empathy_streamed_media_window_fullscreen_add_popup_timeout ( - EmpathyStreamedMediaWindowFullscreen *self) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - if (priv->popup_timeout == 0) - { - priv->popup_timeout = g_timeout_add_seconds (FULLSCREEN_POPUP_TIMEOUT, - (GSourceFunc) empathy_streamed_media_window_fullscreen_hide_popup, self); - } -} - -static void -empathy_streamed_media_window_fullscreen_remove_popup_timeout ( - EmpathyStreamedMediaWindowFullscreen *self) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - if (priv->popup_timeout != 0) - { - g_source_remove (priv->popup_timeout); - priv->popup_timeout = 0; - } -} - -void -empathy_streamed_media_window_fullscreen_show_popup (EmpathyStreamedMediaWindowFullscreen *self) -{ - gint leave_fullscreen_width, leave_fullscreen_height; - GdkScreen *screen; - GdkRectangle fullscreen_rect; - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - g_assert (self->is_fullscreen); - - g_return_if_fail (priv->parent_window != NULL); - - if (priv->popup_creation_in_progress) - return; - - if (!gtk_window_is_active (GTK_WINDOW (priv->parent_window))) - return; - - priv->popup_creation_in_progress = TRUE; - - empathy_streamed_media_window_fullscreen_set_cursor_visible (self, TRUE); - - /* Obtaining the screen rectangle */ - screen = gtk_window_get_screen (GTK_WINDOW (priv->parent_window)); - gdk_screen_get_monitor_geometry (screen, - gdk_screen_get_monitor_at_window (screen, - gtk_widget_get_window (GTK_WIDGET (priv->parent_window))), - &fullscreen_rect); - - /* Getting the popup window sizes */ - gtk_window_get_size (GTK_WINDOW (priv->leave_fullscreen_popup), - &leave_fullscreen_width, &leave_fullscreen_height); - - /* Moving the popup to the top-right corner (if the direction is LTR) or the - top-left corner (if the direction is RTL).*/ - if (gtk_widget_get_direction (priv->leave_fullscreen_popup) - == GTK_TEXT_DIR_LTR) - { - gtk_window_move (GTK_WINDOW (priv->leave_fullscreen_popup), - fullscreen_rect.width + fullscreen_rect.x - leave_fullscreen_width, - fullscreen_rect.y); - - } - else - { - gtk_window_move (GTK_WINDOW (priv->leave_fullscreen_popup), - fullscreen_rect.x, fullscreen_rect.y); - } - - gtk_widget_show_all (priv->leave_fullscreen_popup); - empathy_streamed_media_window_fullscreen_add_popup_timeout (self); - - priv->popup_creation_in_progress = FALSE; -} - -static gboolean -empathy_streamed_media_window_fullscreen_hide_popup (EmpathyStreamedMediaWindowFullscreen *fs) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (fs); - - if (priv->video_widget == NULL || !fs->is_fullscreen) - return TRUE; - - gtk_widget_hide (priv->leave_fullscreen_popup); - empathy_streamed_media_window_fullscreen_remove_popup_timeout (fs); - - empathy_streamed_media_window_fullscreen_set_cursor_visible (fs, FALSE); - - return FALSE; -} - -static void -empathy_streamed_media_window_fullscreen_init (EmpathyStreamedMediaWindowFullscreen *self) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - GtkBuilder *gui; - gchar *filename; - - filename = empathy_file_lookup ("empathy-call-window-fullscreen.ui", "src"); - gui = empathy_builder_get_file (filename, - "leave_fullscreen_window", &priv->leave_fullscreen_popup, - "leave_fullscreen_button", &self->leave_fullscreen_button, - NULL); - - gtk_widget_add_events (priv->leave_fullscreen_popup, GDK_POINTER_MOTION_MASK); - - g_object_unref (gui); - g_free (filename); -} - -static void -empathy_streamed_media_window_fullscreen_class_init ( - EmpathyStreamedMediaWindowFullscreenClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (EmpathyStreamedMediaWindowFullscreenPriv)); - - object_class->dispose = empathy_streamed_media_window_fullscreen_dispose; - object_class->finalize = empathy_streamed_media_window_fullscreen_finalize; -} - -void -empathy_streamed_media_window_fullscreen_dispose (GObject *object) -{ - EmpathyStreamedMediaWindowFullscreen *self = EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN (object); - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - if (priv->leave_fullscreen_popup != NULL) - gtk_widget_destroy (priv->leave_fullscreen_popup); - priv->leave_fullscreen_popup = NULL; - - if (G_OBJECT_CLASS (empathy_streamed_media_window_fullscreen_parent_class)->dispose) - { - G_OBJECT_CLASS ( - empathy_streamed_media_window_fullscreen_parent_class)->dispose (object); - } -} - -void -empathy_streamed_media_window_fullscreen_finalize (GObject *object) -{ - EmpathyStreamedMediaWindowFullscreen *self = EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN (object); - - empathy_streamed_media_window_fullscreen_remove_popup_timeout (self); - - G_OBJECT_CLASS ( - empathy_streamed_media_window_fullscreen_parent_class)->finalize (object); -} - -static void -empathy_streamed_media_window_fullscreen_parent_window_notify (GtkWidget *parent_window, - GParamSpec *property, EmpathyStreamedMediaWindowFullscreen *fs) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (fs); - - if (!fs->is_fullscreen) - return; - - if (parent_window == GTK_WIDGET (priv->parent_window) && - !gtk_window_is_active (GTK_WINDOW (parent_window))) - { - empathy_streamed_media_window_fullscreen_hide_popup (fs); - empathy_streamed_media_window_fullscreen_set_cursor_visible (fs, TRUE); - } -} - -EmpathyStreamedMediaWindowFullscreen * -empathy_streamed_media_window_fullscreen_new (EmpathyStreamedMediaWindow *parent_window) -{ - EmpathyStreamedMediaWindowFullscreen *self = EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN ( - g_object_new (EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN, NULL)); - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - priv->parent_window = parent_window; - g_signal_connect (G_OBJECT (priv->parent_window), "notify::is-active", - G_CALLBACK (empathy_streamed_media_window_fullscreen_parent_window_notify), self); - - return self; -} - -void -empathy_streamed_media_window_fullscreen_set_fullscreen (EmpathyStreamedMediaWindowFullscreen *fs, - gboolean set_fullscreen) -{ - - if (set_fullscreen) - empathy_streamed_media_window_fullscreen_remove_popup_timeout (fs); - else - empathy_streamed_media_window_fullscreen_hide_popup (fs); - - empathy_streamed_media_window_fullscreen_set_cursor_visible (fs, !set_fullscreen); - fs->is_fullscreen = set_fullscreen; -} - -static void -video_widget_destroy_cb (GtkWidget *widget, - EmpathyStreamedMediaWindowFullscreen *self) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (self); - - priv->video_widget = NULL; -} - -void -empathy_streamed_media_window_fullscreen_set_video_widget ( - EmpathyStreamedMediaWindowFullscreen *fs, - GtkWidget *video_widget) -{ - EmpathyStreamedMediaWindowFullscreenPriv *priv = GET_PRIV (fs); - priv->video_widget = video_widget; - - tp_g_signal_connect_object (video_widget, "destroy", - G_CALLBACK (video_widget_destroy_cb), fs, 0); -} diff --git a/src/empathy-streamed-media-window-fullscreen.h b/src/empathy-streamed-media-window-fullscreen.h deleted file mode 100644 index bdb95fb0b..000000000 --- a/src/empathy-streamed-media-window-fullscreen.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * empathy-streamed-media-window-fullscreen.h - Header for EmpathyStreamedMediaWindowFullscreen - * Copyright (C) 2009 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN_H__ -#define __EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "empathy-streamed-media-window.h" - -G_BEGIN_DECLS - -typedef struct _EmpathyStreamedMediaWindowFullscreen EmpathyStreamedMediaWindowFullscreen; -typedef struct _EmpathyStreamedMediaWindowFullscreenClass - EmpathyStreamedMediaWindowFullscreenClass; - -struct _EmpathyStreamedMediaWindowFullscreenClass { - GObjectClass parent_class; -}; - -struct _EmpathyStreamedMediaWindowFullscreen { - GObject parent; - gboolean is_fullscreen; - GtkWidget *leave_fullscreen_button; -}; - -GType empathy_streamed_media_window_fullscreen_get_type (void); - -/* TYPE MACROS */ -#define EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN \ - (empathy_streamed_media_window_fullscreen_get_type ()) -#define EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN, \ - EmpathyStreamedMediaWindowFullscreen)) -#define EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN, \ - EmpathyStreamedMediaWindowClassFullscreen)) -#define EMPATHY_IS_STREAMED_MEDIA_WINDOW_FULLSCREEN(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN)) -#define EMPATHY_IS_STREAMED_MEDIA_WINDOW_FULLSCREEN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN)) -#define EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW_FULLSCREEN, \ - EmpathyStreamedMediaWindowFullscreenClass)) - -EmpathyStreamedMediaWindowFullscreen *empathy_streamed_media_window_fullscreen_new ( - EmpathyStreamedMediaWindow *parent); - -void empathy_streamed_media_window_fullscreen_set_fullscreen ( - EmpathyStreamedMediaWindowFullscreen *fs, - gboolean set_fullscreen); -void empathy_streamed_media_window_fullscreen_set_video_widget ( - EmpathyStreamedMediaWindowFullscreen *fs, - GtkWidget *video_widget); -void empathy_streamed_media_window_fullscreen_show_popup ( - EmpathyStreamedMediaWindowFullscreen *fs); - -G_END_DECLS - -#endif /* #ifndef __EMPATHY_STREAMED_MEDIA_WINDOW_FULLSCREEN_H__*/ diff --git a/src/empathy-streamed-media-window.c b/src/empathy-streamed-media-window.c deleted file mode 100644 index df3fbab00..000000000 --- a/src/empathy-streamed-media-window.c +++ /dev/null @@ -1,3202 +0,0 @@ -/* - * empathy-streamed-media-window.c - Source for EmpathyStreamedMediaWindow - * Copyright (C) 2008-2009 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> - -#include <math.h> - -#include <gdk/gdkkeysyms.h> -#include <gst/gst.h> -#include <gtk/gtk.h> -#include <glib/gi18n.h> - -#include <telepathy-glib/util.h> -#include <telepathy-farsight/channel.h> -#include <telepathy-glib/util.h> - -#include <gst/farsight/fs-element-added-notifier.h> -#include <gst/farsight/fs-utils.h> - -#include <libempathy/empathy-tp-contact-factory.h> -#include <libempathy/empathy-utils.h> -#include <libempathy-gtk/empathy-avatar-image.h> -#include <libempathy-gtk/empathy-dialpad-widget.h> -#include <libempathy-gtk/empathy-ui-utils.h> -#include <libempathy-gtk/empathy-sound-manager.h> -#include <libempathy-gtk/empathy-geometry.h> -#include <libempathy-gtk/empathy-images.h> - -#define DEBUG_FLAG EMPATHY_DEBUG_VOIP -#include <libempathy/empathy-debug.h> - -#include "empathy-streamed-media-window.h" -#include "empathy-streamed-media-window-fullscreen.h" -#include "empathy-video-widget.h" -#include "empathy-audio-src.h" -#include "empathy-audio-sink.h" -#include "empathy-video-src.h" -#include "ev-sidebar.h" - -#define CONTENT_HBOX_BORDER_WIDTH 6 -#define CONTENT_HBOX_SPACING 3 -#define CONTENT_HBOX_CHILDREN_PACKING_PADDING 3 - -#define SELF_VIDEO_SECTION_WIDTH 160 -#define SELF_VIDEO_SECTION_HEIGTH 120 - -/* The avatar's default width and height are set to the same value because we - want a square icon. */ -#define REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT -#define REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT \ - EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT - -/* If an video input error occurs, the error message will start with "v4l" */ -#define VIDEO_INPUT_ERROR_PREFIX "v4l" - -/* The time interval in milliseconds between 2 outgoing rings */ -#define MS_BETWEEN_RING 500 - -G_DEFINE_TYPE(EmpathyStreamedMediaWindow, empathy_streamed_media_window, GTK_TYPE_WINDOW) - -/* signal enum */ -#if 0 -enum -{ - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; -#endif - -enum { - PROP_STREAMED_MEDIA_HANDLER = 1, -}; - -typedef enum { - CONNECTING, - CONNECTED, - DISCONNECTED, - REDIALING -} CallState; - -typedef enum { - CAMERA_STATE_OFF = 0, - CAMERA_STATE_PREVIEW, - CAMERA_STATE_ON, -} CameraState; - -/* private structure */ -typedef struct _EmpathyStreamedMediaWindowPriv EmpathyStreamedMediaWindowPriv; - -struct _EmpathyStreamedMediaWindowPriv -{ - gboolean dispose_has_run; - EmpathyStreamedMediaHandler *handler; - EmpathyContact *contact; - - guint call_state; - gboolean outgoing; - - GtkUIManager *ui_manager; - GtkWidget *errors_vbox; - /* widget displays the video received from the remote user. This widget is - * alive only during call. */ - GtkWidget *video_output; - GtkWidget *video_preview; - GtkWidget *remote_user_avatar_widget; - GtkWidget *self_user_avatar_widget; - GtkWidget *sidebar; - GtkWidget *sidebar_button; - GtkWidget *statusbar; - GtkWidget *volume_button; - GtkWidget *redial_button; - GtkWidget *mic_button; - GtkWidget *toolbar; - GtkWidget *pane; - GtkAction *redial; - GtkAction *menu_fullscreen; - GtkAction *action_camera_on; - GtkWidget *tool_button_camera_off; - GtkWidget *tool_button_camera_preview; - GtkWidget *tool_button_camera_on; - - /* The frames and boxes that contain self and remote avatar and video - input/output. When we redial, we destroy and re-create the boxes */ - GtkWidget *remote_user_output_frame; - GtkWidget *self_user_output_frame; - GtkWidget *remote_user_output_hbox; - GtkWidget *self_user_output_hbox; - - /* We keep a reference on the hbox which contains the main content so we can - easilly repack everything when toggling fullscreen */ - GtkWidget *content_hbox; - - /* This vbox is contained in the content_hbox and it contains the - self_user_output_frame and the sidebar button. When toggling fullscreen, - it needs to be repacked. We keep a reference on it for easier access. */ - GtkWidget *vbox; - - gulong video_output_motion_handler_id; - guint bus_message_source_id; - - gdouble volume; - GtkWidget *volume_scale; - GtkWidget *volume_progress_bar; - GtkAdjustment *audio_input_adj; - - GtkWidget *dtmf_panel; - - /* Details vbox */ - GtkWidget *details_vbox; - GtkWidget *vcodec_encoding_label; - GtkWidget *acodec_encoding_label; - GtkWidget *vcodec_decoding_label; - GtkWidget *acodec_decoding_label; - - GtkWidget *audio_remote_candidate_label; - GtkWidget *audio_local_candidate_label; - GtkWidget *video_remote_candidate_label; - GtkWidget *video_local_candidate_label; - GtkWidget *video_remote_candidate_info_img; - GtkWidget *video_local_candidate_info_img; - GtkWidget *audio_remote_candidate_info_img; - GtkWidget *audio_local_candidate_info_img; - - GstElement *video_input; - GstElement *audio_input; - GstElement *audio_output; - GstElement *pipeline; - GstElement *video_tee; - - GstElement *funnel; - - FsElementAddedNotifier *fsnotifier; - - guint context_id; - - GTimer *timer; - guint timer_id; - - GtkWidget *video_contrast; - GtkWidget *video_brightness; - GtkWidget *video_gamma; - - GMutex *lock; - gboolean call_started; - gboolean sending_video; - CameraState camera_state; - - EmpathyStreamedMediaWindowFullscreen *fullscreen; - gboolean is_fullscreen; - - /* Those fields represent the state of the window before it actually was in - fullscreen mode. */ - gboolean sidebar_was_visible_before_fs; - gint original_width_before_fs; - gint original_height_before_fs; - - /* TRUE if the call should be started when the pipeline is playing */ - gboolean start_call_when_playing; - /* TRUE if we requested to set the pipeline in the playing state */ - gboolean pipeline_playing; - - EmpathySoundManager *sound_mgr; -}; - -#define GET_PRIV(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW, \ - EmpathyStreamedMediaWindowPriv)) - -static void empathy_streamed_media_window_realized_cb (GtkWidget *widget, - EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_delete_cb (GtkWidget *widget, - GdkEvent *event, EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_state_event_cb (GtkWidget *widget, - GdkEventWindowState *event, EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_sidebar_toggled_cb (GtkToggleButton *toggle, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_set_send_video (EmpathyStreamedMediaWindow *window, - CameraState state); - -static void empathy_streamed_media_window_mic_toggled_cb ( - GtkToggleToolButton *toggle, EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_sidebar_hidden_cb (EvSidebar *sidebar, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_sidebar_shown_cb (EvSidebar *sidebar, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_hangup_cb (gpointer object, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_fullscreen_cb (gpointer object, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_fullscreen_toggle (EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_video_button_press_cb ( - GtkWidget *video_output, GdkEventButton *event, EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_key_press_cb (GtkWidget *video_output, - GdkEventKey *event, EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_video_output_motion_notify ( - GtkWidget *widget, GdkEventMotion *event, EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_video_menu_popup (EmpathyStreamedMediaWindow *window, - guint button); - -static void empathy_streamed_media_window_redial_cb (gpointer object, - EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_restart_call (EmpathyStreamedMediaWindow *window); - -static void empathy_streamed_media_window_status_message (EmpathyStreamedMediaWindow *window, - gchar *message); - -static void empathy_streamed_media_window_update_avatars_visibility (EmpathyTpStreamedMedia *call, - EmpathyStreamedMediaWindow *window); - -static gboolean empathy_streamed_media_window_bus_message (GstBus *bus, - GstMessage *message, gpointer user_data); - -static void -empathy_streamed_media_window_volume_changed_cb (GtkScaleButton *button, - gdouble value, EmpathyStreamedMediaWindow *window); - -static void block_camera_control_signals (EmpathyStreamedMediaWindow *self); -static void unblock_camera_control_signals (EmpathyStreamedMediaWindow *self); - -static void -empathy_streamed_media_window_setup_toolbar (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GtkToolItem *tool_item; - GtkWidget *camera_off_icon; - GdkPixbuf *pixbuf, *modded_pixbuf; - - /* set the icon of the 'camera off' button by greying off the webcam icon */ - pixbuf = empathy_pixbuf_from_icon_name ("camera-web", - GTK_ICON_SIZE_SMALL_TOOLBAR); - - modded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - - gdk_pixbuf_saturate_and_pixelate (pixbuf, modded_pixbuf, 1.0, TRUE); - g_object_unref (pixbuf); - - camera_off_icon = gtk_image_new_from_pixbuf (modded_pixbuf); - g_object_unref (modded_pixbuf); - gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON ( - priv->tool_button_camera_off), camera_off_icon); - - /* Add an empty expanded GtkToolItem so the volume button is at the end of - * the toolbar. */ - tool_item = gtk_tool_item_new (); - gtk_tool_item_set_expand (tool_item, TRUE); - gtk_widget_show (GTK_WIDGET (tool_item)); - gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), tool_item, -1); - - priv->volume_button = gtk_volume_button_new (); - /* FIXME listen to the audiosinks signals and update the button according to - * that, for now starting out at 1.0 and assuming only the app changes the - * volume will do */ - gtk_scale_button_set_value (GTK_SCALE_BUTTON (priv->volume_button), 1.0); - g_signal_connect (G_OBJECT (priv->volume_button), "value-changed", - G_CALLBACK (empathy_streamed_media_window_volume_changed_cb), self); - - tool_item = gtk_tool_item_new (); - gtk_container_add (GTK_CONTAINER (tool_item), priv->volume_button); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - gtk_toolbar_insert (GTK_TOOLBAR (priv->toolbar), tool_item, -1); -} - -static void -dtmf_start_tone_cb (EmpathyDialpadWidget *dialpad, - TpDTMFEvent event, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - EmpathyTpStreamedMedia *call; - - g_object_get (priv->handler, "tp-call", &call, NULL); - - empathy_tp_streamed_media_start_tone (call, event); - - g_object_unref (call); -} - -static void -dtmf_stop_tone_cb (EmpathyDialpadWidget *self, - TpDTMFEvent event, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - EmpathyTpStreamedMedia *call; - - g_object_get (priv->handler, "tp-call", &call, NULL); - - empathy_tp_streamed_media_stop_tone (call); - - g_object_unref (call); -} - -static GtkWidget * -empathy_streamed_media_window_create_video_input_add_slider (EmpathyStreamedMediaWindow *self, - gchar *label_text, GtkWidget *bin) -{ - GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); - GtkWidget *scale = gtk_vscale_new_with_range (0, 100, 10); - GtkWidget *label = gtk_label_new (label_text); - - gtk_widget_set_sensitive (scale, FALSE); - - gtk_container_add (GTK_CONTAINER (bin), vbox); - - gtk_range_set_inverted (GTK_RANGE (scale), TRUE); - gtk_box_pack_start (GTK_BOX (vbox), scale, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); - - return scale; -} - -static void -empathy_streamed_media_window_video_contrast_changed_cb (GtkAdjustment *adj, - EmpathyStreamedMediaWindow *self) - -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - empathy_video_src_set_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_CONTRAST, gtk_adjustment_get_value (adj)); -} - -static void -empathy_streamed_media_window_video_brightness_changed_cb (GtkAdjustment *adj, - EmpathyStreamedMediaWindow *self) - -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - empathy_video_src_set_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_BRIGHTNESS, gtk_adjustment_get_value (adj)); -} - -static void -empathy_streamed_media_window_video_gamma_changed_cb (GtkAdjustment *adj, - EmpathyStreamedMediaWindow *self) - -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - empathy_video_src_set_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_GAMMA, gtk_adjustment_get_value (adj)); -} - - -static GtkWidget * -empathy_streamed_media_window_create_video_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GtkWidget *hbox; - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE); - - priv->video_contrast = empathy_streamed_media_window_create_video_input_add_slider ( - self, _("Contrast"), hbox); - - priv->video_brightness = empathy_streamed_media_window_create_video_input_add_slider ( - self, _("Brightness"), hbox); - - priv->video_gamma = empathy_streamed_media_window_create_video_input_add_slider ( - self, _("Gamma"), hbox); - - return hbox; -} - -static void -empathy_streamed_media_window_setup_video_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - guint supported; - GtkAdjustment *adj; - - supported = empathy_video_src_get_supported_channels (priv->video_input); - - if (supported & EMPATHY_GST_VIDEO_SRC_SUPPORTS_CONTRAST) - { - adj = gtk_range_get_adjustment (GTK_RANGE (priv->video_contrast)); - - gtk_adjustment_set_value (adj, - empathy_video_src_get_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_CONTRAST)); - - g_signal_connect (G_OBJECT (adj), "value-changed", - G_CALLBACK (empathy_streamed_media_window_video_contrast_changed_cb), self); - - gtk_widget_set_sensitive (priv->video_contrast, TRUE); - } - - if (supported & EMPATHY_GST_VIDEO_SRC_SUPPORTS_BRIGHTNESS) - { - adj = gtk_range_get_adjustment (GTK_RANGE (priv->video_brightness)); - - gtk_adjustment_set_value (adj, - empathy_video_src_get_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_BRIGHTNESS)); - - g_signal_connect (G_OBJECT (adj), "value-changed", - G_CALLBACK (empathy_streamed_media_window_video_brightness_changed_cb), self); - gtk_widget_set_sensitive (priv->video_brightness, TRUE); - } - - if (supported & EMPATHY_GST_VIDEO_SRC_SUPPORTS_GAMMA) - { - adj = gtk_range_get_adjustment (GTK_RANGE (priv->video_gamma)); - - gtk_adjustment_set_value (adj, - empathy_video_src_get_channel (priv->video_input, - EMPATHY_GST_VIDEO_SRC_CHANNEL_GAMMA)); - - g_signal_connect (G_OBJECT (adj), "value-changed", - G_CALLBACK (empathy_streamed_media_window_video_gamma_changed_cb), self); - gtk_widget_set_sensitive (priv->video_gamma, TRUE); - } -} - -static void -empathy_streamed_media_window_mic_volume_changed_cb (GtkAdjustment *adj, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - gdouble volume; - - volume = gtk_adjustment_get_value (adj)/100.0; - - /* Don't store the volume because of muting */ - if (volume > 0 || gtk_toggle_tool_button_get_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->mic_button))) - priv->volume = volume; - - /* Ensure that the toggle button is active if the volume is > 0 and inactive - * if it's smaller than 0 */ - if ((volume > 0) != gtk_toggle_tool_button_get_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->mic_button))) - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->mic_button), volume > 0); - - empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (priv->audio_input), - volume); -} - -static void -empathy_streamed_media_window_audio_input_level_changed_cb (EmpathyGstAudioSrc *src, - gdouble level, EmpathyStreamedMediaWindow *window) -{ - gdouble value; - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - value = CLAMP (pow (10, level / 20), 0.0, 1.0); - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->volume_progress_bar), - value); -} - -static GtkWidget * -empathy_streamed_media_window_create_audio_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GtkWidget *hbox, *vbox, *label; - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3); - gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 3); - - priv->volume_scale = gtk_vscale_new_with_range (0, 150, 100); - gtk_range_set_inverted (GTK_RANGE (priv->volume_scale), TRUE); - label = gtk_label_new (_("Volume")); - - priv->audio_input_adj = gtk_range_get_adjustment ( - GTK_RANGE (priv->volume_scale)); - priv->volume = empathy_audio_src_get_volume (EMPATHY_GST_AUDIO_SRC - (priv->audio_input)); - gtk_adjustment_set_value (priv->audio_input_adj, priv->volume * 100); - - g_signal_connect (G_OBJECT (priv->audio_input_adj), "value-changed", - G_CALLBACK (empathy_streamed_media_window_mic_volume_changed_cb), self); - - gtk_box_pack_start (GTK_BOX (vbox), priv->volume_scale, TRUE, TRUE, 3); - gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 3); - - priv->volume_progress_bar = gtk_progress_bar_new (); - - gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->volume_progress_bar), - GTK_ORIENTATION_VERTICAL); - - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->volume_progress_bar), - 0); - - gtk_box_pack_start (GTK_BOX (hbox), priv->volume_progress_bar, FALSE, FALSE, - 3); - - return hbox; -} - -static void -create_video_output_widget (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstBus *bus; - - g_assert (priv->video_output == NULL); - g_assert (priv->pipeline != NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); - priv->video_output = empathy_video_widget_new (bus); - - gtk_box_pack_start (GTK_BOX (priv->remote_user_output_hbox), - priv->video_output, TRUE, TRUE, 0); - - gtk_widget_add_events (priv->video_output, - GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); - g_signal_connect (G_OBJECT (priv->video_output), "button-press-event", - G_CALLBACK (empathy_streamed_media_window_video_button_press_cb), self); - - g_object_unref (bus); -} - -static void -create_video_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_assert (priv->video_input == NULL); - priv->video_input = empathy_video_src_new (); - gst_object_ref (priv->video_input); - gst_object_sink (priv->video_input); -} - -static void -create_audio_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_assert (priv->audio_input == NULL); - priv->audio_input = empathy_audio_src_new (); - gst_object_ref (priv->audio_input); - gst_object_sink (priv->audio_input); - - tp_g_signal_connect_object (priv->audio_input, "peak-level-changed", - G_CALLBACK (empathy_streamed_media_window_audio_input_level_changed_cb), - self, 0); -} - -static void -add_video_preview_to_pipeline (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstElement *preview; - - g_assert (priv->video_preview != NULL); - g_assert (priv->pipeline != NULL); - g_assert (priv->video_input != NULL); - g_assert (priv->video_tee != NULL); - - preview = empathy_video_widget_get_element ( - EMPATHY_VIDEO_WIDGET (priv->video_preview)); - - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->video_input)) - { - g_warning ("Could not add video input to pipeline"); - return; - } - - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->video_tee)) - { - g_warning ("Could not add video tee to pipeline"); - return; - } - - if (!gst_bin_add (GST_BIN (priv->pipeline), preview)) - { - g_warning ("Could not add video preview to pipeline"); - return; - } - - if (!gst_element_link (priv->video_input, priv->video_tee)) - { - g_warning ("Could not link video input to video tee"); - return; - } - - if (!gst_element_link (priv->video_tee, preview)) - { - g_warning ("Could not link video tee to video preview"); - return; - } -} - -static void -create_video_preview (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstBus *bus; - - g_assert (priv->video_preview == NULL); - g_assert (priv->video_tee == NULL); - - bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); - - priv->video_preview = empathy_video_widget_new_with_size (bus, - SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH); - g_object_set (priv->video_preview, - "sync", FALSE, - "async", TRUE, - "flip-video", TRUE, - NULL); - - gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox), - priv->video_preview, TRUE, TRUE, 0); - - priv->video_tee = gst_element_factory_make ("tee", NULL); - gst_object_ref (priv->video_tee); - gst_object_sink (priv->video_tee); - - g_object_unref (bus); -} - -static void -play_camera (EmpathyStreamedMediaWindow *window, - gboolean play) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - GstElement *preview; - GstState state; - - if (priv->video_preview == NULL) - { - create_video_preview (window); - add_video_preview_to_pipeline (window); - } - - if (play) - state = GST_STATE_PLAYING; - else - state = GST_STATE_NULL; - - preview = empathy_video_widget_get_element ( - EMPATHY_VIDEO_WIDGET (priv->video_preview)); - - gst_element_set_state (preview, state); - gst_element_set_state (priv->video_input, state); - gst_element_set_state (priv->video_tee, state); -} - -static void -display_video_preview (EmpathyStreamedMediaWindow *self, - gboolean display) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (display) - { - /* Display the preview and hide the self avatar */ - DEBUG ("Show video preview"); - - play_camera (self, TRUE); - gtk_widget_show (priv->video_preview); - gtk_widget_hide (priv->self_user_avatar_widget); - } - else - { - /* Display the self avatar and hide the preview */ - DEBUG ("Show self avatar"); - - if (priv->video_preview != NULL) - { - gtk_widget_hide (priv->video_preview); - play_camera (self, FALSE); - } - gtk_widget_show (priv->self_user_avatar_widget); - } -} - -static void -empathy_streamed_media_window_set_state_connecting (EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - empathy_streamed_media_window_status_message (window, _("Connecting…")); - priv->call_state = CONNECTING; - - if (priv->outgoing) - empathy_sound_manager_start_playing (priv->sound_mgr, GTK_WIDGET (window), - EMPATHY_SOUND_PHONE_OUTGOING, MS_BETWEEN_RING); -} - -static void -disable_camera (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->camera_state == CAMERA_STATE_OFF) - return; - - DEBUG ("Disable camera"); - - display_video_preview (self, FALSE); - - if (priv->camera_state == CAMERA_STATE_ON) - empathy_streamed_media_window_set_send_video (self, CAMERA_STATE_OFF); - - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_on), FALSE); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_preview), FALSE); - - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_off), TRUE); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera_on), - CAMERA_STATE_OFF); - unblock_camera_control_signals (self); - - priv->camera_state = CAMERA_STATE_OFF; -} - -static void -tool_button_camera_off_toggled_cb (GtkToggleToolButton *toggle, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (!gtk_toggle_tool_button_get_active (toggle)) - { - if (priv->camera_state == CAMERA_STATE_OFF) - { - /* We can't change the state by disabling the button */ - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (toggle, TRUE); - unblock_camera_control_signals (self); - } - - return; - } - - disable_camera (self); -} - -static void -enable_preview (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->camera_state == CAMERA_STATE_PREVIEW) - return; - - DEBUG ("Enable preview"); - - if (priv->camera_state == CAMERA_STATE_ON) - { - /* preview is already displayed so we just have to stop sending */ - empathy_streamed_media_window_set_send_video (self, CAMERA_STATE_PREVIEW); - } - else - { - display_video_preview (self, TRUE); - } - - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_off), FALSE); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_on), FALSE); - - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_preview), TRUE); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera_on), - CAMERA_STATE_PREVIEW); - unblock_camera_control_signals (self); - - priv->camera_state = CAMERA_STATE_PREVIEW; -} - -static void -tool_button_camera_preview_toggled_cb (GtkToggleToolButton *toggle, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (!gtk_toggle_tool_button_get_active (toggle)) - { - if (priv->camera_state == CAMERA_STATE_PREVIEW) - { - /* We can't change the state by disabling the button */ - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (toggle, TRUE); - unblock_camera_control_signals (self); - } - - return; - } - - enable_preview (self); -} - -static void -enable_camera (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->camera_state == CAMERA_STATE_ON) - return; - - if (priv->video_input == NULL) - { - DEBUG ("Can't enable camera, no input"); - return; - } - - - DEBUG ("Enable camera"); - - empathy_streamed_media_window_set_send_video (self, CAMERA_STATE_ON); - - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_off), FALSE); - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_preview), FALSE); - - gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON ( - priv->tool_button_camera_on), TRUE); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (priv->action_camera_on), - CAMERA_STATE_ON); - unblock_camera_control_signals (self); - - priv->camera_state = CAMERA_STATE_ON; -} - -static void -tool_button_camera_on_toggled_cb (GtkToggleToolButton *toggle, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (!gtk_toggle_tool_button_get_active (toggle)) - { - if (priv->camera_state == CAMERA_STATE_ON) - { - /* We can't change the state by disabling the button */ - block_camera_control_signals (self); - gtk_toggle_tool_button_set_active (toggle, TRUE); - unblock_camera_control_signals (self); - } - - return; - } - - enable_camera (self); -} - -static void -action_camera_change_cb (GtkRadioAction *action, - GtkRadioAction *current, - EmpathyStreamedMediaWindow *self) -{ - CameraState state; - - state = gtk_radio_action_get_current_value (current); - - switch (state) - { - case CAMERA_STATE_OFF: - disable_camera (self); - break; - - case CAMERA_STATE_PREVIEW: - enable_preview (self); - break; - - case CAMERA_STATE_ON: - enable_camera (self); - break; - - default: - g_assert_not_reached (); - } -} - -static void -create_pipeline (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstBus *bus; - - g_assert (priv->pipeline == NULL); - - priv->pipeline = gst_pipeline_new (NULL); - priv->pipeline_playing = FALSE; - - bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); - priv->bus_message_source_id = gst_bus_add_watch (bus, - empathy_streamed_media_window_bus_message, self); - - g_object_unref (bus); -} - - -static void -empathy_streamed_media_window_init (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GtkBuilder *gui; - GtkWidget *top_vbox; - GtkWidget *h; - GtkWidget *arrow; - GtkWidget *page; - gchar *filename; - GtkWidget *scroll; - - filename = empathy_file_lookup ("empathy-streamed-media-window.ui", "src"); - gui = empathy_builder_get_file (filename, - "call_window_vbox", &top_vbox, - "errors_vbox", &priv->errors_vbox, - "pane", &priv->pane, - "statusbar", &priv->statusbar, - "redial", &priv->redial_button, - "microphone", &priv->mic_button, - "toolbar", &priv->toolbar, - "menuredial", &priv->redial, - "ui_manager", &priv->ui_manager, - "menufullscreen", &priv->menu_fullscreen, - "camera_off", &priv->tool_button_camera_off, - "camera_preview", &priv->tool_button_camera_preview, - "camera_on", &priv->tool_button_camera_on, - "action_camera_on", &priv->action_camera_on, - "details_vbox", &priv->details_vbox, - "vcodec_encoding_label", &priv->vcodec_encoding_label, - "acodec_encoding_label", &priv->acodec_encoding_label, - "acodec_decoding_label", &priv->acodec_decoding_label, - "vcodec_decoding_label", &priv->vcodec_decoding_label, - "audio_remote_candidate_label", &priv->audio_remote_candidate_label, - "audio_local_candidate_label", &priv->audio_local_candidate_label, - "video_remote_candidate_label", &priv->video_remote_candidate_label, - "video_local_candidate_label", &priv->video_local_candidate_label, - "video_remote_candidate_info_img", &priv->video_remote_candidate_info_img, - "video_local_candidate_info_img", &priv->video_local_candidate_info_img, - "audio_remote_candidate_info_img", &priv->audio_remote_candidate_info_img, - "audio_local_candidate_info_img", &priv->audio_local_candidate_info_img, - NULL); - g_free (filename); - - empathy_builder_connect (gui, self, - "menuhangup", "activate", empathy_streamed_media_window_hangup_cb, - "hangup", "clicked", empathy_streamed_media_window_hangup_cb, - "menuredial", "activate", empathy_streamed_media_window_redial_cb, - "redial", "clicked", empathy_streamed_media_window_redial_cb, - "microphone", "toggled", empathy_streamed_media_window_mic_toggled_cb, - "menufullscreen", "activate", empathy_streamed_media_window_fullscreen_cb, - "camera_off", "toggled", tool_button_camera_off_toggled_cb, - "camera_preview", "toggled", tool_button_camera_preview_toggled_cb, - "camera_on", "toggled", tool_button_camera_on_toggled_cb, - "action_camera_on", "changed", action_camera_change_cb, - NULL); - - gtk_action_set_sensitive (priv->menu_fullscreen, FALSE); - - priv->lock = g_mutex_new (); - - gtk_container_add (GTK_CONTAINER (self), top_vbox); - - priv->content_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, - CONTENT_HBOX_SPACING); - gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox), - CONTENT_HBOX_BORDER_WIDTH); - gtk_paned_pack1 (GTK_PANED (priv->pane), priv->content_hbox, TRUE, FALSE); - - /* remote user output frame */ - priv->remote_user_output_frame = gtk_frame_new (NULL); - gtk_widget_set_size_request (priv->remote_user_output_frame, - EMPATHY_VIDEO_WIDGET_DEFAULT_WIDTH, EMPATHY_VIDEO_WIDGET_DEFAULT_HEIGHT); - gtk_box_pack_start (GTK_BOX (priv->content_hbox), - priv->remote_user_output_frame, TRUE, TRUE, - CONTENT_HBOX_CHILDREN_PACKING_PADDING); - - priv->remote_user_output_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - - priv->remote_user_avatar_widget = gtk_image_new (); - - gtk_box_pack_start (GTK_BOX (priv->remote_user_output_hbox), - priv->remote_user_avatar_widget, TRUE, TRUE, 0); - - gtk_container_add (GTK_CONTAINER (priv->remote_user_output_frame), - priv->remote_user_output_hbox); - - /* self user output frame */ - priv->self_user_output_frame = gtk_frame_new (NULL); - gtk_widget_set_size_request (priv->self_user_output_frame, - SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH); - - priv->self_user_output_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - - priv->self_user_avatar_widget = gtk_image_new (); - gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox), - priv->self_user_avatar_widget, TRUE, TRUE, 0); - - gtk_container_add (GTK_CONTAINER (priv->self_user_output_frame), - priv->self_user_output_hbox); - - create_pipeline (self); - create_video_output_widget (self); - create_audio_input (self); - create_video_input (self); - - priv->fsnotifier = fs_element_added_notifier_new (); - fs_element_added_notifier_add (priv->fsnotifier, GST_BIN (priv->pipeline)); - - /* The call will be started as soon the pipeline is playing */ - priv->start_call_when_playing = TRUE; - - priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3); - gtk_box_pack_start (GTK_BOX (priv->content_hbox), priv->vbox, - FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING); - gtk_box_pack_start (GTK_BOX (priv->vbox), priv->self_user_output_frame, - FALSE, FALSE, 0); - - empathy_streamed_media_window_setup_toolbar (self); - - priv->sidebar_button = gtk_toggle_button_new_with_mnemonic (_("_Sidebar")); - arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - g_signal_connect (G_OBJECT (priv->sidebar_button), "toggled", - G_CALLBACK (empathy_streamed_media_window_sidebar_toggled_cb), self); - - gtk_button_set_image (GTK_BUTTON (priv->sidebar_button), arrow); - - h = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_box_pack_end (GTK_BOX (priv->vbox), h, FALSE, FALSE, 3); - gtk_box_pack_end (GTK_BOX (h), priv->sidebar_button, FALSE, FALSE, 3); - - priv->sidebar = ev_sidebar_new (); - g_signal_connect (G_OBJECT (priv->sidebar), - "hide", G_CALLBACK (empathy_streamed_media_window_sidebar_hidden_cb), self); - g_signal_connect (G_OBJECT (priv->sidebar), - "show", G_CALLBACK (empathy_streamed_media_window_sidebar_shown_cb), self); - gtk_paned_pack2 (GTK_PANED (priv->pane), priv->sidebar, FALSE, FALSE); - - page = empathy_streamed_media_window_create_audio_input (self); - ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "audio-input", - _("Audio input"), page); - - page = empathy_streamed_media_window_create_video_input (self); - ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "video-input", - _("Video input"), page); - - priv->dtmf_panel = empathy_dialpad_widget_new (); - g_signal_connect (priv->dtmf_panel, "start-tone", - G_CALLBACK (dtmf_start_tone_cb), self); - g_signal_connect (priv->dtmf_panel, "stop-tone", - G_CALLBACK (dtmf_stop_tone_cb), self); - ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "dialpad", - _("Dialpad"), priv->dtmf_panel); - - gtk_widget_set_sensitive (priv->dtmf_panel, FALSE); - - /* Put the details vbox in a scroll window as it can require a lot of - * horizontal space. */ - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll), - priv->details_vbox); - - ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "details", - _("Details"), scroll); - - gtk_widget_show_all (top_vbox); - - gtk_widget_hide (priv->sidebar); - - priv->fullscreen = empathy_streamed_media_window_fullscreen_new (self); - empathy_streamed_media_window_fullscreen_set_video_widget (priv->fullscreen, - priv->video_output); - g_signal_connect (G_OBJECT (priv->fullscreen->leave_fullscreen_button), - "clicked", G_CALLBACK (empathy_streamed_media_window_fullscreen_cb), self); - - g_signal_connect (G_OBJECT (self), "realize", - G_CALLBACK (empathy_streamed_media_window_realized_cb), self); - - g_signal_connect (G_OBJECT (self), "delete-event", - G_CALLBACK (empathy_streamed_media_window_delete_cb), self); - - g_signal_connect (G_OBJECT (self), "window-state-event", - G_CALLBACK (empathy_streamed_media_window_state_event_cb), self); - - g_signal_connect (G_OBJECT (self), "key-press-event", - G_CALLBACK (empathy_streamed_media_window_key_press_cb), self); - - priv->timer = g_timer_new (); - - g_object_ref (priv->ui_manager); - g_object_unref (gui); - - priv->sound_mgr = empathy_sound_manager_dup_singleton (); - - empathy_geometry_bind (GTK_WINDOW (self), "av-window"); -} - -/* Instead of specifying a width and a height, we specify only one size. That's - because we want a square avatar icon. */ -static void -init_contact_avatar_with_size (EmpathyContact *contact, - GtkWidget *image_widget, - gint size) -{ - GdkPixbuf *pixbuf_avatar = NULL; - - if (contact != NULL) - { - pixbuf_avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, - size, size); - } - - if (pixbuf_avatar == NULL) - { - pixbuf_avatar = empathy_pixbuf_from_icon_name_sized ( - EMPATHY_IMAGE_AVATAR_DEFAULT, size); - } - - gtk_image_set_from_pixbuf (GTK_IMAGE (image_widget), pixbuf_avatar); - - if (pixbuf_avatar != NULL) - g_object_unref (pixbuf_avatar); -} - -static void -set_window_title (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - gchar *tmp; - - /* translators: Call is a noun and %s is the contact name. This string - * is used in the window title */ - tmp = g_strdup_printf (_("Call with %s"), - empathy_contact_get_alias (priv->contact)); - gtk_window_set_title (GTK_WINDOW (self), tmp); - g_free (tmp); -} - -static void -contact_name_changed_cb (EmpathyContact *contact, - GParamSpec *pspec, EmpathyStreamedMediaWindow *self) -{ - set_window_title (self); -} - -static void -contact_avatar_changed_cb (EmpathyContact *contact, - GParamSpec *pspec, GtkWidget *avatar_widget) -{ - int size; - GtkAllocation allocation; - - gtk_widget_get_allocation (avatar_widget, &allocation); - size = allocation.height; - - if (size == 0) - { - /* the widget is not allocated yet, set a default size */ - size = MIN (REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT, - REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH); - } - - init_contact_avatar_with_size (contact, avatar_widget, size); -} - -static void -empathy_streamed_media_window_got_self_contact_cb (TpConnection *connection, - EmpathyContact *contact, const GError *error, gpointer user_data, - GObject *weak_object) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - init_contact_avatar_with_size (contact, priv->self_user_avatar_widget, - MIN (SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH)); - - g_signal_connect (contact, "notify::avatar", - G_CALLBACK (contact_avatar_changed_cb), priv->self_user_avatar_widget); -} - -static void -empathy_streamed_media_window_setup_avatars (EmpathyStreamedMediaWindow *self, - EmpathyStreamedMediaHandler *handler) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_object_get (handler, "contact", &(priv->contact), NULL); - - if (priv->contact != NULL) - { - TpConnection *connection; - - set_window_title (self); - - g_signal_connect (priv->contact, "notify::name", - G_CALLBACK (contact_name_changed_cb), self); - g_signal_connect (priv->contact, "notify::avatar", - G_CALLBACK (contact_avatar_changed_cb), - priv->remote_user_avatar_widget); - - /* Retreiving the self avatar */ - connection = empathy_contact_get_connection (priv->contact); - empathy_tp_contact_factory_get_from_handle (connection, - tp_connection_get_self_handle (connection), - empathy_streamed_media_window_got_self_contact_cb, self, NULL, G_OBJECT (self)); - } - else - { - g_warning ("call handler doesn't have a contact"); - /* translators: Call is a noun. This string is used in the window - * title */ - gtk_window_set_title (GTK_WINDOW (self), _("Call")); - - /* Since we can't access the remote contact, we can't get a connection - to it and can't get the self contact (and its avatar). This means - that we have to manually set the self avatar. */ - init_contact_avatar_with_size (NULL, priv->self_user_avatar_widget, - MIN (SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH)); - } - - init_contact_avatar_with_size (priv->contact, - priv->remote_user_avatar_widget, - MIN (REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH, - REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT)); - - /* The remote avatar is shown by default and will be hidden when we receive - video from the remote side. */ - gtk_widget_hide (priv->video_output); - gtk_widget_show (priv->remote_user_avatar_widget); -} - -static void -update_send_codec (EmpathyStreamedMediaWindow *self, - gboolean audio) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - FsCodec *codec; - GtkWidget *widget; - gchar *tmp; - - if (audio) - { - codec = empathy_streamed_media_handler_get_send_audio_codec (priv->handler); - widget = priv->acodec_encoding_label; - } - else - { - codec = empathy_streamed_media_handler_get_send_video_codec (priv->handler); - widget = priv->vcodec_encoding_label; - } - - if (codec == NULL) - return; - - tmp = g_strdup_printf ("%s/%u", codec->encoding_name, codec->clock_rate); - gtk_label_set_text (GTK_LABEL (widget), tmp); - g_free (tmp); -} - -static void -send_audio_codec_notify_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = user_data; - - update_send_codec (self, TRUE); -} - -static void -send_video_codec_notify_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = user_data; - - update_send_codec (self, FALSE); -} - -static void -update_recv_codec (EmpathyStreamedMediaWindow *self, - gboolean audio) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GList *codecs, *l; - GtkWidget *widget; - GString *str = NULL; - - if (audio) - { - codecs = empathy_streamed_media_handler_get_recv_audio_codecs (priv->handler); - widget = priv->acodec_decoding_label; - } - else - { - codecs = empathy_streamed_media_handler_get_recv_video_codecs (priv->handler); - widget = priv->vcodec_decoding_label; - } - - if (codecs == NULL) - return; - - for (l = codecs; l != NULL; l = g_list_next (l)) - { - FsCodec *codec = l->data; - - if (str == NULL) - str = g_string_new (NULL); - else - g_string_append (str, ", "); - - g_string_append_printf (str, "%s/%u", codec->encoding_name, - codec->clock_rate); - } - - gtk_label_set_text (GTK_LABEL (widget), str->str); - g_string_free (str, TRUE); -} - -static void -recv_audio_codecs_notify_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = user_data; - - update_recv_codec (self, TRUE); -} - -static void -recv_video_codecs_notify_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = user_data; - - update_recv_codec (self, FALSE); -} - -static const gchar * -candidate_type_to_str (FsCandidate *candidate) -{ - switch (candidate->type) - { - case FS_CANDIDATE_TYPE_HOST: - return "host"; - case FS_CANDIDATE_TYPE_SRFLX: - return "server reflexive"; - case FS_CANDIDATE_TYPE_PRFLX: - return "peer reflexive"; - case FS_CANDIDATE_TYPE_RELAY: - return "relay"; - case FS_CANDIDATE_TYPE_MULTICAST: - return "multicast"; - } - - return NULL; -} - -static const gchar * -candidate_type_to_desc (FsCandidate *candidate) -{ - switch (candidate->type) - { - case FS_CANDIDATE_TYPE_HOST: - return _("The IP address as seen by the machine"); - case FS_CANDIDATE_TYPE_SRFLX: - return _("The IP address as seen by a server on the Internet"); - case FS_CANDIDATE_TYPE_PRFLX: - return _("The IP address of the peer as seen by the other side"); - case FS_CANDIDATE_TYPE_RELAY: - return _("The IP address of a relay server"); - case FS_CANDIDATE_TYPE_MULTICAST: - return _("The IP address of the multicast group"); - } - - return NULL; -} - -static void -update_candidat_widget (EmpathyStreamedMediaWindow *self, - GtkWidget *label, - GtkWidget *img, - FsCandidate *candidate) -{ - gchar *str; - - g_assert (candidate != NULL); - str = g_strdup_printf ("%s %u (%s)", candidate->ip, - candidate->port, candidate_type_to_str (candidate)); - - gtk_label_set_text (GTK_LABEL (label), str); - gtk_widget_set_tooltip_text (img, candidate_type_to_desc (candidate)); - - g_free (str); -} - -static void -candidates_changed_cb (GObject *object, - FsMediaType type, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - FsCandidate *candidate = NULL; - - if (type == FS_MEDIA_TYPE_VIDEO) - { - /* Update remote candidate */ - candidate = empathy_streamed_media_handler_get_video_remote_candidate ( - priv->handler); - - update_candidat_widget (self, priv->video_remote_candidate_label, - priv->video_remote_candidate_info_img, candidate); - - /* Update local candidate */ - candidate = empathy_streamed_media_handler_get_video_local_candidate ( - priv->handler); - - update_candidat_widget (self, priv->video_local_candidate_label, - priv->video_local_candidate_info_img, candidate); - } - else - { - /* Update remote candidate */ - candidate = empathy_streamed_media_handler_get_audio_remote_candidate ( - priv->handler); - - update_candidat_widget (self, priv->audio_remote_candidate_label, - priv->audio_remote_candidate_info_img, candidate); - - /* Update local candidate */ - candidate = empathy_streamed_media_handler_get_audio_local_candidate ( - priv->handler); - - update_candidat_widget (self, priv->audio_local_candidate_label, - priv->audio_local_candidate_info_img, candidate); - } -} - -static void -empathy_streamed_media_window_constructed (GObject *object) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (object); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - EmpathyTpStreamedMedia *call; - - g_assert (priv->handler != NULL); - - g_object_get (priv->handler, "tp-call", &call, NULL); - priv->outgoing = (call == NULL); - if (call != NULL) - g_object_unref (call); - - empathy_streamed_media_window_setup_avatars (self, priv->handler); - empathy_streamed_media_window_set_state_connecting (self); - - if (!empathy_streamed_media_handler_has_initial_video (priv->handler)) - { - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_off), TRUE); - } - /* If call has InitialVideo, the preview will be started once the call has - * been started (start_call()). */ - - update_send_codec (self, TRUE); - update_send_codec (self, FALSE); - update_recv_codec (self, TRUE); - update_recv_codec (self, FALSE); - - tp_g_signal_connect_object (priv->handler, "notify::send-audio-codec", - G_CALLBACK (send_audio_codec_notify_cb), self, 0); - tp_g_signal_connect_object (priv->handler, "notify::send-video-codec", - G_CALLBACK (send_video_codec_notify_cb), self, 0); - tp_g_signal_connect_object (priv->handler, "notify::recv-audio-codecs", - G_CALLBACK (recv_audio_codecs_notify_cb), self, 0); - tp_g_signal_connect_object (priv->handler, "notify::recv-video-codecs", - G_CALLBACK (recv_video_codecs_notify_cb), self, 0); - - tp_g_signal_connect_object (priv->handler, "candidates-changed", - G_CALLBACK (candidates_changed_cb), self, 0); -} - -static void empathy_streamed_media_window_dispose (GObject *object); -static void empathy_streamed_media_window_finalize (GObject *object); - -static void -empathy_streamed_media_window_set_property (GObject *object, - guint property_id, const GValue *value, GParamSpec *pspec) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (object); - - switch (property_id) - { - case PROP_STREAMED_MEDIA_HANDLER: - priv->handler = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -empathy_streamed_media_window_get_property (GObject *object, - guint property_id, GValue *value, GParamSpec *pspec) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (object); - - switch (property_id) - { - case PROP_STREAMED_MEDIA_HANDLER: - g_value_set_object (value, priv->handler); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -empathy_streamed_media_window_class_init ( - EmpathyStreamedMediaWindowClass *empathy_streamed_media_window_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (empathy_streamed_media_window_class); - GParamSpec *param_spec; - - g_type_class_add_private (empathy_streamed_media_window_class, - sizeof (EmpathyStreamedMediaWindowPriv)); - - object_class->constructed = empathy_streamed_media_window_constructed; - object_class->set_property = empathy_streamed_media_window_set_property; - object_class->get_property = empathy_streamed_media_window_get_property; - - object_class->dispose = empathy_streamed_media_window_dispose; - object_class->finalize = empathy_streamed_media_window_finalize; - - param_spec = g_param_spec_object ("handler", - "handler", "The call handler", - EMPATHY_TYPE_STREAMED_MEDIA_HANDLER, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_STREAMED_MEDIA_HANDLER, param_spec); -} - -static void -empathy_streamed_media_window_video_stream_changed_cb (EmpathyTpStreamedMedia *call, - GParamSpec *property, EmpathyStreamedMediaWindow *self) -{ - DEBUG ("video stream changed"); - empathy_streamed_media_window_update_avatars_visibility (call, self); -} - -void -empathy_streamed_media_window_dispose (GObject *object) -{ - EmpathyTpStreamedMedia *call; - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (object); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - g_object_get (priv->handler, "tp-call", &call, NULL); - - if (call != NULL) - { - g_object_unref (call); - } - - if (priv->handler != NULL) - { - empathy_streamed_media_handler_stop_call (priv->handler); - g_object_unref (priv->handler); - } - priv->handler = NULL; - - if (priv->bus_message_source_id != 0) - { - g_source_remove (priv->bus_message_source_id); - priv->bus_message_source_id = 0; - } - - if (priv->pipeline != NULL) - g_object_unref (priv->pipeline); - priv->pipeline = NULL; - - if (priv->video_input != NULL) - g_object_unref (priv->video_input); - priv->video_input = NULL; - - if (priv->audio_input != NULL) - g_object_unref (priv->audio_input); - priv->audio_input = NULL; - - if (priv->video_tee != NULL) - g_object_unref (priv->video_tee); - priv->video_tee = NULL; - - if (priv->fsnotifier != NULL) - g_object_unref (priv->fsnotifier); - priv->fsnotifier = NULL; - - if (priv->timer_id != 0) - g_source_remove (priv->timer_id); - priv->timer_id = 0; - - if (priv->ui_manager != NULL) - g_object_unref (priv->ui_manager); - priv->ui_manager = NULL; - - if (priv->fullscreen != NULL) - g_object_unref (priv->fullscreen); - priv->fullscreen = NULL; - - if (priv->contact != NULL) - { - g_signal_handlers_disconnect_by_func (priv->contact, - contact_name_changed_cb, self); - g_object_unref (priv->contact); - priv->contact = NULL; - } - - tp_clear_object (&priv->sound_mgr); - - /* release any references held by the object here */ - if (G_OBJECT_CLASS (empathy_streamed_media_window_parent_class)->dispose) - G_OBJECT_CLASS (empathy_streamed_media_window_parent_class)->dispose (object); -} - -static void -disconnect_video_output_motion_handler (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->video_output_motion_handler_id != 0) - { - g_signal_handler_disconnect (G_OBJECT (priv->video_output), - priv->video_output_motion_handler_id); - priv->video_output_motion_handler_id = 0; - } -} - -void -empathy_streamed_media_window_finalize (GObject *object) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (object); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - disconnect_video_output_motion_handler (self); - - /* free any data held directly by the object here */ - g_mutex_free (priv->lock); - - g_timer_destroy (priv->timer); - - G_OBJECT_CLASS (empathy_streamed_media_window_parent_class)->finalize (object); -} - - -EmpathyStreamedMediaWindow * -empathy_streamed_media_window_new (EmpathyStreamedMediaHandler *handler) -{ - return EMPATHY_STREAMED_MEDIA_WINDOW ( - g_object_new (EMPATHY_TYPE_STREAMED_MEDIA_WINDOW, "handler", handler, NULL)); -} - -static void -empathy_streamed_media_window_conference_added_cb (EmpathyStreamedMediaHandler *handler, - GstElement *conference, gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GKeyFile *keyfile; - - keyfile = fs_utils_get_default_element_properties (conference); - if (keyfile != NULL) - fs_element_added_notifier_set_properties_from_keyfile (priv->fsnotifier, - keyfile); - - gst_bin_add (GST_BIN (priv->pipeline), conference); - - gst_element_set_state (conference, GST_STATE_PLAYING); -} - -static gboolean -empathy_streamed_media_window_request_resource_cb (EmpathyStreamedMediaHandler *handler, - FsMediaType type, FsStreamDirection direction, gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (type != FS_MEDIA_TYPE_VIDEO) - return TRUE; - - if (direction == FS_DIRECTION_RECV) - return TRUE; - - /* video and direction is send */ - return priv->video_input != NULL; -} - -static gboolean -empathy_streamed_media_window_reset_pipeline (EmpathyStreamedMediaWindow *self) -{ - GstStateChangeReturn state_change_return; - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (priv->pipeline == NULL) - return TRUE; - - if (priv->bus_message_source_id != 0) - { - g_source_remove (priv->bus_message_source_id); - priv->bus_message_source_id = 0; - } - - state_change_return = gst_element_set_state (priv->pipeline, GST_STATE_NULL); - - if (state_change_return == GST_STATE_CHANGE_SUCCESS || - state_change_return == GST_STATE_CHANGE_NO_PREROLL) - { - if (priv->pipeline != NULL) - g_object_unref (priv->pipeline); - priv->pipeline = NULL; - - g_signal_handlers_disconnect_by_func (priv->audio_input_adj, - empathy_streamed_media_window_mic_volume_changed_cb, self); - - if (priv->video_tee != NULL) - g_object_unref (priv->video_tee); - priv->video_tee = NULL; - - if (priv->video_preview != NULL) - gtk_widget_destroy (priv->video_preview); - priv->video_preview = NULL; - - priv->funnel = NULL; - - create_pipeline (self); - /* Call will be started when user will hit the 'redial' button */ - priv->start_call_when_playing = FALSE; - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); - - return TRUE; - } - else - { - g_message ("Error: could not destroy pipeline. Closing call window"); - gtk_widget_destroy (GTK_WIDGET (self)); - - return FALSE; - } -} - -static void -reset_details_pane (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - /* translators: encoding video codec is unknown */ - gtk_label_set_text (GTK_LABEL (priv->vcodec_encoding_label), - C_("codec", "Unknown")); - /* translators: encoding audio codec is unknown */ - gtk_label_set_text (GTK_LABEL (priv->acodec_encoding_label), - C_("codec", "Unknown")); - /* translators: decoding video codec is unknown */ - gtk_label_set_text (GTK_LABEL (priv->vcodec_decoding_label), - C_("codec", "Unknown")); - /* translators: decoding audio codec is unknown */ - gtk_label_set_text (GTK_LABEL (priv->acodec_decoding_label), - C_("codec", "Unknown")); -} - -static gboolean -empathy_streamed_media_window_disconnected (EmpathyStreamedMediaWindow *self, - gboolean restart) -{ - gboolean could_disconnect = FALSE; - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - gboolean could_reset_pipeline; - - /* Leave full screen mode if needed */ - gtk_window_unfullscreen (GTK_WINDOW (self)); - - gtk_action_set_sensitive (priv->menu_fullscreen, FALSE); - - could_reset_pipeline = empathy_streamed_media_window_reset_pipeline (self); - - if (priv->call_state == CONNECTING) - empathy_sound_manager_stop (priv->sound_mgr, - EMPATHY_SOUND_PHONE_OUTGOING); - - if (priv->call_state != REDIALING) - priv->call_state = DISCONNECTED; - - if (could_reset_pipeline) - { - g_mutex_lock (priv->lock); - - g_timer_stop (priv->timer); - - if (priv->timer_id != 0) - g_source_remove (priv->timer_id); - priv->timer_id = 0; - - g_mutex_unlock (priv->lock); - - if (!restart) - /* We are about to destroy the window, no need to update it or create - * a video preview */ - return TRUE; - - empathy_streamed_media_window_status_message (self, _("Disconnected")); - - gtk_action_set_sensitive (priv->redial, TRUE); - gtk_widget_set_sensitive (priv->redial_button, TRUE); - - /* Unsensitive the camera and mic button */ - gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE); - gtk_action_set_sensitive (priv->action_camera_on, FALSE); - gtk_widget_set_sensitive (priv->mic_button, FALSE); - - /* Be sure that the mic button is enabled */ - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->mic_button), TRUE); - - if (priv->camera_state == CAMERA_STATE_ON) - { - /* Enable the 'preview' button as we are not sending atm. */ - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_preview), TRUE); - } - else if (priv->camera_state == CAMERA_STATE_PREVIEW) - { - /* Restart the preview with the new pipeline. */ - display_video_preview (self, TRUE); - } - - gtk_progress_bar_set_fraction ( - GTK_PROGRESS_BAR (priv->volume_progress_bar), 0); - - /* destroy the video output; it will be recreated when we'll redial */ - disconnect_video_output_motion_handler (self); - gtk_widget_destroy (priv->video_output); - priv->video_output = NULL; - - gtk_widget_show (priv->remote_user_avatar_widget); - - reset_details_pane (self); - - priv->sending_video = FALSE; - priv->call_started = FALSE; - - could_disconnect = TRUE; - - /* TODO: display the self avatar of the preview (depends if the "Always - * Show Video Preview" is enabled or not) */ - } - - return could_disconnect; -} - - -static void -empathy_streamed_media_window_channel_closed_cb (EmpathyStreamedMediaHandler *handler, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - if (empathy_streamed_media_window_disconnected (self, TRUE) && - priv->call_state == REDIALING) - empathy_streamed_media_window_restart_call (self); -} - - -static void -empathy_streamed_media_window_channel_stream_closed_cb (EmpathyStreamedMediaHandler *handler, - TfStream *stream, gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - guint media_type; - - g_object_get (stream, "media-type", &media_type, NULL); - - /* - * This assumes that there is only one video stream per channel... - */ - - if (media_type == TP_MEDIA_STREAM_TYPE_VIDEO) - { - if (priv->funnel != NULL) - { - GstElement *output; - - output = empathy_video_widget_get_element (EMPATHY_VIDEO_WIDGET - (priv->video_output)); - - gst_element_set_state (output, GST_STATE_NULL); - gst_element_set_state (priv->funnel, GST_STATE_NULL); - - gst_bin_remove (GST_BIN (priv->pipeline), output); - gst_bin_remove (GST_BIN (priv->pipeline), priv->funnel); - priv->funnel = NULL; - } - } - else if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO) - { - if (priv->audio_output != NULL) - { - gst_element_set_state (priv->audio_output, GST_STATE_NULL); - - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); - priv->audio_output = NULL; - } - } -} - -/* Called with global lock held */ -static GstPad * -empathy_streamed_media_window_get_video_sink_pad (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstPad *pad; - GstElement *output; - - if (priv->funnel == NULL) - { - output = empathy_video_widget_get_element (EMPATHY_VIDEO_WIDGET - (priv->video_output)); - - priv->funnel = gst_element_factory_make ("fsfunnel", NULL); - - if (!priv->funnel) - { - g_warning ("Could not create fsfunnel"); - return NULL; - } - - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->funnel)) - { - gst_object_unref (priv->funnel); - priv->funnel = NULL; - g_warning ("Could not add funnel to pipeline"); - return NULL; - } - - if (!gst_bin_add (GST_BIN (priv->pipeline), output)) - { - g_warning ("Could not add the video output widget to the pipeline"); - goto error; - } - - if (!gst_element_link (priv->funnel, output)) - { - g_warning ("Could not link output sink to funnel"); - goto error_output_added; - } - - if (gst_element_set_state (output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start video sink"); - goto error_output_added; - } - - if (gst_element_set_state (priv->funnel, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start funnel"); - goto error_output_added; - } - } - - pad = gst_element_get_request_pad (priv->funnel, "sink%d"); - - if (!pad) - g_warning ("Could not get request pad from funnel"); - - return pad; - - - error_output_added: - - gst_element_set_locked_state (priv->funnel, TRUE); - gst_element_set_locked_state (output, TRUE); - - gst_element_set_state (priv->funnel, GST_STATE_NULL); - gst_element_set_state (output, GST_STATE_NULL); - - gst_bin_remove (GST_BIN (priv->pipeline), output); - gst_element_set_locked_state (output, FALSE); - - error: - - gst_bin_remove (GST_BIN (priv->pipeline), priv->funnel); - priv->funnel = NULL; - - return NULL; -} - -/* Called with global lock held */ -static GstPad * -empathy_streamed_media_window_get_audio_sink_pad (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstPad *pad; - GstPadTemplate *template; - - if (priv->audio_output == NULL) - { - priv->audio_output = empathy_audio_sink_new (); - - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->audio_output)) - { - g_warning ("Could not add audio sink to pipeline"); - g_object_unref (priv->audio_output); - goto error_add_output; - } - - if (gst_element_set_state (priv->audio_output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start audio sink"); - goto error; - } - } - - template = gst_element_class_get_pad_template ( - GST_ELEMENT_GET_CLASS (priv->audio_output), "sink%d"); - - pad = gst_element_request_pad (priv->audio_output, - template, NULL, NULL); - - if (pad == NULL) - { - g_warning ("Could not get sink pad from sink"); - return NULL; - } - - return pad; - -error: - gst_element_set_locked_state (priv->audio_output, TRUE); - gst_element_set_state (priv->audio_output, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output); - priv->audio_output = NULL; - -error_add_output: - - return NULL; -} - -static gboolean -empathy_streamed_media_window_update_timer (gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - gchar *str; - gdouble time_; - - time_ = g_timer_elapsed (priv->timer, NULL); - - /* Translators: number of minutes:seconds the caller has been connected */ - str = g_strdup_printf (_("Connected — %d:%02dm"), (int) time_ / 60, - (int) time_ % 60); - empathy_streamed_media_window_status_message (self, str); - g_free (str); - - return TRUE; -} - -static void -display_error (EmpathyStreamedMediaWindow *self, - EmpathyTpStreamedMedia *call, - const gchar *img, - const gchar *title, - const gchar *desc, - const gchar *details) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GtkWidget *info_bar; - GtkWidget *content_area; - GtkWidget *hbox; - GtkWidget *vbox; - GtkWidget *image; - GtkWidget *label; - gchar *txt; - - /* Create info bar */ - info_bar = gtk_info_bar_new_with_buttons (GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, - NULL); - - gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING); - - content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); - - /* hbox containing the image and the messages vbox */ - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_container_add (GTK_CONTAINER (content_area), hbox); - - /* Add image */ - image = gtk_image_new_from_icon_name (img, GTK_ICON_SIZE_DIALOG); - gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); - - /* vbox containing the main message and the details expander */ - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3); - gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); - - /* Add text */ - txt = g_strdup_printf ("<b>%s</b>\n%s", title, desc); - - label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (label), txt); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - g_free (txt); - - gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); - - /* Add details */ - if (details != NULL) - { - GtkWidget *expander; - - expander = gtk_expander_new (_("Technical Details")); - - txt = g_strdup_printf ("<i>%s</i>", details); - - label = gtk_label_new (NULL); - gtk_label_set_markup (GTK_LABEL (label), txt); - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0); - g_free (txt); - - gtk_container_add (GTK_CONTAINER (expander), label); - gtk_box_pack_start (GTK_BOX (vbox), expander, TRUE, TRUE, 0); - } - - g_signal_connect (info_bar, "response", - G_CALLBACK (gtk_widget_destroy), NULL); - - gtk_box_pack_start (GTK_BOX (priv->errors_vbox), info_bar, - FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING); - gtk_widget_show_all (info_bar); -} - -static gchar * -media_stream_error_to_txt (EmpathyStreamedMediaWindow *self, - EmpathyTpStreamedMedia *call, - gboolean audio, - TpMediaStreamError error) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - const gchar *cm; - gchar *url; - gchar *result; - - switch (error) - { - case TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED: - if (audio) - return g_strdup_printf ( - _("%s's software does not understand any of the audio formats " - "supported by your computer"), - empathy_contact_get_alias (priv->contact)); - else - return g_strdup_printf ( - _("%s's software does not understand any of the video formats " - "supported by your computer"), - empathy_contact_get_alias (priv->contact)); - - case TP_MEDIA_STREAM_ERROR_CONNECTION_FAILED: - return g_strdup_printf ( - _("Can't establish a connection to %s. " - "One of you might be on a network that does not allow " - "direct connections."), - empathy_contact_get_alias (priv->contact)); - - case TP_MEDIA_STREAM_ERROR_NETWORK_ERROR: - return g_strdup (_("There was a failure on the network")); - - case TP_MEDIA_STREAM_ERROR_NO_CODECS: - if (audio) - return g_strdup (_("The audio formats necessary for this call " - "are not installed on your computer")); - else - return g_strdup (_("The video formats necessary for this call " - "are not installed on your computer")); - - case TP_MEDIA_STREAM_ERROR_INVALID_CM_BEHAVIOR: - cm = empathy_tp_streamed_media_get_connection_manager (call); - - url = g_strdup_printf ("http://bugs.freedesktop.org/enter_bug.cgi?" - "product=Telepathy&component=%s", cm); - - result = g_strdup_printf ( - _("Something unexpected happened in a Telepathy component. " - "Please <a href=\"%s\">report this bug</a> and attach " - "logs gathered from the 'Debug' window in the Help menu."), url); - - g_free (url); - return result; - - case TP_MEDIA_STREAM_ERROR_MEDIA_ERROR: - return g_strdup (_("There was a failure in the call engine")); - - case TP_MEDIA_STREAM_ERROR_EOS: - return g_strdup (_("The end of the stream was reached")); - - case TP_MEDIA_STREAM_ERROR_UNKNOWN: - default: - return NULL; - } -} - -static void -empathy_streamed_media_window_stream_error (EmpathyStreamedMediaWindow *self, - EmpathyTpStreamedMedia *call, - gboolean audio, - guint code, - const gchar *msg, - const gchar *icon, - const gchar *title) -{ - gchar *desc; - - desc = media_stream_error_to_txt (self, call, audio, code); - if (desc == NULL) - { - /* No description, use the error message. That's not great as it's not - * localized but it's better than nothing. */ - display_error (self, call, icon, title, msg, NULL); - } - else - { - display_error (self, call, icon, title, desc, msg); - g_free (desc); - } -} - -static void -empathy_streamed_media_window_audio_stream_error (EmpathyTpStreamedMedia *call, - guint code, - const gchar *msg, - EmpathyStreamedMediaWindow *self) -{ - empathy_streamed_media_window_stream_error (self, call, TRUE, code, msg, - "gnome-stock-mic", _("Can't establish audio stream")); -} - -static void -empathy_streamed_media_window_video_stream_error (EmpathyTpStreamedMedia *call, - guint code, - const gchar *msg, - EmpathyStreamedMediaWindow *self) -{ - empathy_streamed_media_window_stream_error (self, call, FALSE, code, msg, - "camera-web", _("Can't establish video stream")); -} - -static gboolean -empathy_streamed_media_window_connected (gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - EmpathyTpStreamedMedia *call; - gboolean can_send_video; - - empathy_sound_manager_stop (priv->sound_mgr, EMPATHY_SOUND_PHONE_OUTGOING); - - can_send_video = priv->video_input != NULL && priv->contact != NULL && - empathy_contact_can_voip_video (priv->contact); - - g_object_get (priv->handler, "tp-call", &call, NULL); - - tp_g_signal_connect_object (call, "notify::video-stream", - G_CALLBACK (empathy_streamed_media_window_video_stream_changed_cb), - self, 0); - - if (empathy_tp_streamed_media_has_dtmf (call)) - gtk_widget_set_sensitive (priv->dtmf_panel, TRUE); - - if (priv->video_input == NULL) - empathy_streamed_media_window_set_send_video (self, CAMERA_STATE_OFF); - - priv->sending_video = can_send_video ? - empathy_tp_streamed_media_is_sending_video (call) : FALSE; - - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on), - priv->sending_video && priv->video_input != NULL); - gtk_widget_set_sensitive (priv->tool_button_camera_on, can_send_video); - gtk_action_set_sensitive (priv->action_camera_on, can_send_video); - - gtk_action_set_sensitive (priv->redial, FALSE); - gtk_widget_set_sensitive (priv->redial_button, FALSE); - - gtk_widget_set_sensitive (priv->mic_button, TRUE); - - empathy_streamed_media_window_update_avatars_visibility (call, self); - - g_object_unref (call); - - g_mutex_lock (priv->lock); - - priv->timer_id = g_timeout_add_seconds (1, - empathy_streamed_media_window_update_timer, self); - - g_mutex_unlock (priv->lock); - - empathy_streamed_media_window_update_timer (self); - - gtk_action_set_sensitive (priv->menu_fullscreen, TRUE); - - return FALSE; -} - - -/* Called from the streaming thread */ -static gboolean -empathy_streamed_media_window_src_added_cb (EmpathyStreamedMediaHandler *handler, - GstPad *src, guint media_type, gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - gboolean retval = FALSE; - - GstPad *pad; - - g_mutex_lock (priv->lock); - - if (priv->call_state != CONNECTED) - { - g_timer_start (priv->timer); - priv->timer_id = g_idle_add (empathy_streamed_media_window_connected, self); - priv->call_state = CONNECTED; - } - - switch (media_type) - { - case TP_MEDIA_STREAM_TYPE_AUDIO: - pad = empathy_streamed_media_window_get_audio_sink_pad (self); - break; - case TP_MEDIA_STREAM_TYPE_VIDEO: - gtk_widget_hide (priv->remote_user_avatar_widget); - gtk_widget_show (priv->video_output); - pad = empathy_streamed_media_window_get_video_sink_pad (self); - break; - default: - g_assert_not_reached (); - } - - if (pad == NULL) - goto out; - - if (GST_PAD_LINK_FAILED (gst_pad_link (src, pad))) - g_warning ("Could not link %s sink pad", - media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video"); - else - retval = TRUE; - - gst_object_unref (pad); - - out: - - /* If no sink could be linked, try to add fakesink to prevent the whole call - * aborting */ - - if (!retval) - { - GstElement *fakesink = gst_element_factory_make ("fakesink", NULL); - - if (gst_bin_add (GST_BIN (priv->pipeline), fakesink)) - { - GstPad *sinkpad = gst_element_get_static_pad (fakesink, "sink"); - if (gst_element_set_state (fakesink, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE || - GST_PAD_LINK_FAILED (gst_pad_link (src, sinkpad))) - { - gst_element_set_locked_state (fakesink, TRUE); - gst_element_set_state (fakesink, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), fakesink); - } - else - { - DEBUG ("Could not link real sink, linked fakesink instead"); - } - gst_object_unref (sinkpad); - } - else - { - gst_object_unref (fakesink); - } - } - - - g_mutex_unlock (priv->lock); - - return TRUE; -} - -static gboolean -empathy_streamed_media_window_sink_added_cb (EmpathyStreamedMediaHandler *handler, - GstPad *sink, guint media_type, gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstPad *pad; - gboolean retval = FALSE; - - switch (media_type) - { - case TP_MEDIA_STREAM_TYPE_AUDIO: - if (!gst_bin_add (GST_BIN (priv->pipeline), priv->audio_input)) - { - g_warning ("Could not add audio source to pipeline"); - break; - } - - pad = gst_element_get_static_pad (priv->audio_input, "src"); - if (!pad) - { - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_input); - g_warning ("Could not get source pad from audio source"); - break; - } - - if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sink))) - { - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_input); - g_warning ("Could not link audio source to farsight"); - break; - } - - if (gst_element_set_state (priv->audio_input, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) - { - g_warning ("Could not start audio source"); - gst_element_set_state (priv->audio_input, GST_STATE_NULL); - gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_input); - break; - } - - retval = TRUE; - break; - case TP_MEDIA_STREAM_TYPE_VIDEO: - if (priv->video_input != NULL) - { - if (priv->video_tee != NULL) - { - pad = gst_element_get_request_pad (priv->video_tee, "src%d"); - if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sink))) - { - g_warning ("Could not link videp soure input pipeline"); - break; - } - gst_object_unref (pad); - } - - retval = TRUE; - } - break; - default: - g_assert_not_reached (); - } - - return retval; -} - -static void -empathy_streamed_media_window_remove_video_input (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstElement *preview; - - disable_camera (self); - - DEBUG ("remove video input"); - preview = empathy_video_widget_get_element ( - EMPATHY_VIDEO_WIDGET (priv->video_preview)); - - gst_element_set_state (priv->video_input, GST_STATE_NULL); - gst_element_set_state (priv->video_tee, GST_STATE_NULL); - gst_element_set_state (preview, GST_STATE_NULL); - - gst_bin_remove_many (GST_BIN (priv->pipeline), priv->video_input, - priv->video_tee, preview, NULL); - - g_object_unref (priv->video_input); - priv->video_input = NULL; - g_object_unref (priv->video_tee); - priv->video_tee = NULL; - gtk_widget_destroy (priv->video_preview); - priv->video_preview = NULL; - - gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE); - gtk_action_set_sensitive (priv->action_camera_on, FALSE); - gtk_widget_set_sensitive (priv->tool_button_camera_preview, FALSE); -} - -static void -start_call (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - priv->call_started = TRUE; - empathy_streamed_media_handler_start_call (priv->handler, - empathy_get_current_action_time ()); - - if (empathy_streamed_media_handler_has_initial_video (priv->handler)) - { - /* Enable 'send video' buttons and display the preview */ - gtk_toggle_tool_button_set_active ( - GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on), TRUE); - } -} - -static gboolean -empathy_streamed_media_window_bus_message (GstBus *bus, GstMessage *message, - gpointer user_data) -{ - EmpathyStreamedMediaWindow *self = EMPATHY_STREAMED_MEDIA_WINDOW (user_data); - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - GstState newstate; - - empathy_streamed_media_handler_bus_message (priv->handler, bus, message); - - switch (GST_MESSAGE_TYPE (message)) - { - case GST_MESSAGE_STATE_CHANGED: - if (GST_MESSAGE_SRC (message) == GST_OBJECT (priv->video_input)) - { - gst_message_parse_state_changed (message, NULL, &newstate, NULL); - if (newstate == GST_STATE_PAUSED) - empathy_streamed_media_window_setup_video_input (self); - } - if (GST_MESSAGE_SRC (message) == GST_OBJECT (priv->pipeline) && - !priv->call_started) - { - gst_message_parse_state_changed (message, NULL, &newstate, NULL); - if (newstate == GST_STATE_PAUSED) - { - gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); - priv->pipeline_playing = TRUE; - - if (priv->start_call_when_playing) - start_call (self); - } - } - break; - case GST_MESSAGE_ERROR: - { - GError *error = NULL; - GstElement *gst_error; - gchar *debug; - - gst_message_parse_error (message, &error, &debug); - gst_error = GST_ELEMENT (GST_MESSAGE_SRC (message)); - - g_message ("Element error: %s -- %s\n", error->message, debug); - - if (g_str_has_prefix (gst_element_get_name (gst_error), - VIDEO_INPUT_ERROR_PREFIX)) - { - /* Remove the video input and continue */ - if (priv->video_input != NULL) - empathy_streamed_media_window_remove_video_input (self); - gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); - } - else - { - empathy_streamed_media_window_disconnected (self, TRUE); - } - g_error_free (error); - g_free (debug); - } - case GST_MESSAGE_UNKNOWN: - case GST_MESSAGE_EOS: - case GST_MESSAGE_WARNING: - case GST_MESSAGE_INFO: - case GST_MESSAGE_TAG: - case GST_MESSAGE_BUFFERING: - case GST_MESSAGE_STATE_DIRTY: - case GST_MESSAGE_STEP_DONE: - case GST_MESSAGE_CLOCK_PROVIDE: - case GST_MESSAGE_CLOCK_LOST: - case GST_MESSAGE_NEW_CLOCK: - case GST_MESSAGE_STRUCTURE_CHANGE: - case GST_MESSAGE_STREAM_STATUS: - case GST_MESSAGE_APPLICATION: - case GST_MESSAGE_ELEMENT: - case GST_MESSAGE_SEGMENT_START: - case GST_MESSAGE_SEGMENT_DONE: - case GST_MESSAGE_DURATION: - case GST_MESSAGE_ANY: - default: - break; - } - - return TRUE; -} - -static void -empathy_streamed_media_window_update_avatars_visibility (EmpathyTpStreamedMedia *call, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (empathy_tp_streamed_media_is_receiving_video (call)) - { - gtk_widget_hide (priv->remote_user_avatar_widget); - gtk_widget_show (priv->video_output); - } - else - { - gtk_widget_hide (priv->video_output); - gtk_widget_show (priv->remote_user_avatar_widget); - } -} - -static void -call_handler_notify_tp_streamed_media_cb (EmpathyStreamedMediaHandler *handler, - GParamSpec *spec, - EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - EmpathyTpStreamedMedia *call; - - g_object_get (priv->handler, "tp-call", &call, NULL); - if (call == NULL) - return; - - tp_g_signal_connect_object (call, "audio-stream-error", - G_CALLBACK (empathy_streamed_media_window_audio_stream_error), self, 0); - tp_g_signal_connect_object (call, "video-stream-error", - G_CALLBACK (empathy_streamed_media_window_video_stream_error), self, 0); - - g_object_unref (call); -} - -static void -empathy_streamed_media_window_realized_cb (GtkWidget *widget, EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - EmpathyTpStreamedMedia *call; - - g_signal_connect (priv->handler, "conference-added", - G_CALLBACK (empathy_streamed_media_window_conference_added_cb), window); - g_signal_connect (priv->handler, "request-resource", - G_CALLBACK (empathy_streamed_media_window_request_resource_cb), window); - g_signal_connect (priv->handler, "closed", - G_CALLBACK (empathy_streamed_media_window_channel_closed_cb), window); - g_signal_connect (priv->handler, "src-pad-added", - G_CALLBACK (empathy_streamed_media_window_src_added_cb), window); - g_signal_connect (priv->handler, "sink-pad-added", - G_CALLBACK (empathy_streamed_media_window_sink_added_cb), window); - g_signal_connect (priv->handler, "stream-closed", - G_CALLBACK (empathy_streamed_media_window_channel_stream_closed_cb), window); - - g_object_get (priv->handler, "tp-call", &call, NULL); - if (call != NULL) - { - tp_g_signal_connect_object (call, "audio-stream-error", - G_CALLBACK (empathy_streamed_media_window_audio_stream_error), window, - 0); - tp_g_signal_connect_object (call, "video-stream-error", - G_CALLBACK (empathy_streamed_media_window_video_stream_error), window, - 0); - - g_object_unref (call); - } - else - { - /* tp-call doesn't exist yet, we'll connect signals once it has been - * set */ - g_signal_connect (priv->handler, "notify::tp-call", - G_CALLBACK (call_handler_notify_tp_streamed_media_cb), window); - } - - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); -} - -static gboolean -empathy_streamed_media_window_delete_cb (GtkWidget *widget, GdkEvent*event, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->pipeline != NULL) - { - if (priv->bus_message_source_id != 0) - { - g_source_remove (priv->bus_message_source_id); - priv->bus_message_source_id = 0; - } - - gst_element_set_state (priv->pipeline, GST_STATE_NULL); - } - - if (priv->call_state == CONNECTING) - empathy_sound_manager_stop (priv->sound_mgr, EMPATHY_SOUND_PHONE_OUTGOING); - - return FALSE; -} - -static void -show_controls (EmpathyStreamedMediaWindow *window, gboolean set_fullscreen) -{ - GtkWidget *menu; - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - menu = gtk_ui_manager_get_widget (priv->ui_manager, - "/menubar1"); - - if (set_fullscreen) - { - gtk_widget_hide (priv->sidebar); - gtk_widget_hide (menu); - gtk_widget_hide (priv->vbox); - gtk_widget_hide (priv->statusbar); - gtk_widget_hide (priv->toolbar); - } - else - { - if (priv->sidebar_was_visible_before_fs) - gtk_widget_show (priv->sidebar); - - gtk_widget_show (menu); - gtk_widget_show (priv->vbox); - gtk_widget_show (priv->statusbar); - gtk_widget_show (priv->toolbar); - - gtk_window_resize (GTK_WINDOW (window), priv->original_width_before_fs, - priv->original_height_before_fs); - } -} - -static void -show_borders (EmpathyStreamedMediaWindow *window, gboolean set_fullscreen) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox), - set_fullscreen ? 0 : CONTENT_HBOX_BORDER_WIDTH); - gtk_box_set_spacing (GTK_BOX (priv->content_hbox), - set_fullscreen ? 0 : CONTENT_HBOX_SPACING); - - if (priv->video_output != NULL) - { - gtk_box_set_child_packing (GTK_BOX (priv->content_hbox), - priv->video_output, TRUE, TRUE, - set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING, - GTK_PACK_START); - } - - gtk_box_set_child_packing (GTK_BOX (priv->content_hbox), - priv->vbox, TRUE, TRUE, - set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING, - GTK_PACK_START); -} - -static gboolean -empathy_streamed_media_window_state_event_cb (GtkWidget *widget, - GdkEventWindowState *event, EmpathyStreamedMediaWindow *window) -{ - if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) - { - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - gboolean set_fullscreen = event->new_window_state & - GDK_WINDOW_STATE_FULLSCREEN; - - if (set_fullscreen) - { - gboolean sidebar_was_visible; - GtkAllocation allocation; - gint original_width, original_height; - - gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); - original_width = allocation.width; - original_height = allocation.height; - - g_object_get (priv->sidebar, "visible", &sidebar_was_visible, NULL); - - priv->sidebar_was_visible_before_fs = sidebar_was_visible; - priv->original_width_before_fs = original_width; - priv->original_height_before_fs = original_height; - - if (priv->video_output_motion_handler_id == 0 && - priv->video_output != NULL) - { - priv->video_output_motion_handler_id = g_signal_connect ( - G_OBJECT (priv->video_output), "motion-notify-event", - G_CALLBACK (empathy_streamed_media_window_video_output_motion_notify), - window); - } - } - else - { - disconnect_video_output_motion_handler (window); - } - - empathy_streamed_media_window_fullscreen_set_fullscreen (priv->fullscreen, - set_fullscreen); - show_controls (window, set_fullscreen); - show_borders (window, set_fullscreen); - gtk_action_set_stock_id (priv->menu_fullscreen, - (set_fullscreen ? "gtk-leave-fullscreen" : "gtk-fullscreen")); - priv->is_fullscreen = set_fullscreen; - } - - return FALSE; -} - -static void -empathy_streamed_media_window_sidebar_toggled_cb (GtkToggleButton *toggle, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - GtkWidget *arrow; - int w, h, handle_size; - GtkAllocation allocation, sidebar_allocation; - - gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); - w = allocation.width; - h = allocation.height; - - gtk_widget_style_get (priv->pane, "handle_size", &handle_size, NULL); - - gtk_widget_get_allocation (priv->sidebar, &sidebar_allocation); - if (gtk_toggle_button_get_active (toggle)) - { - arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE); - gtk_widget_show (priv->sidebar); - w += sidebar_allocation.width + handle_size; - } - else - { - arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - w -= sidebar_allocation.width + handle_size; - gtk_widget_hide (priv->sidebar); - } - - gtk_button_set_image (GTK_BUTTON (priv->sidebar_button), arrow); - - if (w > 0 && h > 0) - gtk_window_resize (GTK_WINDOW (window), w, h); -} - -static void -empathy_streamed_media_window_set_send_video (EmpathyStreamedMediaWindow *window, - CameraState state) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - EmpathyTpStreamedMedia *call; - - priv->sending_video = (state == CAMERA_STATE_ON); - - if (state == CAMERA_STATE_PREVIEW || - state == CAMERA_STATE_ON) - { - /* When we start sending video, we want to show the video preview by - default. */ - display_video_preview (window, TRUE); - } - else - { - display_video_preview (window, FALSE); - } - - if (priv->call_state != CONNECTED) - return; - - g_object_get (priv->handler, "tp-call", &call, NULL); - DEBUG ("%s sending video", priv->sending_video ? "start": "stop"); - empathy_tp_streamed_media_request_video_stream_direction (call, priv->sending_video); - g_object_unref (call); -} - -static void -empathy_streamed_media_window_mic_toggled_cb (GtkToggleToolButton *toggle, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - gboolean active; - - active = (gtk_toggle_tool_button_get_active (toggle)); - - if (active) - { - empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (priv->audio_input), - priv->volume); - gtk_adjustment_set_value (priv->audio_input_adj, priv->volume * 100); - } - else - { - /* TODO, Instead of setting the input volume to 0 we should probably - * stop sending but this would cause the audio call to drop if both - * sides mute at the same time on certain CMs AFAIK. Need to revisit this - * in the future. GNOME #574574 - */ - empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (priv->audio_input), - 0); - gtk_adjustment_set_value (priv->audio_input_adj, 0); - } -} - -static void -empathy_streamed_media_window_sidebar_hidden_cb (EvSidebar *sidebar, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button), - FALSE); -} - -static void -empathy_streamed_media_window_sidebar_shown_cb (EvSidebar *sidebar, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button), - TRUE); -} - -static void -empathy_streamed_media_window_hangup_cb (gpointer object, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - empathy_streamed_media_handler_stop_call (priv->handler); - - if (empathy_streamed_media_window_disconnected (window, FALSE)) - gtk_widget_destroy (GTK_WIDGET (window)); -} - -static void -empathy_streamed_media_window_restart_call (EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - /* Remove error info bars */ - gtk_container_forall (GTK_CONTAINER (priv->errors_vbox), - (GtkCallback) gtk_widget_destroy, NULL); - - create_video_output_widget (window); - - g_signal_connect (G_OBJECT (priv->audio_input_adj), "value-changed", - G_CALLBACK (empathy_streamed_media_window_mic_volume_changed_cb), window); - - /* While the call was disconnected, the input volume might have changed. - * However, since the audio_input source was destroyed, its volume has not - * been updated during that time. That's why we manually update it here */ - empathy_streamed_media_window_mic_volume_changed_cb (priv->audio_input_adj, window); - - priv->outgoing = TRUE; - empathy_streamed_media_window_set_state_connecting (window); - - if (priv->pipeline_playing) - start_call (window); - else - /* call will be started when the pipeline is ready */ - priv->start_call_when_playing = TRUE; - - - empathy_streamed_media_window_setup_avatars (window, priv->handler); - - gtk_action_set_sensitive (priv->redial, FALSE); - gtk_widget_set_sensitive (priv->redial_button, FALSE); -} - -static void -empathy_streamed_media_window_redial_cb (gpointer object, - EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->call_state == CONNECTED) - priv->call_state = REDIALING; - - empathy_streamed_media_handler_stop_call (priv->handler); - - if (priv->call_state != CONNECTED) - empathy_streamed_media_window_restart_call (window); -} - -static void -empathy_streamed_media_window_fullscreen_cb (gpointer object, - EmpathyStreamedMediaWindow *window) -{ - empathy_streamed_media_window_fullscreen_toggle (window); -} - -static void -empathy_streamed_media_window_fullscreen_toggle (EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->is_fullscreen) - gtk_window_unfullscreen (GTK_WINDOW (window)); - else - gtk_window_fullscreen (GTK_WINDOW (window)); -} - -static gboolean -empathy_streamed_media_window_video_button_press_cb (GtkWidget *video_output, - GdkEventButton *event, EmpathyStreamedMediaWindow *window) -{ - if (event->button == 3 && event->type == GDK_BUTTON_PRESS) - { - empathy_streamed_media_window_video_menu_popup (window, event->button); - return TRUE; - } - - return FALSE; -} - -static gboolean -empathy_streamed_media_window_key_press_cb (GtkWidget *video_output, - GdkEventKey *event, EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->is_fullscreen && event->keyval == GDK_KEY_Escape) - { - /* Since we are in fullscreen mode, toggling will bring us back to - normal mode. */ - empathy_streamed_media_window_fullscreen_toggle (window); - return TRUE; - } - - return FALSE; -} - -static gboolean -empathy_streamed_media_window_video_output_motion_notify (GtkWidget *widget, - GdkEventMotion *event, EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->is_fullscreen) - { - empathy_streamed_media_window_fullscreen_show_popup (priv->fullscreen); - return TRUE; - } - return FALSE; -} - -static void -empathy_streamed_media_window_video_menu_popup (EmpathyStreamedMediaWindow *window, - guint button) -{ - GtkWidget *menu; - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - menu = gtk_ui_manager_get_widget (priv->ui_manager, - "/video-popup"); - gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, - button, gtk_get_current_event_time ()); - gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE); -} - -static void -empathy_streamed_media_window_status_message (EmpathyStreamedMediaWindow *window, - gchar *message) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->context_id == 0) - { - priv->context_id = gtk_statusbar_get_context_id ( - GTK_STATUSBAR (priv->statusbar), "voip call status messages"); - } - else - { - gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar), priv->context_id); - } - - gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), priv->context_id, - message); -} - -static void -empathy_streamed_media_window_volume_changed_cb (GtkScaleButton *button, - gdouble value, EmpathyStreamedMediaWindow *window) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (window); - - if (priv->audio_output == NULL) - return; - - empathy_audio_sink_set_volume (EMPATHY_GST_AUDIO_SINK (priv->audio_output), - value); -} - -/* block all the signals related to camera control widgets. This is useful - * when we are manually updating the UI and so don't want to fire the - * callbacks */ -static void -block_camera_control_signals (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_signal_handlers_block_by_func (priv->tool_button_camera_off, - tool_button_camera_off_toggled_cb, self); - g_signal_handlers_block_by_func (priv->tool_button_camera_preview, - tool_button_camera_preview_toggled_cb, self); - g_signal_handlers_block_by_func (priv->tool_button_camera_on, - tool_button_camera_on_toggled_cb, self); - g_signal_handlers_block_by_func (priv->action_camera_on, - action_camera_change_cb, self); -} - -static void -unblock_camera_control_signals (EmpathyStreamedMediaWindow *self) -{ - EmpathyStreamedMediaWindowPriv *priv = GET_PRIV (self); - - g_signal_handlers_unblock_by_func (priv->tool_button_camera_off, - tool_button_camera_off_toggled_cb, self); - g_signal_handlers_unblock_by_func (priv->tool_button_camera_preview, - tool_button_camera_preview_toggled_cb, self); - g_signal_handlers_unblock_by_func (priv->tool_button_camera_on, - tool_button_camera_on_toggled_cb, self); - g_signal_handlers_unblock_by_func (priv->action_camera_on, - action_camera_change_cb, self); -} diff --git a/src/empathy-streamed-media-window.h b/src/empathy-streamed-media-window.h deleted file mode 100644 index aae56d882..000000000 --- a/src/empathy-streamed-media-window.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * empathy-streamed-media-window.h - Header for EmpathyStreamedMediaWindow - * Copyright (C) 2008 Collabora Ltd. - * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __EMPATHY_STREAMED_MEDIA_WINDOW_H__ -#define __EMPATHY_STREAMED_MEDIA_WINDOW_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "empathy-streamed-media-handler.h" - -G_BEGIN_DECLS - -typedef struct _EmpathyStreamedMediaWindow EmpathyStreamedMediaWindow; -typedef struct _EmpathyStreamedMediaWindowClass EmpathyStreamedMediaWindowClass; - -struct _EmpathyStreamedMediaWindowClass { - GtkWindowClass parent_class; -}; - -struct _EmpathyStreamedMediaWindow { - GtkWindow parent; -}; - -GType empathy_streamed_media_window_get_type (void); - -/* TYPE MACROS */ -#define EMPATHY_TYPE_STREAMED_MEDIA_WINDOW \ - (empathy_streamed_media_window_get_type ()) -#define EMPATHY_STREAMED_MEDIA_WINDOW(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW, \ - EmpathyStreamedMediaWindow)) -#define EMPATHY_STREAMED_MEDIA_WINDOW_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW, \ - EmpathyStreamedMediaWindowClass)) -#define EMPATHY_IS_STREAMED_MEDIA_WINDOW(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW)) -#define EMPATHY_IS_STREAMED_MEDIA_WINDOW_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW)) -#define EMPATHY_STREAMED_MEDIA_WINDOW_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_STREAMED_MEDIA_WINDOW, \ - EmpathyStreamedMediaWindowClass)) - -EmpathyStreamedMediaWindow *empathy_streamed_media_window_new (EmpathyStreamedMediaHandler *handler); - -G_END_DECLS - -#endif /* #ifndef __EMPATHY_STREAMED_MEDIA_WINDOW_H__*/ diff --git a/src/empathy-streamed-media-window.ui b/src/empathy-streamed-media-window.ui deleted file mode 100644 index 5f1a16e8c..000000000 --- a/src/empathy-streamed-media-window.ui +++ /dev/null @@ -1,861 +0,0 @@ -<?xml version="1.0"?> -<!--Generated with glade3 3.4.5 on Mon Feb 16 12:31:56 2009 --> -<interface> - <object class="GtkUIManager" id="ui_manager"> - <child> - <object class="GtkActionGroup" id="actiongroup1"> - <child> - <object class="GtkAction" id="call"> - <property name="name">call</property> - <property name="label" translatable="yes">_Call</property> - </object> - </child> - <child> - <object class="GtkAction" id="menuhangup"> - <property name="icon_name">call-stop</property> - <property name="name">menuhangup</property> - <property name="label" translatable="yes">Hang up</property> - </object> - </child> - <child> - <object class="GtkAction" id="menuredial"> - <property name="stock_id">gtk-refresh</property> - <property name="name">menuredial</property> - <property name="label" translatable="yes">Redial</property> - <property name="sensitive">False</property> - </object> - </child> - <child> - <object class="GtkAction" id="camera"> - <property name="name">camera</property> - <property name="label" translatable="yes">V_ideo</property> - </object> - </child> - <child> - <object class="GtkRadioAction" id="action_camera_off"> - <property name="name">action_camera_off</property> - <property name="visible">True</property> - <property name="label" translatable="yes">Video Off</property> - <property name="draw_as_radio">True</property> - <property name="value">0</property> - <property name="current-value">0</property> - </object> - </child> - <child> - <object class="GtkRadioAction" id="action_camera_preview"> - <property name="name">action_camera_preview</property> - <property name="visible">True</property> - <property name="label" translatable="yes">Video Preview</property> - <property name="draw_as_radio">True</property> - <property name="group">action_camera_off</property> - <property name="value">1</property> - </object> - </child> - <child> - <object class="GtkRadioAction" id="action_camera_on"> - <property name="name">action_camera_on</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="label" translatable="yes">Video On</property> - <property name="draw_as_radio">True</property> - <property name="group">action_camera_off</property> - <property name="value">2</property> - </object> - </child> - <child> - <object class="GtkAction" id="view"> - <property name="name">view</property> - <property name="label" translatable="yes">_View</property> - </object> - </child> - <child> - <object class="GtkAction" id="menufullscreen"> - <property name="stock_id">gtk-fullscreen</property> - <property name="name">menufullscreen</property> - </object> - <accelerator key="F11"/> - </child> - </object> - </child> - <ui> - <menubar name="menubar1"> - <menu action="call"> - <menuitem action="menuhangup"/> - <menuitem action="menuredial"/> - </menu> - <menu action="camera"> - <menuitem action="action_camera_off"/> - <menuitem action="action_camera_preview"/> - <menuitem action="action_camera_on"/> - </menu> - <menu action="view"> - <menuitem action="menufullscreen"/> - </menu> - </menubar> - <popup name="video-popup"> - <menuitem name="menufullscreen" action="menufullscreen"/> - </popup> - </ui> - </object> - <object class="GtkVBox" id="call_window_vbox"> - <property name="visible">True</property> - <child> - <object class="GtkMenuBar" constructor="ui_manager" id="menubar1"> - <property name="visible">True</property> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="toolbar"> - <property name="visible">True</property> - <style> - <class name="primary-toolbar"/> - </style> - <child> - <object class="GtkToolButton" id="hangup"> - <property name="visible">True</property> - <property name="is_important">True</property> - <property name="label" translatable="yes">Hang up</property> - <property name="icon_name">call-stop</property> - <property name="tooltip_text" translatable="yes">Hang up current call</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="redial"> - <property name="visible">True</property> - <property name="is_important">True</property> - <property name="label" translatable="yes">Redial</property> - <property name="stock_id">gtk-refresh</property> - <property name="sensitive">False</property> - <property name="tooltip_text" translatable="yes">Call the contact again</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkSeparatorToolItem" id="toolbutton1"> - <property name="visible">True</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToggleToolButton" id="microphone"> - <property name="visible">True</property> - <property name="active">True</property> - <property name="label" translatable="yes">Send Audio</property> - <property name="icon_name">gnome-stock-mic</property> - <property name="tooltip_text" translatable="yes">Toggle audio transmission</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkSeparatorToolItem" id="camera_separator"> - <property name="visible">True</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToggleToolButton" id="camera_off"> - <property name="visible">True</property> - <property name="label" translatable="yes">Camera Off</property> - <property name="sensitive">True</property> - <property name="tooltip_text" translatable="yes">Disable camera and stop sending video</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToggleToolButton" id="camera_preview"> - <property name="visible">True</property> - <property name="label" translatable="yes">Preview</property> - <property name="icon_name">avatar-default</property> - <property name="sensitive">True</property> - <property name="tooltip_text" translatable="yes">Enable camera but don't send video</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToggleToolButton" id="camera_on"> - <property name="visible">True</property> - <property name="label" translatable="yes">Camera On</property> - <property name="icon_name">camera-web</property> - <property name="sensitive">False</property> - <property name="tooltip_text" translatable="yes">Enable camera and send video</property> - </object> - <packing> - <property name="homogeneous">True</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="errors_vbox"> - <property name="visible">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkHPaned" id="pane"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - </object> - <packing> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkStatusbar" id="statusbar"> - <property name="visible">True</property> - <property name="spacing">2</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">4</property> - </packing> - </child> - </object> - - <object class="GtkVBox" id="details_vbox"> - <property name="border_width">6</property> - <property name="visible">False</property> - <property name="homogeneous">False</property> - <property name="spacing">18</property> - <property name="orientation">vertical</property> - - <child> - <object class="GtkVBox" id="video_vbox"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">6</property> - <property name="orientation">vertical</property> - - <child> - <object class="GtkLabel" id="video_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Video</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - - <child> - <object class="GtkAlignment" id="alignment2"> - <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">1</property> - <property name="yscale">1</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">12</property> - <property name="right_padding">0</property> - - <child> - <object class="GtkGrid" id="video"> - <property name="visible">True</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - - <child> - <object class="GtkLabel" id="vcodec1_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Encoding Codec:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - - <child> - - <object class="GtkLabel" id="vcodec_encoding_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="vcodec2_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Decoding Codec:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - - <child> - - <object class="GtkLabel" id="vcodec_decoding_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">2</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="vrc_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Remote Candidate:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">3</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="video_remote_candidate_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">3</property> - </packing> - </child> - - <child> - <object class="GtkImage" id="video_remote_candidate_info_img"> - <property name="visible">True</property> - <property name="stock">gtk-info</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">3</property> - </packing> - </child> - - - <child> - <object class="GtkLabel" id="vlc_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Local Candidate:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">4</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="video_local_candidate_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">4</property> - </packing> - </child> - - <child> - <object class="GtkImage" id="video_local_candidate_info_img"> - <property name="visible">True</property> - <property name="stock">gtk-info</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">4</property> - </packing> - </child> - - </object> - </child> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - - <child> - <object class="GtkVBox" id="audio_vbox"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">6</property> - <property name="orientation">vertical</property> - - <child> - <object class="GtkLabel" id="bvwp_audio_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Audio</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - - <child> - <object class="GtkAlignment" id="alignment3"> - <property name="visible">True</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xscale">1</property> - <property name="yscale">1</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">12</property> - <property name="right_padding">0</property> - - <child> - <object class="GtkGrid" id="audio"> - <property name="visible">True</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - - <child> - <object class="GtkLabel" id="acodec1_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Encoding Codec:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="acodec_encoding_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="acodec2_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Decoding Codec:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="acodec_decoding_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="arc_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Remote Candidate:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="audio_remote_candidate_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">2</property> - </packing> - </child> - - <child> - <object class="GtkImage" id="audio_remote_candidate_info_img"> - <property name="visible">True</property> - <property name="stock">gtk-info</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">2</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="alc_label"> - <property name="visible">True</property> - <property name="label" translatable="yes">Local Candidate:</property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - <attributes> - <attribute name="style" value="PANGO_STYLE_ITALIC"/> - </attributes> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">3</property> - </packing> - </child> - - <child> - <object class="GtkLabel" id="audio_local_candidate_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Unknown</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">3</property> - </packing> - </child> - - <child> - <object class="GtkImage" id="audio_local_candidate_info_img"> - <property name="visible">True</property> - <property name="stock">gtk-info</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">3</property> - </packing> - </child> - - </object> - </child> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - </object> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - </object> - -</interface> |