#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 <libempathy-gtk/empathy-video-src.h>
#include <libempathy-gtk/empathy-ui-utils.h>
#include <libempathy-gtk/empathy-sound.h>
+#include <libempathy-gtk/empathy-geometry.h>
+#include <libempathy-gtk/empathy-images.h>
#define DEBUG_FLAG EMPATHY_DEBUG_VOIP
#include <libempathy/empathy-debug.h>
REDIALING
} CallState;
+typedef enum {
+ CAMERA_STATE_OFF = 0,
+ CAMERA_STATE_PREVIEW,
+ CAMERA_STATE_ON,
+} CameraState;
+
/* private structure */
typedef struct _EmpathyCallWindowPriv EmpathyCallWindowPriv;
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 *volume_button;
GtkWidget *redial_button;
GtkWidget *mic_button;
- GtkWidget *camera_button;
GtkWidget *toolbar;
GtkWidget *pane;
- GtkAction *always_show_preview;
- GtkAction *send_video;
GtkAction *redial;
GtkAction *menu_fullscreen;
+ GtkAction *action_camera;
+ GtkAction *action_camera_preview;
+ 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 */
GMutex *lock;
gboolean call_started;
gboolean sending_video;
+ CameraState camera_state;
EmpathyCallWindowFullscreen *fullscreen;
gboolean is_fullscreen;
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;
};
#define GET_PRIV(o) \
static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle,
EmpathyCallWindow *window);
-static void empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle,
- EmpathyCallWindow *window);
-
static void empathy_call_window_set_send_video (EmpathyCallWindow *window,
gboolean send);
-static void empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle,
- EmpathyCallWindow *window);
-
-static void empathy_call_window_always_show_preview_toggled_cb (
- GtkToggleAction *toggle, EmpathyCallWindow *window);
-
static void empathy_call_window_mic_toggled_cb (
GtkToggleToolButton *toggle, EmpathyCallWindow *window);
empathy_call_window_volume_changed_cb (GtkScaleButton *button,
gdouble value, EmpathyCallWindow *window);
+static void block_camera_control_signals (EmpathyCallWindow *self);
+static void unblock_camera_control_signals (EmpathyCallWindow *self);
+
static void
empathy_call_window_setup_toolbar (EmpathyCallWindow *self)
{
EmpathyCallWindowPriv *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. */
EmpathyCallWindowPriv *priv = GET_PRIV (self);
gdouble volume;
- if (priv->audio_input == NULL)
- return;
-
volume = gtk_adjustment_get_value (adj)/100.0;
/* Don't store the volume because of muting */
}
static void
-empathy_call_window_setup_remote_frame (GstBus *bus, EmpathyCallWindow *self)
+create_video_output_widget (EmpathyCallWindow *self)
{
EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ GstBus *bus;
- /* Initializing all the content (UI and output gst elements) related to the
- remote contact */
- priv->remote_user_output_hbox = gtk_hbox_new (FALSE, 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);
+ 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);
g_signal_connect (G_OBJECT (priv->video_output), "button-press-event",
G_CALLBACK (empathy_call_window_video_button_press_cb), self);
- gtk_container_add (GTK_CONTAINER (priv->remote_user_output_frame),
- priv->remote_user_output_hbox);
+ g_object_unref (bus);
+}
+
+static void
+create_audio_output (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ g_assert (priv->audio_output == NULL);
priv->audio_output = empathy_audio_sink_new ();
gst_object_ref (priv->audio_output);
gst_object_sink (priv->audio_output);
}
static void
-empathy_call_window_setup_self_frame (GstBus *bus, EmpathyCallWindow *self)
+create_video_input (EmpathyCallWindow *self)
{
EmpathyCallWindowPriv *priv = GET_PRIV (self);
- /* Initializing all the content (UI and input gst elements) related to the
- self contact, except for the video preview widget. This widget is only
- initialized when the "show video preview" option is activated */
- priv->self_user_output_hbox = gtk_hbox_new (FALSE, 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);
-
+ 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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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);
- empathy_signal_connect_weak (priv->audio_input, "peak-level-changed",
+ tp_g_signal_connect_object (priv->audio_input, "peak-level-changed",
G_CALLBACK (empathy_call_window_audio_input_level_changed_cb),
- G_OBJECT (self));
+ self, 0);
}
static void
-empathy_call_window_setup_video_preview (EmpathyCallWindow *window)
+add_video_preview_to_pipeline (EmpathyCallWindow *self)
{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
GstElement *preview;
- GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
- if (priv->video_preview != NULL)
+ 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))
{
- /* Since the video preview and the video tee are initialized and freed
- at the same time, if one is initialized, then the other one should
- be too. */
- g_assert (priv->video_tee != NULL);
+ 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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ GstBus *bus;
+
+ g_assert (priv->video_preview == NULL);
g_assert (priv->video_tee == NULL);
- priv->video_tee = gst_element_factory_make ("tee", NULL);
- gst_object_ref (priv->video_tee);
- gst_object_sink (priv->video_tee);
+ 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, NULL);
+
gtk_box_pack_start (GTK_BOX (priv->self_user_output_hbox),
priv->video_preview, TRUE, TRUE, 0);
- preview = empathy_video_widget_get_element (
- EMPATHY_VIDEO_WIDGET (priv->video_preview));
- gst_bin_add_many (GST_BIN (priv->pipeline), priv->video_input,
- priv->video_tee, preview, NULL);
- gst_element_link_many (priv->video_input, priv->video_tee,
- preview, NULL);
+ 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 (EmpathyCallWindow *window,
+ gboolean play)
+{
+ EmpathyCallWindowPriv *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;
- gst_element_set_state (preview, GST_STATE_PLAYING);
- gst_element_set_state (priv->video_input, GST_STATE_PLAYING);
- gst_element_set_state (priv->video_tee, GST_STATE_PLAYING);
+ 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 the preview and hide the self avatar */
DEBUG ("Show video preview");
- if (priv->video_preview == NULL)
- empathy_call_window_setup_video_preview (self);
+ play_camera (self, TRUE);
gtk_widget_show (priv->video_preview);
gtk_widget_hide (priv->self_user_avatar_widget);
}
DEBUG ("Show self avatar");
if (priv->video_preview != NULL)
- gtk_widget_hide (priv->video_preview);
+ {
+ gtk_widget_hide (priv->video_preview);
+ play_camera (self, FALSE);
+ }
gtk_widget_show (priv->self_user_avatar_widget);
}
}
{
EmpathyCallWindowPriv *priv = GET_PRIV (window);
- empathy_call_window_status_message (window, _("Connecting..."));
+ empathy_call_window_status_message (window, _("Connecting…"));
priv->call_state = CONNECTING;
if (priv->outgoing)
EMPATHY_SOUND_PHONE_OUTGOING, MS_BETWEEN_RING);
}
+static void
+disable_camera (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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_call_window_set_send_video (self, FALSE);
+
+ 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),
+ CAMERA_STATE_OFF);
+ unblock_camera_control_signals (self);
+
+ priv->camera_state = CAMERA_STATE_OFF;
+}
+
+static void
+tool_button_camera_off_toggled_cb (GtkToggleToolButton *toggle,
+ EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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_call_window_set_send_video (self, FALSE);
+
+ 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),
+ CAMERA_STATE_PREVIEW);
+ unblock_camera_control_signals (self);
+
+ priv->camera_state = CAMERA_STATE_PREVIEW;
+}
+
+static void
+tool_button_camera_preview_toggled_cb (GtkToggleToolButton *toggle,
+ EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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_call_window_set_send_video (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_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),
+ CAMERA_STATE_ON);
+ unblock_camera_control_signals (self);
+
+ priv->camera_state = CAMERA_STATE_ON;
+}
+
+static void
+tool_button_camera_on_toggled_cb (GtkToggleToolButton *toggle,
+ EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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,
+ EmpathyCallWindow *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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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_call_window_bus_message, self);
+
+ g_object_unref (bus);
+}
+
+
static void
empathy_call_window_init (EmpathyCallWindow *self)
{
GtkWidget *h;
GtkWidget *arrow;
GtkWidget *page;
- GstBus *bus;
gchar *filename;
GKeyFile *keyfile;
GError *error = NULL;
"statusbar", &priv->statusbar,
"redial", &priv->redial_button,
"microphone", &priv->mic_button,
- "camera", &priv->camera_button,
"toolbar", &priv->toolbar,
- "send_video", &priv->send_video,
"menuredial", &priv->redial,
- "always_show_preview", &priv->always_show_preview,
"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_off", &priv->action_camera,
+ "action_camera_preview", &priv->action_camera_preview,
NULL);
g_free (filename);
"menuredial", "activate", empathy_call_window_redial_cb,
"redial", "clicked", empathy_call_window_redial_cb,
"microphone", "toggled", empathy_call_window_mic_toggled_cb,
- "camera", "toggled", empathy_call_window_camera_toggled_cb,
- "send_video", "toggled", empathy_call_window_send_video_toggled_cb,
- "always_show_preview", "toggled",
- empathy_call_window_always_show_preview_toggled_cb,
"menufullscreen", "activate", empathy_call_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_off", "changed", action_camera_change_cb,
NULL);
priv->lock = g_mutex_new ();
CONTENT_HBOX_BORDER_WIDTH);
gtk_paned_pack1 (GTK_PANED (priv->pane), priv->content_hbox, TRUE, FALSE);
- priv->pipeline = gst_pipeline_new (NULL);
- bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
- priv->bus_message_source_id = gst_bus_add_watch (bus,
- empathy_call_window_bus_message, self);
+ /* 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_hbox_new (FALSE, 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_hbox_new (FALSE, 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_audio_output (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;
+
keyfile = g_key_file_new ();
filename = empathy_file_lookup ("element-properties", "data");
if (g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
}
g_free (filename);
-
- 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);
- empathy_call_window_setup_remote_frame (bus, self);
-
- 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->vbox = gtk_vbox_new (FALSE, 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_call_window_setup_self_frame (bus, self);
empathy_call_window_setup_toolbar (self);
- g_object_unref (bus);
-
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",
"show", G_CALLBACK (empathy_call_window_sidebar_shown_cb), self);
gtk_paned_pack2 (GTK_PANED (priv->pane), priv->sidebar, FALSE, FALSE);
- priv->dtmf_panel = empathy_call_window_create_dtmf (self);
- empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Dialpad"),
- priv->dtmf_panel);
-
- gtk_widget_set_sensitive (priv->dtmf_panel, FALSE);
-
page = empathy_call_window_create_audio_input (self);
empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Audio input"),
page);
empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Video input"),
page);
+ priv->dtmf_panel = empathy_call_window_create_dtmf (self);
+ empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Dialpad"),
+ priv->dtmf_panel);
+
+ gtk_widget_set_sensitive (priv->dtmf_panel, FALSE);
+
+
gtk_widget_show_all (top_vbox);
gtk_widget_hide (priv->sidebar);
g_object_ref (priv->ui_manager);
g_object_unref (gui);
+
+ empathy_geometry_bind (GTK_WINDOW (self), "call-window");
}
/* Instead of specifying a width and a height, we specify only one size. That's
if (pixbuf_avatar == NULL)
{
- pixbuf_avatar = empathy_pixbuf_from_icon_name_sized ("stock_person",
- size);
+ 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
empathy_call_window_setup_avatars (self, priv->handler);
empathy_call_window_set_state_connecting (self);
+
+ if (!empathy_call_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()). */
}
static void empathy_call_window_dispose (GObject *object);
empathy_call_window_video_stream_changed_cb (EmpathyTpCall *call,
GParamSpec *property, EmpathyCallWindow *self)
{
+ DEBUG ("video stream changed");
empathy_call_window_update_avatars_visibility (call, self);
}
if (call != NULL)
{
- g_signal_handlers_disconnect_by_func (call,
- empathy_call_window_video_stream_changed_cb, object);
g_object_unref (call);
}
if (priv->handler != NULL)
- g_object_unref (priv->handler);
+ {
+ empathy_call_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;
g_object_unref (priv->video_tee);
priv->video_tee = NULL;
+ if (priv->liveadder != NULL)
+ gst_object_unref (priv->liveadder);
+ priv->liveadder = NULL;
+
if (priv->fsnotifier != NULL)
g_object_unref (priv->fsnotifier);
priv->fsnotifier = 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,
priv->video_output_motion_handler_id = 0;
}
- if (priv->bus_message_source_id != 0)
- {
- g_source_remove (priv->bus_message_source_id);
- priv->bus_message_source_id = 0;
- }
-
/* free any data held directly by the object here */
g_mutex_free (priv->lock);
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
- if (type != TP_MEDIA_STREAM_TYPE_VIDEO)
+ if (type != FS_MEDIA_TYPE_VIDEO)
return TRUE;
if (direction == FS_DIRECTION_RECV)
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;
-
g_signal_handlers_disconnect_by_func (priv->audio_input_adj,
empathy_call_window_mic_volume_changed_cb, self);
- if (priv->audio_output != NULL)
- g_object_unref (priv->audio_output);
- priv->audio_output = NULL;
-
if (priv->video_tee != NULL)
g_object_unref (priv->video_tee);
priv->video_tee = NULL;
priv->liveadder = 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
}
static gboolean
-empathy_call_window_disconnected (EmpathyCallWindow *self)
+empathy_call_window_disconnected (EmpathyCallWindow *self,
+ gboolean restart)
{
gboolean could_disconnect = FALSE;
EmpathyCallWindowPriv *priv = GET_PRIV (self);
- gboolean could_reset_pipeline = empathy_call_window_reset_pipeline (self);
+ gboolean could_reset_pipeline;
+
+ could_reset_pipeline = empathy_call_window_reset_pipeline (self);
if (priv->call_state == CONNECTING)
empathy_sound_stop (EMPATHY_SOUND_PHONE_OUTGOING);
if (could_reset_pipeline)
{
- gboolean initial_video = empathy_call_handler_has_initial_video (
- priv->handler);
g_mutex_lock (priv->lock);
g_timer_stop (priv->timer);
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_call_window_status_message (self, _("Disconnected"));
gtk_action_set_sensitive (priv->redial, TRUE);
gtk_widget_set_sensitive (priv->redial_button, TRUE);
- /* Reseting the send_video, camera_buton and mic_button to their
- initial state */
- gtk_widget_set_sensitive (priv->camera_button, FALSE);
+ /* Unsensitive the camera and mic button */
+ gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE);
gtk_widget_set_sensitive (priv->mic_button, FALSE);
- gtk_action_set_sensitive (priv->send_video, FALSE);
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video),
- initial_video);
- gtk_toggle_tool_button_set_active (
- GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), initial_video);
+
+ /* 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);
- gtk_widget_hide (priv->video_output);
+ /* destroy the video output; it will be recreated when we'll redial */
+ gtk_widget_destroy (priv->video_output);
+ priv->video_output = NULL;
+
gtk_widget_show (priv->remote_user_avatar_widget);
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;
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
- if (empathy_call_window_disconnected (self) && priv->call_state == REDIALING)
+ if (empathy_call_window_disconnected (self, TRUE) &&
+ priv->call_state == REDIALING)
empathy_call_window_restart_call (self);
}
{
EmpathyCallWindowPriv *priv = GET_PRIV (self);
GstPad *pad;
+ GstElement *output;
if (priv->funnel == NULL)
{
- GstElement *output;
-
output = empathy_video_widget_get_element (EMPATHY_VIDEO_WIDGET
(priv->video_output));
priv->funnel = gst_element_factory_make ("fsfunnel", NULL);
- gst_bin_add (GST_BIN (priv->pipeline), priv->funnel);
- gst_bin_add (GST_BIN (priv->pipeline), output);
+ 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;
+ }
- gst_element_link (priv->funnel, output);
+ if (gst_element_set_state (output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
+ {
+ g_warning ("Could not start video sink");
+ goto error_output_added;
+ }
- gst_element_set_state (priv->funnel, GST_STATE_PLAYING);
- gst_element_set_state (output, GST_STATE_PLAYING);
+ 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 */
{
EmpathyCallWindowPriv *priv = GET_PRIV (self);
GstPad *pad;
+ GstElement *filter;
+ GError *gerror = NULL;
if (priv->liveadder == NULL)
{
priv->liveadder = gst_element_factory_make ("liveadder", NULL);
- gst_bin_add (GST_BIN (priv->pipeline), priv->liveadder);
- gst_bin_add (GST_BIN (priv->pipeline), priv->audio_output);
+ if (!gst_bin_add (GST_BIN (priv->pipeline), priv->liveadder))
+ {
+ g_warning ("Could not add liveadder to the pipeline");
+ goto error_add_liveadder;
+ }
+ if (!gst_bin_add (GST_BIN (priv->pipeline), priv->audio_output))
+ {
+ g_warning ("Could not add audio sink to pipeline");
+ goto error_add_output;
+ }
+
+ if (gst_element_set_state (priv->liveadder, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
+ {
+ g_warning ("Could not start liveadder");
+ goto error;
+ }
+
+ if (gst_element_set_state (priv->audio_output, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
+ {
+ g_warning ("Could not start audio sink");
+ goto error;
+ }
+
+ if (GST_PAD_LINK_FAILED (
+ gst_element_link (priv->liveadder, priv->audio_output)))
+ {
+ g_warning ("Could not link liveadder to audio output");
+ goto error;
+ }
+ }
+
+ filter = gst_parse_bin_from_description (
+ "audioconvert ! audioresample ! audioconvert", TRUE, &gerror);
+ if (filter == NULL)
+ {
+ g_warning ("Could not make audio conversion filter: %s", gerror->message);
+ g_clear_error (&gerror);
+ goto error;
+ }
- gst_element_link (priv->liveadder, priv->audio_output);
+ if (!gst_bin_add (GST_BIN (priv->pipeline), filter))
+ {
+ g_warning ("Could not add audio conversion filter to pipeline");
+ gst_object_unref (filter);
+ goto error;
+ }
+
+ if (gst_element_set_state (filter, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
+ {
+ g_warning ("Could not start audio conversion filter");
+ goto error_filter;
+ }
- gst_element_set_state (priv->liveadder, GST_STATE_PLAYING);
- gst_element_set_state (priv->audio_output, GST_STATE_PLAYING);
+ if (!gst_element_link (filter, priv->liveadder))
+ {
+ g_warning ("Could not link audio conversion filter to liveadder");
+ goto error_filter;
}
- pad = gst_element_get_request_pad (priv->liveadder, "sink%d");
+ pad = gst_element_get_static_pad (filter, "sink");
+
+ if (pad == NULL)
+ {
+ g_warning ("Could not get sink pad from filter");
+ goto error_filter;
+ }
return pad;
+
+ error_filter:
+
+ gst_element_set_locked_state (filter, TRUE);
+ gst_element_set_state (filter, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN (priv->pipeline), filter);
+
+ error:
+
+ gst_element_set_locked_state (priv->liveadder, TRUE);
+ gst_element_set_locked_state (priv->audio_output, TRUE);
+
+ gst_element_set_state (priv->liveadder, GST_STATE_NULL);
+ gst_element_set_state (priv->audio_output, GST_STATE_NULL);
+
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->audio_output);
+
+ error_add_output:
+
+ gst_bin_remove (GST_BIN (priv->pipeline), priv->liveadder);
+
+ gst_element_set_locked_state (priv->liveadder, FALSE);
+ gst_element_set_locked_state (priv->audio_output, FALSE);
+
+ error_add_liveadder:
+
+ if (priv->liveadder != NULL)
+ {
+ gst_object_unref (priv->liveadder);
+ priv->liveadder = NULL;
+ }
+
+ return NULL;
}
static gboolean
"product=Telepathy&component=%s", cm);
result = g_strdup_printf (
- _("Something not expected happened in a Telepathy component. "
+ _("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_object_get (priv->handler, "tp-call", &call, NULL);
- g_signal_connect (call, "notify::video-stream",
- G_CALLBACK (empathy_call_window_video_stream_changed_cb), self);
+ tp_g_signal_connect_object (call, "notify::video-stream",
+ G_CALLBACK (empathy_call_window_video_stream_changed_cb),
+ self, 0);
if (empathy_tp_call_has_dtmf (call))
gtk_widget_set_sensitive (priv->dtmf_panel, TRUE);
priv->sending_video = can_send_video ?
empathy_tp_call_is_sending_video (call) : FALSE;
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video),
- priv->sending_video && priv->video_input != NULL);
gtk_toggle_tool_button_set_active (
- GTK_TOGGLE_TOOL_BUTTON (priv->camera_button),
+ GTK_TOGGLE_TOOL_BUTTON (priv->tool_button_camera_on),
priv->sending_video && priv->video_input != NULL);
- gtk_widget_set_sensitive (priv->camera_button, can_send_video);
- gtk_action_set_sensitive (priv->send_video, can_send_video);
+ gtk_widget_set_sensitive (priv->tool_button_camera_on, can_send_video);
gtk_action_set_sensitive (priv->redial, FALSE);
gtk_widget_set_sensitive (priv->redial_button, FALSE);
/* Called from the streaming thread */
-static void
+static gboolean
empathy_call_window_src_added_cb (EmpathyCallHandler *handler,
GstPad *src, guint media_type, gpointer user_data)
{
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ gboolean retval = FALSE;
GstPad *pad;
g_assert_not_reached ();
}
- gst_pad_link (src, pad);
+ 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
+ {
+ g_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;
}
-/* Called from the streaming thread */
-static void
+static gboolean
empathy_call_window_sink_added_cb (EmpathyCallHandler *handler,
GstPad *sink, guint media_type, gpointer user_data)
{
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
GstPad *pad;
+ gboolean retval = FALSE;
switch (media_type)
{
case TP_MEDIA_STREAM_TYPE_AUDIO:
- gst_bin_add (GST_BIN (priv->pipeline), priv->audio_input);
+ 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");
- gst_pad_link (pad, sink);
+ 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;
+ }
- gst_element_set_state (priv->audio_input, GST_STATE_PLAYING);
+ retval = TRUE;
break;
case TP_MEDIA_STREAM_TYPE_VIDEO:
if (priv->video_input != NULL)
{
- EmpathyTpCall *call;
- g_object_get (priv->handler, "tp-call", &call, NULL);
-
- if (empathy_tp_call_is_sending_video (call))
- {
- display_video_preview (self, TRUE);
- }
-
- g_object_unref (call);
-
if (priv->video_tee != NULL)
{
pad = gst_element_get_request_pad (priv->video_tee, "src%d");
- gst_pad_link (pad, sink);
+ 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
EmpathyCallWindowPriv *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));
gtk_widget_destroy (priv->video_preview);
priv->video_preview = NULL;
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), FALSE);
- gtk_toggle_tool_button_set_active (
- GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), FALSE);
- gtk_widget_set_sensitive (priv->camera_button, FALSE);
- gtk_action_set_sensitive (priv->send_video, FALSE);
-
- gtk_widget_show (priv->self_user_avatar_widget);
+ gtk_widget_set_sensitive (priv->tool_button_camera_on, FALSE);
+ gtk_widget_set_sensitive (priv->tool_button_camera_preview, FALSE);
}
+static void
+start_call (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+
+ priv->call_started = TRUE;
+ empathy_call_handler_start_call (priv->handler,
+ gtk_get_current_event_time ());
+
+ if (empathy_call_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_call_window_bus_message (GstBus *bus, GstMessage *message,
gst_message_parse_state_changed (message, NULL, &newstate, NULL);
if (newstate == GST_STATE_PAUSED)
{
- priv->call_started = TRUE;
- empathy_call_handler_start_call (priv->handler);
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
+ priv->pipeline_playing = TRUE;
+
+ if (priv->start_call_when_playing)
+ start_call (self);
}
}
break;
}
else
{
- empathy_call_window_disconnected (self);
+ empathy_call_window_disconnected (self, TRUE);
}
g_error_free (error);
g_free (debug);
return TRUE;
}
-static void
-empathy_call_window_update_self_avatar_visibility (EmpathyCallWindow *window)
-{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
-
- if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (priv->always_show_preview)))
- {
- if (priv->video_preview != NULL)
- {
- gtk_widget_hide (priv->self_user_avatar_widget);
- gtk_widget_show (priv->video_preview);
- }
- else
- {
- if (priv->video_preview != NULL)
- gtk_widget_hide (priv->video_preview);
-
- gtk_widget_show (priv->self_user_avatar_widget);
- }
- }
-}
-
static void
empathy_call_window_update_avatars_visibility (EmpathyTpCall *call,
EmpathyCallWindow *window)
gtk_widget_hide (priv->video_output);
gtk_widget_show (priv->remote_user_avatar_widget);
}
-
- empathy_call_window_update_self_avatar_visibility (window);
}
static void
if (call == NULL)
return;
- empathy_signal_connect_weak (call, "audio-stream-error",
- G_CALLBACK (empathy_call_window_audio_stream_error), G_OBJECT (self));
- empathy_signal_connect_weak (call, "video-stream-error",
- G_CALLBACK (empathy_call_window_video_stream_error), G_OBJECT (self));
+ tp_g_signal_connect_object (call, "audio-stream-error",
+ G_CALLBACK (empathy_call_window_audio_stream_error), self, 0);
+ tp_g_signal_connect_object (call, "video-stream-error",
+ G_CALLBACK (empathy_call_window_video_stream_error), self, 0);
g_object_unref (call);
}
g_object_get (priv->handler, "tp-call", &call, NULL);
if (call != NULL)
{
- empathy_signal_connect_weak (call, "audio-stream-error",
- G_CALLBACK (empathy_call_window_audio_stream_error), G_OBJECT (window));
- empathy_signal_connect_weak (call, "video-stream-error",
- G_CALLBACK (empathy_call_window_video_stream_error), G_OBJECT (window));
+ tp_g_signal_connect_object (call, "audio-stream-error",
+ G_CALLBACK (empathy_call_window_audio_stream_error), window,
+ 0);
+ tp_g_signal_connect_object (call, "video-stream-error",
+ G_CALLBACK (empathy_call_window_video_stream_error), window,
+ 0);
g_object_unref (call);
}
/* When we start sending video, we want to show the video preview by
default. */
- if (send)
- {
- display_video_preview (window, TRUE);
- }
-
- g_object_get (priv->handler, "tp-call", &call, NULL);
- empathy_tp_call_request_video_stream_direction (call, send);
- g_object_unref (call);
-}
-
-static void
-empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle,
- EmpathyCallWindow *window)
-{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
- gboolean active;
-
- if (priv->call_state != CONNECTED)
- return;
-
- active = (gtk_toggle_tool_button_get_active (toggle));
-
- if (priv->sending_video == active)
- return;
-
- empathy_call_window_set_send_video (window, active);
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active);
-}
-
-static void
-empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle,
- EmpathyCallWindow *window)
-{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
- gboolean active;
+ display_video_preview (window, send);
if (priv->call_state != CONNECTED)
return;
- active = (gtk_toggle_action_get_active (toggle));
-
- if (priv->sending_video == active)
- return;
-
- empathy_call_window_set_send_video (window, active);
- gtk_toggle_tool_button_set_active (
- GTK_TOGGLE_TOOL_BUTTON (priv->camera_button), active);
-}
-
-static void
-empathy_call_window_always_show_preview_toggled_cb (GtkToggleAction *toggle,
- EmpathyCallWindow *window)
-{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
-
- if (gtk_toggle_action_get_active (toggle))
- {
- display_video_preview (window, TRUE);
- }
- else
- {
- /* disable preview if we are not sending */
- if (!priv->sending_video)
- display_video_preview (window, FALSE);
- }
+ g_object_get (priv->handler, "tp-call", &call, NULL);
+ DEBUG ("%s sending video", send ? "start": "stop");
+ empathy_tp_call_request_video_stream_direction (call, send);
+ g_object_unref (call);
}
static void
EmpathyCallWindowPriv *priv = GET_PRIV (window);
gboolean active;
- if (priv->audio_input == NULL)
- return;
-
active = (gtk_toggle_tool_button_get_active (toggle));
if (active)
empathy_call_window_hangup_cb (gpointer object,
EmpathyCallWindow *window)
{
- if (empathy_call_window_disconnected (window))
+ EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+ empathy_call_handler_stop_call (priv->handler);
+
+ if (empathy_call_window_disconnected (window, FALSE))
gtk_widget_destroy (GTK_WIDGET (window));
}
static void
empathy_call_window_restart_call (EmpathyCallWindow *window)
{
- GstBus *bus;
EmpathyCallWindowPriv *priv = GET_PRIV (window);
- gtk_widget_destroy (priv->remote_user_output_hbox);
- gtk_widget_destroy (priv->self_user_output_hbox);
-
- priv->pipeline = gst_pipeline_new (NULL);
- bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
- priv->bus_message_source_id = gst_bus_add_watch (bus,
- empathy_call_window_bus_message, window);
-
- empathy_call_window_setup_remote_frame (bus, window);
- empathy_call_window_setup_self_frame (bus, window);
+ create_video_output_widget (window);
g_signal_connect (G_OBJECT (priv->audio_input_adj), "value-changed",
G_CALLBACK (empathy_call_window_mic_volume_changed_cb), window);
* been updated during that time. That's why we manually update it here */
empathy_call_window_mic_volume_changed_cb (priv->audio_input_adj, window);
- g_object_unref (bus);
-
- gtk_widget_show_all (priv->content_hbox);
-
- if (!empathy_call_handler_has_initial_video (priv->handler))
- gtk_widget_hide (priv->self_user_output_frame);
-
priv->outgoing = TRUE;
empathy_call_window_set_state_connecting (window);
- priv->call_started = TRUE;
- empathy_call_handler_start_call (priv->handler);
+ if (priv->pipeline_playing)
+ start_call (window);
+ else
+ /* call will be started when the pipeline is ready */
+ priv->start_call_when_playing = TRUE;
+
+
empathy_call_window_setup_avatars (window, priv->handler);
- gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
gtk_action_set_sensitive (priv->redial, FALSE);
gtk_widget_set_sensitive (priv->redial_button, FALSE);
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 (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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,
+ action_camera_change_cb, self);
+}
+
+static void
+unblock_camera_control_signals (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *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,
+ action_camera_change_cb, self);
+}