diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-06-15 17:47:06 +0800 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-06-15 17:47:06 +0800 |
commit | 909f3e3d892afc61e42143bf9182d6dec9f3ccb9 (patch) | |
tree | 0653659c3a13b832168fc2256b2756634617777d /src/empathy-call-window.c | |
parent | 3624ff9a9fc90161487431fd536cdc3fffb0bb57 (diff) | |
parent | e5989d0face9edde213e0530ba6c886d61a1276f (diff) | |
download | gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar.gz gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar.bz2 gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar.lz gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar.xz gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.tar.zst gsoc2013-empathy-909f3e3d892afc61e42143bf9182d6dec9f3ccb9.zip |
Merge commit 'jtellier/call-window-video-preview'
Diffstat (limited to 'src/empathy-call-window.c')
-rw-r--r-- | src/empathy-call-window.c | 325 |
1 files changed, 242 insertions, 83 deletions
diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c index 0ce80c97c..9946dd320 100644 --- a/src/empathy-call-window.c +++ b/src/empathy-call-window.c @@ -62,6 +62,9 @@ #define CONNECTING_STATUS_TEXT _("Connecting...") +/* If an video input error occurs, the error message will start with "v4l" */ +#define VIDEO_INPUT_ERROR_PREFIX "v4l" + G_DEFINE_TYPE(EmpathyCallWindow, empathy_call_window, GTK_TYPE_WINDOW) /* signal enum */ @@ -103,6 +106,7 @@ struct _EmpathyCallWindowPriv GtkWidget *camera_button; GtkWidget *toolbar; GtkWidget *pane; + GtkAction *show_preview; GtkAction *send_video; GtkAction *redial; GtkAction *menu_fullscreen; @@ -186,6 +190,9 @@ static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle, 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); @@ -229,6 +236,9 @@ static void empathy_call_window_restart_call (EmpathyCallWindow *window); static void empathy_call_window_status_message (EmpathyCallWindow *window, gchar *message); +static void empathy_call_window_update_avatars_visibility (EmpathyTpCall *call, + EmpathyCallWindow *window); + static gboolean empathy_call_window_bus_message (GstBus *bus, GstMessage *message, gpointer user_data); @@ -574,23 +584,14 @@ empathy_call_window_setup_self_frame (GstBus *bus, EmpathyCallWindow *self) EmpathyCallWindowPriv *priv = GET_PRIV (self); /* Initializing all the content (UI and input gst elements) related to the - self contact*/ - priv->video_tee = gst_element_factory_make ("tee", NULL); - gst_object_ref (priv->video_tee); - gst_object_sink (priv->video_tee); - + 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); - 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); - gtk_container_add (GTK_CONTAINER (priv->self_user_output_frame), priv->self_user_output_hbox); @@ -610,13 +611,42 @@ static void empathy_call_window_setup_video_preview (EmpathyCallWindow *window) { EmpathyCallWindowPriv *priv = GET_PRIV (window); + GstElement *preview; + GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); + + if (priv->video_preview != NULL) + { + /* 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); + return; + } - GstElement *preview = empathy_video_widget_get_element ( + 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); + + 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); + + g_object_unref (bus); + + 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); } static void @@ -642,6 +672,7 @@ empathy_call_window_init (EmpathyCallWindow *self) "toolbar", &priv->toolbar, "send_video", &priv->send_video, "menuredial", &priv->redial, + "show_preview", &priv->show_preview, "ui_manager", &priv->ui_manager, "menufullscreen", &priv->menu_fullscreen, NULL); @@ -823,14 +854,12 @@ empathy_call_window_got_self_contact_cb (EmpathyTpContactFactory *factory, } static void -empathy_call_window_constructed (GObject *object) +empathy_call_window_setup_avatars (EmpathyCallWindow *self, + EmpathyCallHandler *handler) { - EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); EmpathyCallWindowPriv *priv = GET_PRIV (self); - g_assert (priv->handler != NULL); - - g_object_get (priv->handler, "contact", &(priv->contact), NULL); + g_object_get (handler, "contact", &(priv->contact), NULL); if (priv->contact != NULL) { @@ -870,15 +899,34 @@ empathy_call_window_constructed (GObject *object) priv->remote_user_avatar_widget, MIN (REMOTE_CONTACT_AVATAR_DEFAULT_WIDTH, REMOTE_CONTACT_AVATAR_DEFAULT_HEIGHT)); - /* We hide the self avatar. It will be shown if a problem is - encountered when we try to send video. As for the remote avatar, it - is shown by default and will be hidden when we receive video from - the remote side. */ - gtk_widget_hide (priv->self_user_avatar_widget); + /* 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 +empathy_call_window_setup_video_preview_visibility (EmpathyCallWindow *self, + EmpathyCallHandler *handler) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (self); + gboolean initial_video = empathy_call_handler_has_initial_video (priv->handler); + + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), + initial_video); +} + +static void +empathy_call_window_constructed (GObject *object) +{ + EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); + EmpathyCallWindowPriv *priv = GET_PRIV (self); + + g_assert (priv->handler != NULL); + empathy_call_window_setup_avatars (self, priv->handler); + empathy_call_window_setup_video_preview_visibility (self, priv->handler); +} + static void empathy_call_window_dispose (GObject *object); static void empathy_call_window_finalize (GObject *object); @@ -940,9 +988,17 @@ empathy_call_window_class_init ( } +static void +empathy_call_window_video_stream_changed_cb (EmpathyTpCall *call, + GParamSpec *property, EmpathyCallWindow *self) +{ + empathy_call_window_update_avatars_visibility (call, self); +} + void empathy_call_window_dispose (GObject *object) { + EmpathyTpCall *call; EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object); EmpathyCallWindowPriv *priv = GET_PRIV (self); @@ -951,6 +1007,16 @@ empathy_call_window_dispose (GObject *object) priv->dispose_has_run = TRUE; + g_object_get (priv->handler, "tp-call", &call, NULL); + + 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); @@ -1069,10 +1135,32 @@ empathy_call_window_reset_pipeline (EmpathyCallWindow *self) 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; + + 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->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; + + if (priv->video_preview != NULL) + gtk_widget_destroy (priv->video_preview); + priv->video_preview = NULL; + priv->liveadder = NULL; priv->funnel = NULL; - g_object_unref (priv->pipeline); - priv->pipeline = NULL; return TRUE; } @@ -1217,18 +1305,33 @@ empathy_call_window_connected (gpointer user_data) 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); + if (empathy_tp_call_has_dtmf (call)) gtk_widget_set_sensitive (priv->dtmf_panel, TRUE); - if (priv->video_input != NULL) - { - gtk_widget_set_sensitive (priv->camera_button, TRUE); - gtk_action_set_sensitive (priv->send_video, TRUE); - } + if (priv->video_input == NULL) + empathy_call_window_set_send_video (self, FALSE); + + priv->sending_video = empathy_tp_call_is_sending_video (call); + + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), + priv->sending_video + || gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (priv->show_preview))); + 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), + priv->sending_video && priv->video_input != NULL); + gtk_widget_set_sensitive (priv->camera_button, priv->video_input != NULL); + gtk_action_set_sensitive (priv->send_video, priv->video_input != NULL); gtk_action_set_sensitive (priv->redial, FALSE); gtk_widget_set_sensitive (priv->redial_button, FALSE); + empathy_call_window_update_avatars_visibility (call, self); + g_object_unref (call); g_mutex_lock (priv->lock); @@ -1305,53 +1408,34 @@ empathy_call_window_sink_added_cb (EmpathyCallHandler *handler, case TP_MEDIA_STREAM_TYPE_VIDEO: if (priv->video_input != NULL) { - pad = gst_element_get_request_pad (priv->video_tee, "src%d"); - gst_pad_link (pad, sink); - } - break; - default: - g_assert_not_reached (); - } + EmpathyTpCall *call; + g_object_get (priv->handler, "tp-call", &call, NULL); -} + if (empathy_tp_call_is_sending_video (call)) + { + empathy_call_window_setup_video_preview (self); -static gboolean -empathy_gst_bin_has_child (GstBin *bin, GstElement *element) -{ - GstIterator *it; - gboolean ret = FALSE; - GstElement *item; + gtk_toggle_action_set_active ( + GTK_TOGGLE_ACTION (priv->show_preview), TRUE); + + if (priv->video_preview != NULL) + gtk_widget_show (priv->video_preview); + gtk_widget_hide (priv->self_user_avatar_widget); + } - it = gst_bin_iterate_recurse (bin); + g_object_unref (call); - for (;;) - { - switch (gst_iterator_next (it, (gpointer *)&item)) - { - case GST_ITERATOR_OK: - if (item == element) - { - gst_object_unref (GST_OBJECT (item)); - ret = TRUE; - goto out; - } - gst_object_unref (GST_OBJECT (item)); - break; - case GST_ITERATOR_RESYNC: - gst_iterator_resync (it); - break; - case GST_ITERATOR_ERROR: - g_assert_not_reached (); - /* fallthrough */ - case GST_ITERATOR_DONE: - goto out; - break; - } + if (priv->video_tee != NULL) + { + pad = gst_element_get_request_pad (priv->video_tee, "src%d"); + gst_pad_link (pad, sink); + } + } + break; + default: + g_assert_not_reached (); } - gst_iterator_free (it); -out: - return ret; } static void @@ -1374,8 +1458,15 @@ empathy_call_window_remove_video_input (EmpathyCallWindow *self) 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_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_hide (priv->video_preview); gtk_widget_show (priv->self_user_avatar_widget); } @@ -1414,19 +1505,21 @@ empathy_call_window_bus_message (GstBus *bus, GstMessage *message, 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 (priv->video_input != NULL && - empathy_gst_bin_has_child (GST_BIN (priv->video_input), - GST_ELEMENT (GST_MESSAGE_SRC (message)))) + if (g_str_has_prefix (gst_element_get_name (gst_error), + VIDEO_INPUT_ERROR_PREFIX)) { /* Remove the video input and continue */ - empathy_call_window_remove_video_input (self); - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + if (priv->video_input != NULL) + empathy_call_window_remove_video_input (self); + gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); } else { @@ -1443,6 +1536,48 @@ empathy_call_window_bus_message (GstBus *bus, GstMessage *message, } 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->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) +{ + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + if (empathy_tp_call_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); + } + + empathy_call_window_update_self_avatar_visibility (window); +} + +static void empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window) { EmpathyCallWindowPriv *priv = GET_PRIV (window); @@ -1458,8 +1593,6 @@ empathy_call_window_realized_cb (GtkWidget *widget, EmpathyCallWindow *window) g_signal_connect (priv->handler, "sink-pad-added", G_CALLBACK (empathy_call_window_sink_added_cb), window); - empathy_call_window_setup_video_preview (window); - gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); } @@ -1469,7 +1602,8 @@ empathy_call_window_delete_cb (GtkWidget *widget, GdkEvent*event, { EmpathyCallWindowPriv *priv = GET_PRIV (window); - gst_element_set_state (priv->pipeline, GST_STATE_NULL); + if (priv->pipeline != NULL) + gst_element_set_state (priv->pipeline, GST_STATE_NULL); return FALSE; } @@ -1615,6 +1749,17 @@ empathy_call_window_set_send_video (EmpathyCallWindow *window, EmpathyCallWindowPriv *priv = GET_PRIV (window); EmpathyTpCall *call; + priv->sending_video = send; + + /* When we start sending video, we want to show the video preview by + default. */ + if (send) + { + empathy_call_window_setup_video_preview (window); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), + TRUE); + } + g_object_get (priv->handler, "tp-call", &call, NULL); empathy_tp_call_request_video_stream_direction (call, send); g_object_unref (call); @@ -1631,7 +1776,6 @@ empathy_call_window_camera_toggled_cb (GtkToggleToolButton *toggle, if (priv->sending_video == active) return; - priv->sending_video = active; empathy_call_window_set_send_video (window, active); gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->send_video), active); @@ -1648,7 +1792,6 @@ empathy_call_window_send_video_toggled_cb (GtkToggleAction *toggle, if (priv->sending_video == active) return; - priv->sending_video = active; empathy_call_window_set_send_video (window, active); gtk_toggle_tool_button_set_active ( @@ -1659,7 +1802,21 @@ static void empathy_call_window_show_preview_toggled_cb (GtkToggleAction *toggle, EmpathyCallWindow *window) { - /* FIXME: Not implemented */ + gboolean show_preview_toggled; + EmpathyCallWindowPriv *priv = GET_PRIV (window); + + show_preview_toggled = gtk_toggle_action_get_active (toggle); + + if (show_preview_toggled) + { + empathy_call_window_setup_video_preview (window); + gtk_widget_show (priv->self_user_output_frame); + empathy_call_window_update_self_avatar_visibility (window); + } + else + { + gtk_widget_hide (priv->self_user_output_frame); + } } static void @@ -1733,12 +1890,14 @@ empathy_call_window_restart_call (EmpathyCallWindow *window) empathy_call_window_setup_remote_frame (bus, window); empathy_call_window_setup_self_frame (bus, window); - empathy_call_window_setup_video_preview (window); g_object_unref (bus); gtk_widget_show_all (priv->content_hbox); + gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_preview), + gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (priv->show_preview))); + empathy_call_window_status_message (window, CONNECTING_STATUS_TEXT); priv->call_started = TRUE; empathy_call_handler_start_call (priv->handler); |