#include <libempathy-gtk/empathy-audio-sink.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-sound-manager.h>
#include <libempathy-gtk/empathy-geometry.h>
#include <libempathy-gtk/empathy-images.h>
#include "empathy-call-window.h"
#include "empathy-call-window-fullscreen.h"
-#include "empathy-sidebar.h"
+#include "ev-sidebar.h"
#define BUTTON_ID "empathy-call-dtmf-button-id"
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;
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) \
static void empathy_call_window_mic_toggled_cb (
GtkToggleToolButton *toggle, EmpathyCallWindow *window);
-static void empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar,
+static void empathy_call_window_sidebar_hidden_cb (EvSidebar *sidebar,
EmpathyCallWindow *window);
-static void empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar,
+static void empathy_call_window_sidebar_shown_cb (EvSidebar *sidebar,
EmpathyCallWindow *window);
static void empathy_call_window_hangup_cb (gpointer object,
int i;
GQuark button_quark;
struct {
- gchar *label;
+ const gchar *label;
TpDTMFEvent event;
} dtmfbuttons[] = { { "1", TP_DTMF_EVENT_DIGIT_1 },
{ "2", TP_DTMF_EVENT_DIGIT_2 },
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 3);
priv->volume_progress_bar = gtk_progress_bar_new ();
- gtk_progress_bar_set_orientation (
- GTK_PROGRESS_BAR (priv->volume_progress_bar),
- GTK_PROGRESS_BOTTOM_TO_TOP);
+
+ 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);
priv->call_state = CONNECTING;
if (priv->outgoing)
- empathy_sound_start_playing (GTK_WIDGET (window),
+ empathy_sound_manager_start_playing (priv->sound_mgr, GTK_WIDGET (window),
EMPATHY_SOUND_PHONE_OUTGOING, MS_BETWEEN_RING);
}
"camera_on", &priv->tool_button_camera_on,
"action_camera_off", &priv->action_camera,
"action_camera_preview", &priv->action_camera_preview,
+ "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);
"action_camera_off", "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);
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 = empathy_sidebar_new ();
+ priv->sidebar = ev_sidebar_new ();
g_signal_connect (G_OBJECT (priv->sidebar),
"hide", G_CALLBACK (empathy_call_window_sidebar_hidden_cb), self);
g_signal_connect (G_OBJECT (priv->sidebar),
gtk_paned_pack2 (GTK_PANED (priv->pane), priv->sidebar, FALSE, FALSE);
page = empathy_call_window_create_audio_input (self);
- empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Audio input"),
- page);
+ ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "audio-input",
+ _("Audio input"), page);
page = empathy_call_window_create_video_input (self);
- empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Video input"),
- page);
+ ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "video-input",
+ _("Video input"), page);
priv->dtmf_panel = empathy_call_window_create_dtmf (self);
- empathy_sidebar_add_page (EMPATHY_SIDEBAR (priv->sidebar), _("Dialpad"),
- priv->dtmf_panel);
+ ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "dialpad",
+ _("Dialpad"), priv->dtmf_panel);
gtk_widget_set_sensitive (priv->dtmf_panel, FALSE);
+ ev_sidebar_add_page (EV_SIDEBAR (priv->sidebar), "details",
+ _("Details"), priv->details_vbox);
gtk_widget_show_all (top_vbox);
g_object_ref (priv->ui_manager);
g_object_unref (gui);
+ priv->sound_mgr = empathy_sound_manager_dup_singleton ();
+
empathy_geometry_bind (GTK_WINDOW (self), "call-window");
}
/* 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_name (priv->contact));
+ empathy_contact_get_alias (priv->contact));
gtk_window_set_title (GTK_WINDOW (self), tmp);
g_free (tmp);
}
GParamSpec *pspec, GtkWidget *avatar_widget)
{
int size;
+ GtkAllocation allocation;
- size = avatar_widget->allocation.height;
+ gtk_widget_get_allocation (avatar_widget, &allocation);
+ size = allocation.height;
if (size == 0)
{
gtk_widget_show (priv->remote_user_avatar_widget);
}
+static void
+update_send_codec (EmpathyCallWindow *self,
+ gboolean audio)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ FsCodec *codec;
+ GtkWidget *widget;
+ gchar *tmp;
+
+ if (audio)
+ {
+ codec = empathy_call_handler_get_send_audio_codec (priv->handler);
+ widget = priv->acodec_encoding_label;
+ }
+ else
+ {
+ codec = empathy_call_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)
+{
+ EmpathyCallWindow *self = user_data;
+
+ update_send_codec (self, TRUE);
+}
+
+static void
+send_video_codec_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EmpathyCallWindow *self = user_data;
+
+ update_send_codec (self, FALSE);
+}
+
+static void
+update_recv_codec (EmpathyCallWindow *self,
+ gboolean audio)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ GList *codecs, *l;
+ GtkWidget *widget;
+ GString *str = NULL;
+
+ if (audio)
+ {
+ codecs = empathy_call_handler_get_recv_audio_codecs (priv->handler);
+ widget = priv->acodec_decoding_label;
+ }
+ else
+ {
+ codecs = empathy_call_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)
+{
+ EmpathyCallWindow *self = user_data;
+
+ update_recv_codec (self, TRUE);
+}
+
+static void
+recv_video_codecs_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EmpathyCallWindow *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 (EmpathyCallWindow *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,
+ EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+ FsCandidate *candidate = NULL;
+
+ if (type == FS_MEDIA_TYPE_VIDEO)
+ {
+ /* Update remote candidate */
+ candidate = empathy_call_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_call_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_call_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_call_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_call_window_constructed (GObject *object)
{
}
/* 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_call_window_dispose (GObject *object);
priv->contact = NULL;
}
+ tp_clear_object (&priv->sound_mgr);
+
/* release any references held by the object here */
if (G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose)
G_OBJECT_CLASS (empathy_call_window_parent_class)->dispose (object);
}
-void
-empathy_call_window_finalize (GObject *object)
+static void
+disconnect_video_output_motion_handler (EmpathyCallWindow *self)
{
- EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
if (priv->video_output_motion_handler_id != 0)
priv->video_output_motion_handler_id);
priv->video_output_motion_handler_id = 0;
}
+}
+
+void
+empathy_call_window_finalize (GObject *object)
+{
+ EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object);
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+
+ disconnect_video_output_motion_handler (self);
/* free any data held directly by the object here */
g_mutex_free (priv->lock);
}
}
+static void
+reset_details_pane (EmpathyCallWindow *self)
+{
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
+
+ gtk_label_set_text (GTK_LABEL (priv->vcodec_encoding_label), _("Unknown"));
+ gtk_label_set_text (GTK_LABEL (priv->acodec_encoding_label), _("Unknown"));
+ gtk_label_set_text (GTK_LABEL (priv->vcodec_decoding_label), _("Unknown"));
+ gtk_label_set_text (GTK_LABEL (priv->acodec_decoding_label), _("Unknown"));
+}
+
static gboolean
empathy_call_window_disconnected (EmpathyCallWindow *self,
gboolean restart)
EmpathyCallWindowPriv *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_call_window_reset_pipeline (self);
if (priv->call_state == CONNECTING)
- empathy_sound_stop (EMPATHY_SOUND_PHONE_OUTGOING);
+ empathy_sound_manager_stop (priv->sound_mgr,
+ EMPATHY_SOUND_PHONE_OUTGOING);
if (priv->call_state != REDIALING)
priv->call_state = DISCONNECTED;
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;
return g_strdup_printf (
_("%s's software does not understand any of the audio formats "
"supported by your computer"),
- empathy_contact_get_name (priv->contact));
+ 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_name (priv->contact));
+ 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_name (priv->contact));
+ 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_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;
}
EmpathyTpCall *call;
gboolean can_send_video;
- empathy_sound_stop (EMPATHY_SOUND_PHONE_OUTGOING);
+ 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);
empathy_call_window_update_timer (self);
+ gtk_action_set_sensitive (priv->menu_fullscreen, TRUE);
+
return FALSE;
}
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;
}
}
if (priv->call_state == CONNECTING)
- empathy_sound_stop (EMPATHY_SOUND_PHONE_OUTGOING);
+ empathy_sound_manager_stop (priv->sound_mgr, EMPATHY_SOUND_PHONE_OUTGOING);
return FALSE;
}
set_fullscreen ? 0 : CONTENT_HBOX_BORDER_WIDTH);
gtk_box_set_spacing (GTK_BOX (priv->content_hbox),
set_fullscreen ? 0 : CONTENT_HBOX_SPACING);
- 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);
+
+ 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,
}
else
{
- 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;
- }
+ disconnect_video_output_motion_handler (window);
}
empathy_call_window_fullscreen_set_fullscreen (priv->fullscreen,
}
static void
-empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar,
+empathy_call_window_sidebar_hidden_cb (EvSidebar *sidebar,
EmpathyCallWindow *window)
{
EmpathyCallWindowPriv *priv = GET_PRIV (window);
}
static void
-empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar,
+empathy_call_window_sidebar_shown_cb (EvSidebar *sidebar,
EmpathyCallWindow *window)
{
EmpathyCallWindowPriv *priv = GET_PRIV (window);
{
EmpathyCallWindowPriv *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",
{
EmpathyCallWindowPriv *priv = GET_PRIV (window);
- if (priv->is_fullscreen && event->keyval == GDK_Escape)
+ if (priv->is_fullscreen && event->keyval == GDK_KEY_Escape)
{
/* Since we are in fullscreen mode, toggling will bring us back to
normal mode. */