Merge call branch from Elliot Fairweather with cleanups from Xavier Claessens.
authorXavier Claessens <xclaesse@src.gnome.org>
Fri, 15 Feb 2008 15:00:45 +0000 (15:00 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Fri, 15 Feb 2008 15:00:45 +0000 (15:00 +0000)
svn path=/trunk/; revision=632

docs/libempathy/libempathy.types
libempathy-gtk/empathy-call-window.c
libempathy-gtk/empathy-call-window.glade
libempathy-gtk/empathy-call-window.h
libempathy/empathy-tp-call.c
libempathy/empathy-tp-call.h
libempathy/empathy-utils.c
python/pyempathy/pyempathy.defs
python/pyempathy/pyempathy.override
python/pyempathygtk/pyempathygtk.defs
src/empathy-call-chandler.c

index 28706f44f7e2c546b1d4a341a6c2642d0393ef6a..657fa00675c596108fac78112d2741b948585bfe 100644 (file)
@@ -3,11 +3,11 @@ empathy_contact_manager_get_type
 empathy_reg_ex_type_get_type
 empathy_message_type_get_type
 empathy_capabilities_get_type
-empathy_tp_call_status_get_type
 empathy_filter_get_type
 empathy_idle_get_type
 empathy_log_manager_get_type
 empathy_message_get_gtype
+empathy_tp_call_status_get_type
 empathy_tp_call_get_type
 empathy_tp_chat_get_type
 empathy_tp_chatroom_get_type
index a1c7bd79906927d84644982ea8f54f95b99a6599..5cd62d1ce79a242960927a081da88ab2ba9cb1e1 100644 (file)
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2007 Elliot Fairweather
- * Copyright (C) 2007 Collabora Ltd.
+ *  Copyright (C) 2007 Elliot Fairweather
  *
- * 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 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.
+ *  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
+ *  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
  *
- * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
- *          Xavier Claessens <xclaesse@gmail.com>
+ *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
  */
 
-#include "config.h"
+#include <string.h>
 
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-helpers.h>
 
+#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mc-account-monitor.h>
+#include <libmissioncontrol/mission-control.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-tp-call.h>
+#include <libempathy/empathy-chandler.h>
 #include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
 
-#include "empathy-call-window.h"
-#include "empathy-ui-utils.h"
+#include <libempathy-gtk/empathy-call-window.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
 
 #define DEBUG_DOMAIN "CallWindow"
 
-typedef struct {
-       GtkWidget     *window;
-       GtkWidget     *input_volume_scale;
-       GtkWidget     *output_volume_scale;
-       GtkWidget     *input_mute_togglebutton;
-       GtkWidget     *output_mute_togglebutton;
-       GtkWidget     *preview_video_frame;
-       GtkWidget     *output_video_frame;
-       GtkWidget     *preview_video_socket;
-       GtkWidget     *output_video_socket;
-       GtkWidget     *send_video_checkbutton;
-
-       EmpathyTpCall *call;
+typedef struct 
+{
+  GtkWidget *window;
+  GtkWidget *status_label;
+  GtkWidget *start_call_button;
+  GtkWidget *end_call_button;
+  GtkWidget *input_volume_scale;
+  GtkWidget *output_volume_scale;
+  GtkWidget *input_mute_button;
+  GtkWidget *output_mute_button;
+  GtkWidget *preview_video_frame;
+  GtkWidget *output_video_frame;
+  GtkWidget *preview_video_socket;
+  GtkWidget *output_video_socket;
+  GtkWidget *video_button;
+  GtkWidget *output_video_label;
+
+  EmpathyTpCall *call;
+
+  GTimeVal start_time;
+  guint timeout_event_id;
+
+  gboolean is_drawing;
 } EmpathyCallWindow;
 
+static gboolean
+call_window_update_timer (gpointer data)
+{
+  EmpathyCallWindow *window = data;
+  GTimeVal current;
+  gchar *str;
+  glong now, then;
+  glong time, seconds, minutes, hours;
+
+  g_get_current_time (&current);
+
+  now = current.tv_sec;
+  then = (window->start_time).tv_sec;
+
+  time = now - then;
+
+  seconds = time % 60;
+  time /= 60;
+  minutes = time % 60;
+  time /= 60;
+  hours = time % 60;
+
+  if (hours > 0)
+    {
+      str = g_strdup_printf ("Connected  -  %02ld : %02ld : %02ld", hours,
+          minutes, seconds);
+    }
+  else
+    {
+      str = g_strdup_printf ("Connected  -  %02ld : %02ld", minutes, seconds);
+    }
+
+  gtk_label_set_text (GTK_LABEL (window->status_label), str);
+
+  g_free (str);
+
+  return TRUE;
+}
+
 static void
-call_window_output_volume_changed_cb (GtkWidget         *scale,
-                                     EmpathyCallWindow *window)
+call_window_stop_timeout (EmpathyCallWindow *window)
 {
-       guint volume;
+  GMainContext *context;
+  GSource *source;
+
+  context = g_main_context_default ();
+
+  empathy_debug (DEBUG_DOMAIN, "Timer stopped");
 
-       volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
-       empathy_tp_call_set_output_volume (window->call, volume);
+  if (window->timeout_event_id)
+    {
+      source = g_main_context_find_source_by_id (context,
+          window->timeout_event_id);
+      g_source_destroy (source);
+      window->timeout_event_id = 0;
+    }
 }
 
+static void
+call_window_set_output_video_is_drawing (EmpathyCallWindow *window,
+                                         gboolean is_drawing)
+{
+  GtkWidget* child;
+
+  child = gtk_bin_get_child (GTK_BIN (window->output_video_frame));
+
+  empathy_debug (DEBUG_DOMAIN,
+      "Setting output video is drawing - %d", is_drawing);
+
+  if (is_drawing)
+    {
+      if (!window->is_drawing)
+        {
+          if (child)
+            {
+              gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
+                  child);
+            }
+          gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+              window->output_video_socket);
+          gtk_widget_show (window->output_video_socket);
+          empathy_tp_call_add_output_video (window->call,
+              gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
+          window->is_drawing = is_drawing;
+        }
+    }
+  else
+    {
+      if (window->is_drawing)
+        {
+          empathy_tp_call_add_output_video (window->call, 0);
+          if (child)
+            {
+              gtk_container_remove (GTK_CONTAINER (window->output_video_frame),
+                  child);
+            }
+          gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+              window->output_video_label);
+          gtk_widget_show (window->output_video_label);
+          window->is_drawing = is_drawing;
+        }
+    }
+}
+
+static gboolean
+call_window_delete_event_cb (GtkWidget *widget,
+                             GdkEvent *event,
+                             EmpathyCallWindow *window)
+{
+  GtkWidget *dialog;
+  gint result;
+  guint status;
+
+  empathy_debug (DEBUG_DOMAIN, "Delete event occurred");
+
+  g_object_get (G_OBJECT (window->call), "status", &status, NULL);
+
+  if (status != EMPATHY_TP_CALL_STATUS_CLOSED)
+    {
+      dialog = gtk_message_dialog_new (GTK_WINDOW (window->window),
+          GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+          GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+          "This call will be ended. Continue?");
+
+      result = gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+
+      switch (result)
+        {
+        case GTK_RESPONSE_YES:
+          call_window_stop_timeout (window);
+          call_window_set_output_video_is_drawing (window, FALSE);
+          empathy_tp_call_close_channel (window->call);
+          empathy_tp_call_remove_preview_video (gtk_socket_get_id (GTK_SOCKET
+              (window->preview_video_socket)));
+          return FALSE;
+        default:
+          return TRUE;
+        }
+    }
+  else
+    {
+      empathy_tp_call_remove_preview_video (gtk_socket_get_id (GTK_SOCKET
+          (window->preview_video_socket)));
+      return FALSE;
+    }
+}
 
 static void
-call_window_output_mute_toggled_cb (GtkWidget         *button,
-                                   EmpathyCallWindow *window)
+call_window_video_button_toggled_cb (GtkWidget *button,
+                                     EmpathyCallWindow *window)
 {
-       gboolean is_muted;
+  gboolean is_sending;
+
+  is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+  empathy_debug (DEBUG_DOMAIN, "Send video toggled - %d", is_sending);
 
-       is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
-       empathy_tp_call_mute_output (window->call, is_muted);
+  empathy_tp_call_request_video_stream_direction (window->call, is_sending);
 }
 
+static void
+call_window_status_changed_cb (EmpathyTpCall *call,
+                               EmpathyCallWindow *window)
+{
+  EmpathyContact *contact;
+  guint status;
+  guint stream_state;
+  EmpathyTpCallStream *audio_stream;
+  EmpathyTpCallStream *video_stream;
+  gboolean is_incoming;
+  gchar *title;
+
+  g_object_get (G_OBJECT (window->call), "status", &status, NULL);
+  g_object_get (G_OBJECT (window->call), "audio-stream", &audio_stream, NULL);
+  g_object_get (G_OBJECT (window->call), "video-stream", &video_stream, NULL);
+
+  if (video_stream->state > audio_stream->state)
+    {
+      stream_state = video_stream->state;
+    }
+  else
+    {
+      stream_state = audio_stream->state;
+    }
+
+  empathy_debug (DEBUG_DOMAIN, "Status changed - status: %d, stream state: %d",
+      status, stream_state);
+
+  if (window->timeout_event_id)
+    {
+      call_window_stop_timeout (window);
+    }
+
+  if (status == EMPATHY_TP_CALL_STATUS_CLOSED)
+    {
+      gtk_label_set_text (GTK_LABEL (window->status_label), "Closed");
+      gtk_widget_set_sensitive (window->end_call_button, FALSE);
+      gtk_widget_set_sensitive (window->start_call_button, FALSE);
+
+      call_window_set_output_video_is_drawing (window, FALSE);
+    }
+  else if (stream_state == TP_MEDIA_STREAM_STATE_DISCONNECTED)
+    {
+      gtk_label_set_text (GTK_LABEL (window->status_label), "Disconnected");
+    }
+  else if (status == EMPATHY_TP_CALL_STATUS_PENDING)
+    {
+      g_object_get (G_OBJECT (window->call), "contact", &contact, NULL);
+
+      title = g_strdup_printf ("%s - Empathy Call",
+          empathy_contact_get_name (contact));
+      gtk_window_set_title (GTK_WINDOW (window->window), title);
+
+      gtk_label_set_text (GTK_LABEL (window->status_label), "Ringing");
+      gtk_widget_set_sensitive (window->end_call_button, TRUE);
+      gtk_widget_set_sensitive (window->video_button, TRUE);
+
+      g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
+      if (is_incoming)
+        {
+          gtk_widget_set_sensitive (window->start_call_button, TRUE);
+        }
+      else
+        {
+          g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
+              G_CALLBACK (call_window_video_button_toggled_cb),
+              window);
+        }
+    }
+  else if (status == EMPATHY_TP_CALL_STATUS_ACCEPTED)
+    {
+      if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTING)
+        {
+          gtk_label_set_text (GTK_LABEL (window->status_label), "Connecting");
+        }
+      else if (stream_state == TP_MEDIA_STREAM_STATE_CONNECTED)
+        {
+          if ((window->start_time).tv_sec == 0)
+            {
+              g_get_current_time (&(window->start_time));
+            }
+          window->timeout_event_id = g_timeout_add (1000,
+              call_window_update_timer, window);
+          empathy_debug (DEBUG_DOMAIN, "Timer started");
+        }
+    }
+}
 
 static void
-call_window_input_mute_toggled_cb (GtkWidget         *button,
-                                  EmpathyCallWindow *window)
+call_window_receiving_video_cb (EmpathyTpCall *call,
+                                gboolean receiving_video,
+                                EmpathyCallWindow *window)
 {
-       gboolean is_muted;
+  empathy_debug (DEBUG_DOMAIN, "Receiving video signal received");
 
-       is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
-       empathy_tp_call_mute_input (window->call, is_muted);
+  call_window_set_output_video_is_drawing (window, receiving_video);
 }
 
+static void
+call_window_sending_video_cb (EmpathyTpCall *call,
+                              gboolean sending_video,
+                              EmpathyCallWindow *window)
+{
+  empathy_debug (DEBUG_DOMAIN, "Sending video signal received");
+
+  g_signal_handlers_block_by_func (window->video_button,
+      call_window_video_button_toggled_cb, window);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (window->video_button),
+      sending_video);
+  g_signal_handlers_unblock_by_func (window->video_button,
+      call_window_video_button_toggled_cb, window);
+}
 
 static void
-call_window_send_video_toggled_cb (GtkWidget         *button,
-                                  EmpathyCallWindow *window)
+call_window_socket_realized_cb (GtkWidget *widget,
+                                EmpathyCallWindow *window)
 {
-       gboolean is_sending;
+  if (widget == window->preview_video_socket)
+    {
+      empathy_debug (DEBUG_DOMAIN, "Preview socket realized");
+      empathy_tp_call_add_preview_video (gtk_socket_get_id (GTK_SOCKET
+          (window->preview_video_socket)));
+    }
+  else
+    {
+      empathy_debug (DEBUG_DOMAIN, "Output socket realized");
+    }
+}
 
-       is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
-       empathy_tp_call_send_video (window->call, is_sending);
+static void
+call_window_start_call_button_clicked_cb (GtkWidget *widget,
+                                          EmpathyCallWindow *window)
+{
+  gboolean send_video;
+  gboolean is_incoming;
+
+  empathy_debug (DEBUG_DOMAIN, "Start call clicked");
+
+  gtk_widget_set_sensitive (window->start_call_button, FALSE);
+  g_object_get (G_OBJECT (window->call), "is-incoming", &is_incoming, NULL);
+  if (is_incoming)
+    {
+      empathy_tp_call_accept_incoming_call (window->call);
+      send_video = gtk_toggle_button_get_active
+          (GTK_TOGGLE_BUTTON (window->video_button));
+      empathy_tp_call_request_video_stream_direction (window->call, send_video);
+      g_signal_connect (GTK_OBJECT (window->video_button), "toggled",
+          G_CALLBACK (call_window_video_button_toggled_cb), window);
+    }
 }
 
 static void
-call_window_capabilities_notify_cb (EmpathyContact    *contact,
-                                   GParamSpec        *param,
-                                   EmpathyCallWindow *window)
+call_window_end_call_button_clicked_cb (GtkWidget *widget,
+                                        EmpathyCallWindow *window)
 {
-       EmpathyCapabilities capabilities;
+  empathy_debug (DEBUG_DOMAIN, "End call clicked");
 
-       capabilities = empathy_contact_get_capabilities (contact);
-       empathy_tp_call_request_streams (window->call,
-                                        capabilities & EMPATHY_CAPABILITIES_AUDIO,
-                                        capabilities & EMPATHY_CAPABILITIES_VIDEO);
+  call_window_set_output_video_is_drawing (window, FALSE);
+  empathy_tp_call_close_channel (window->call);
+  gtk_widget_set_sensitive (window->end_call_button, FALSE);
+  gtk_widget_set_sensitive (window->start_call_button, FALSE);
 }
 
 static void
-call_window_name_notify_cb (EmpathyContact    *contact,
-                           GParamSpec        *param,
-                           EmpathyCallWindow *window)
+call_window_output_volume_changed_cb (GtkWidget *scale,
+                                      EmpathyCallWindow *window)
 {
-       const gchar *name;
-       gchar       *title;
+  guint volume;
 
-       name = empathy_contact_get_name (contact);
-       title = g_strdup_printf (_("Call from %s"), name);
-       gtk_window_set_title (GTK_WINDOW (window->window), title);
-       g_free (title);
+  volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
+
+  empathy_debug (DEBUG_DOMAIN, "Output volume changed - %u", volume);
+
+  empathy_tp_call_set_output_volume (window->call, volume);
 }
 
 static void
-call_window_status_notify_cb (EmpathyTpCall     *call,
-                             GParamSpec        *param,
-                             EmpathyCallWindow *window)
-{
-       guint status;
-
-       status = empathy_tp_call_get_status (call);
-       empathy_debug (DEBUG_DOMAIN, "Status changed to %d",
-                      status);
-
-       if (status == EMPATHY_TP_CALL_STATUS_RINGING) {
-               if (empathy_tp_call_is_incoming (window->call)) {
-                       empathy_tp_call_accept (window->call);
-               } else {
-                       EmpathyContact *contact;
-
-                       contact = empathy_tp_call_get_contact (call);
-                       g_signal_connect (contact, "notify::capabilities",
-                                         G_CALLBACK (call_window_capabilities_notify_cb),
-                                         window);
-                       g_signal_connect (contact, "notify::name",
-                                         G_CALLBACK (call_window_name_notify_cb),
-                                         window);
-                       call_window_capabilities_notify_cb (contact, NULL, window);
-                       call_window_name_notify_cb (contact, NULL, window);
-               }
-       }
-
-       if (status == EMPATHY_TP_CALL_STATUS_RUNNING) {
-               empathy_tp_call_set_output_window (window->call,
-                       gtk_socket_get_id (GTK_SOCKET (window->output_video_socket)));
-       }
+call_window_output_mute_button_toggled_cb (GtkWidget *button,
+                                           EmpathyCallWindow *window)
+{
+  gboolean is_muted;
+
+  is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+  empathy_debug (DEBUG_DOMAIN, "Mute output toggled - %d", is_muted);
+
+  empathy_tp_call_mute_output (window->call, is_muted);
 }
 
 static void
-call_window_destroy_cb (GtkWidget         *widget,
-                       EmpathyCallWindow *window)
+call_window_input_mute_button_toggled_cb (GtkWidget *button,
+                                          EmpathyCallWindow *window)
 {
-       g_object_unref (window->call);
-       g_slice_free (EmpathyCallWindow, window);
+  gboolean is_muted;
+
+  is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+  empathy_debug (DEBUG_DOMAIN, "Mute input toggled - %d", is_muted);
+
+  empathy_tp_call_mute_input (window->call, is_muted);
+}
+
+static void
+call_window_destroy_cb (GtkWidget *widget,
+                        EmpathyCallWindow *window)
+{
+  g_signal_handlers_disconnect_by_func (window->call,
+      call_window_status_changed_cb, window);
+  g_signal_handlers_disconnect_by_func (window->call,
+      call_window_receiving_video_cb, window);
+  g_signal_handlers_disconnect_by_func (window->call,
+      call_window_sending_video_cb, window);
+
+  g_object_unref (window->call);
+  g_object_unref (window->output_video_socket);
+  g_object_unref (window->preview_video_socket);
+  g_object_unref (window->output_video_label);
+
+  g_slice_free (EmpathyCallWindow, window);
 }
 
 GtkWidget *
-empathy_call_window_show (EmpathyTpCall *call)
-{
-       EmpathyCallWindow *window;
-       GladeXML          *glade;
-
-       window = g_slice_new0 (EmpathyCallWindow);
-
-       glade = empathy_glade_get_file ("empathy-call-window.glade",
-                                       "window",
-                                       NULL,
-                                       "window", &window->window,
-                                       "input_volume_scale", &window->input_volume_scale,
-                                       "output_volume_scale", &window->output_volume_scale,
-                                       "input_mute_togglebutton", &window->input_mute_togglebutton,
-                                       "output_mute_togglebutton", &window->output_mute_togglebutton,
-                                       "preview_video_frame", &window->preview_video_frame,
-                                       "output_video_frame", &window->output_video_frame,
-                                       "send_video_checkbutton", &window->send_video_checkbutton,
-                                       NULL);
-
-       empathy_glade_connect (glade,
-                              window,
-                              "window", "destroy", call_window_destroy_cb,
-                              "input_mute_togglebutton", "toggled", call_window_input_mute_toggled_cb,
-                              "output_mute_togglebutton", "toggled", call_window_output_mute_toggled_cb,
-                              "output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
-                              "send_video_checkbutton", "toggled", call_window_send_video_toggled_cb,
-                              NULL);
-       g_object_unref (glade);
-
-       /* Set output window socket */
-       window->output_video_socket = gtk_socket_new ();
-       gtk_widget_show (window->output_video_socket);
-       gtk_container_add (GTK_CONTAINER (window->output_video_frame),
-                          window->output_video_socket);
-
-       /* Set preview window socket */
-       window->preview_video_socket = gtk_socket_new ();
-       gtk_widget_show (window->preview_video_socket);
-       gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
-                          window->preview_video_socket);
-
-       /* Setup TpCall */
-       window->call = g_object_ref (call);
-       empathy_tp_call_add_preview_window (window->call,
-               gtk_socket_get_id (GTK_SOCKET (window->preview_video_socket)));
-       g_signal_connect (window->call, "notify::status",
-                         G_CALLBACK (call_window_status_notify_cb),
-                         window);
-
-       gtk_widget_show (window->window);
-
-       return window->window;
+empathy_call_window_new (EmpathyTpCall *call)
+{
+  EmpathyCallWindow *window;
+  GladeXML *glade;
+  guint status;
+
+  g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), NULL);
+
+  window = g_slice_new0 (EmpathyCallWindow);
+  window->call = g_object_ref (call);
+
+  glade = empathy_glade_get_file ("empathy-call-window.glade",
+      "window",
+      NULL,
+      "window", &window->window,
+      "status_label", &window->status_label,
+      "start_call_button", &window->start_call_button,
+      "end_call_button", &window->end_call_button,
+      "input_volume_scale", &window->input_volume_scale,
+      "output_volume_scale", &window->output_volume_scale,
+      "input_mute_button", &window->input_mute_button,
+      "output_mute_button", &window->output_mute_button,
+      "preview_video_frame", &window->preview_video_frame,
+      "output_video_frame", &window->output_video_frame,
+      "video_button", &window->video_button,
+      NULL);
+
+  empathy_glade_connect (glade,
+      window,
+      "window", "destroy", call_window_destroy_cb,
+      "window", "delete_event", call_window_delete_event_cb,
+      "input_mute_button", "toggled", call_window_input_mute_button_toggled_cb,
+      "output_mute_button", "toggled", call_window_output_mute_button_toggled_cb,
+      "output_volume_scale", "value-changed", call_window_output_volume_changed_cb,
+      "start_call_button", "clicked", call_window_start_call_button_clicked_cb,
+      "end_call_button", "clicked", call_window_end_call_button_clicked_cb,
+      NULL);
+
+  g_object_unref (glade);
+
+  /* Output video label */
+  window->output_video_label = g_object_ref (gtk_label_new ("No video output"));
+  gtk_container_add (GTK_CONTAINER (window->output_video_frame),
+      window->output_video_label);
+  gtk_widget_show (window->output_video_label);
+
+  /* Output video socket */
+  window->output_video_socket = g_object_ref (gtk_socket_new ());
+  g_signal_connect (GTK_OBJECT (window->output_video_socket), "realize",
+      G_CALLBACK (call_window_socket_realized_cb), window);
+  gtk_widget_show (window->output_video_socket);
+
+  /* Preview video socket */
+  window->preview_video_socket = g_object_ref (gtk_socket_new ());
+  g_signal_connect (GTK_OBJECT (window->preview_video_socket), "realize",
+      G_CALLBACK (call_window_socket_realized_cb), window);
+  gtk_container_add (GTK_CONTAINER (window->preview_video_frame),
+      window->preview_video_socket);
+  gtk_widget_show (window->preview_video_socket);
+
+  g_signal_connect (G_OBJECT (window->call), "status-changed",
+      G_CALLBACK (call_window_status_changed_cb),
+      window);
+  g_signal_connect (G_OBJECT (window->call), "receiving-video",
+      G_CALLBACK (call_window_receiving_video_cb),
+      window);
+  g_signal_connect (G_OBJECT (window->call), "sending-video",
+      G_CALLBACK (call_window_sending_video_cb),
+      window);
+
+  window->is_drawing = FALSE;
+
+  g_object_get (G_OBJECT (window->call), "status", &status, NULL);
+
+  if (status == EMPATHY_TP_CALL_STATUS_READYING)
+    {
+      gtk_window_set_title (GTK_WINDOW (window->window), "Empathy Call");
+      gtk_label_set_text (GTK_LABEL (window->status_label), "Readying");
+    }
+
+  gtk_widget_show (window->window);
+
+  return window->window;
 }
 
index bc18952b6b96fa3547444268d2774ce21702857c..20b2760a1082135a7628e77e5af5e716c346fb46 100644 (file)
-<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
-
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.1 on Thu Jan 17 20:37:30 2008 -->
 <glade-interface>
-
-<widget class="GtkWindow" id="window">
-  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-  <property name="title" translatable="yes">Call</property>
-  <property name="type">GTK_WINDOW_TOPLEVEL</property>
-  <property name="window_position">GTK_WIN_POS_NONE</property>
-  <property name="modal">False</property>
-  <property name="resizable">True</property>
-  <property name="destroy_with_parent">False</property>
-  <property name="decorated">True</property>
-  <property name="skip_taskbar_hint">False</property>
-  <property name="skip_pager_hint">False</property>
-  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
-  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
-  <property name="focus_on_map">True</property>
-  <property name="urgency_hint">False</property>
-
-  <child>
-    <widget class="GtkHBox" id="hbox2">
-      <property name="visible">True</property>
-      <property name="homogeneous">False</property>
-      <property name="spacing">10</property>
-
-      <child>
-       <widget class="GtkFrame" id="frame1">
-         <property name="visible">True</property>
-         <property name="label_xalign">0</property>
-         <property name="label_yalign">0.5</property>
-         <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
-         <child>
-           <widget class="GtkAlignment" id="alignment1">
-             <property name="visible">True</property>
-             <property name="xalign">0</property>
-             <property name="yalign">0</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">0</property>
-             <property name="right_padding">0</property>
-
-             <child>
-               <widget class="GtkHBox" id="hbox3">
-                 <property name="visible">True</property>
-                 <property name="homogeneous">True</property>
-                 <property name="spacing">0</property>
-
-                 <child>
-                   <widget class="GtkVBox" id="vbox4">
-                     <property name="visible">True</property>
-                     <property name="homogeneous">False</property>
-                     <property name="spacing">0</property>
-
-                     <child>
-                       <widget class="GtkLabel" id="label2">
-                         <property name="visible">True</property>
-                         <property name="label" translatable="yes">Input</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">False</property>
-                         <property name="xalign">0.5</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>
-                       </widget>
-                       <packing>
-                         <property name="padding">5</property>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <widget class="GtkVScale" id="input_volume_scale">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="can_focus">True</property>
-                         <property name="draw_value">False</property>
-                         <property name="value_pos">GTK_POS_TOP</property>
-                         <property name="digits">1</property>
-                         <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
-                         <property name="inverted">True</property>
-                         <property name="adjustment">100 0 100 1 0 0</property>
-                       </widget>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">True</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <widget class="GtkToggleButton" id="input_mute_togglebutton">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="can_focus">True</property>
-                         <property name="label" translatable="yes">Mute</property>
-                         <property name="use_underline">True</property>
-                         <property name="relief">GTK_RELIEF_NORMAL</property>
-                         <property name="focus_on_click">True</property>
-                         <property name="active">False</property>
-                         <property name="inconsistent">False</property>
-                       </widget>
-                       <packing>
-                         <property name="padding">5</property>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-                   </widget>
-                   <packing>
-                     <property name="padding">5</property>
-                     <property name="expand">True</property>
-                     <property name="fill">True</property>
-                   </packing>
-                 </child>
-
-                 <child>
-                   <widget class="GtkVBox" id="vbox5">
-                     <property name="visible">True</property>
-                     <property name="homogeneous">False</property>
-                     <property name="spacing">0</property>
-
-                     <child>
-                       <widget class="GtkLabel" id="label3">
-                         <property name="visible">True</property>
-                         <property name="label" translatable="yes">Output</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">False</property>
-                         <property name="xalign">0.5</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>
-                       </widget>
-                       <packing>
-                         <property name="padding">5</property>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <widget class="GtkVScale" id="output_volume_scale">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="can_focus">True</property>
-                         <property name="draw_value">False</property>
-                         <property name="value_pos">GTK_POS_TOP</property>
-                         <property name="digits">1</property>
-                         <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
-                         <property name="inverted">True</property>
-                         <property name="adjustment">100 0 100 1 0 0</property>
-                       </widget>
-                       <packing>
-                         <property name="padding">0</property>
-                         <property name="expand">True</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-
-                     <child>
-                       <widget class="GtkToggleButton" id="output_mute_togglebutton">
-                         <property name="visible">True</property>
-                         <property name="sensitive">False</property>
-                         <property name="can_focus">True</property>
-                         <property name="label" translatable="yes">Mute</property>
-                         <property name="use_underline">True</property>
-                         <property name="relief">GTK_RELIEF_NORMAL</property>
-                         <property name="focus_on_click">True</property>
-                         <property name="active">False</property>
-                         <property name="inconsistent">False</property>
-                       </widget>
-                       <packing>
-                         <property name="padding">5</property>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
-                       </packing>
-                     </child>
-                   </widget>
-                   <packing>
-                     <property name="padding">5</property>
-                     <property name="expand">True</property>
-                     <property name="fill">True</property>
-                   </packing>
-                 </child>
-               </widget>
-             </child>
-           </widget>
-         </child>
-
-         <child>
-           <widget class="GtkLabel" id="label4">
-             <property name="visible">True</property>
-             <property name="label" translatable="yes">Volume</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.5</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>
-           </widget>
-           <packing>
-             <property name="type">label_item</property>
-           </packing>
-         </child>
-       </widget>
-       <packing>
-         <property name="padding">0</property>
-         <property name="expand">True</property>
-         <property name="fill">True</property>
-       </packing>
-      </child>
-
-      <child>
-       <widget class="GtkVBox" id="vbox2">
-         <property name="visible">True</property>
-         <property name="homogeneous">False</property>
-         <property name="spacing">0</property>
-
-         <child>
-           <widget class="GtkAspectFrame" id="output_video_frame">
-             <property name="width_request">352</property>
-             <property name="height_request">288</property>
-             <property name="visible">True</property>
-             <property name="label_xalign">0</property>
-             <property name="label_yalign">0.5</property>
-             <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-             <property name="xalign">0.5</property>
-             <property name="yalign">0.5</property>
-             <property name="ratio">1.22000002861</property>
-             <property name="obey_child">False</property>
-
-             <child>
-               <placeholder/>
-             </child>
-           </widget>
-           <packing>
-             <property name="padding">0</property>
-             <property name="expand">True</property>
-             <property name="fill">True</property>
-           </packing>
-         </child>
-       </widget>
-       <packing>
-         <property name="padding">0</property>
-         <property name="expand">True</property>
-         <property name="fill">True</property>
-       </packing>
-      </child>
-
-      <child>
-       <widget class="GtkVBox" id="vbox3">
-         <property name="visible">True</property>
-         <property name="homogeneous">False</property>
-         <property name="spacing">0</property>
-
-         <child>
-           <widget class="GtkAspectFrame" id="preview_video_frame">
-             <property name="width_request">176</property>
-             <property name="height_request">144</property>
-             <property name="visible">True</property>
-             <property name="label_xalign">0</property>
-             <property name="label_yalign">0.5</property>
-             <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-             <property name="xalign">0.5</property>
-             <property name="yalign">0.5</property>
-             <property name="ratio">1.22000002861</property>
-             <property name="obey_child">False</property>
-
-             <child>
-               <placeholder/>
-             </child>
-           </widget>
-           <packing>
-             <property name="padding">0</property>
-             <property name="expand">False</property>
-             <property name="fill">True</property>
-           </packing>
-         </child>
-
-         <child>
-           <widget class="GtkCheckButton" id="send_video_checkbutton">
-             <property name="visible">True</property>
-             <property name="can_focus">True</property>
-             <property name="label" translatable="yes">Send Video</property>
-             <property name="use_underline">True</property>
-             <property name="relief">GTK_RELIEF_NORMAL</property>
-             <property name="focus_on_click">True</property>
-             <property name="active">True</property>
-             <property name="inconsistent">False</property>
-             <property name="draw_indicator">True</property>
-           </widget>
-           <packing>
-             <property name="padding">10</property>
-             <property name="expand">False</property>
-             <property name="fill">False</property>
-           </packing>
-         </child>
-       </widget>
-       <packing>
-         <property name="padding">0</property>
-         <property name="expand">True</property>
-         <property name="fill">True</property>
-       </packing>
-      </child>
-    </widget>
-  </child>
-</widget>
-
+  <widget class="GtkWindow" id="window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <child>
+      <widget class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">10</property>
+        <property name="spacing">10</property>
+        <child>
+          <widget class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <widget class="GtkLabel" id="status_label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHSeparator" id="hseparator1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHBox" id="hbox2">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">10</property>
+            <child>
+              <widget class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label_xalign">0</property>
+                <child>
+                  <widget class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <child>
+                      <widget class="GtkHBox" id="hbox3">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="homogeneous">True</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="extension_events">GDK_EXTENSION_EVENTS_CURSOR</property>
+                            <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+                            <child>
+                              <widget class="GtkLabel" id="label2">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">Input</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="padding">5</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkVScale" id="input_volume_scale">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="adjustment">100 0 100 1 0 0</property>
+                                <property name="inverted">True</property>
+                                <property name="draw_value">False</property>
+                              </widget>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkToggleButton" id="input_mute_button">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">Mute</property>
+                                <property name="response_id">0</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="padding">5</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="padding">5</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkVBox" id="vbox5">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <child>
+                              <widget class="GtkLabel" id="label3">
+                                <property name="visible">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">Output</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="padding">5</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkVScale" id="output_volume_scale">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="adjustment">100 0 100 1 0 0</property>
+                                <property name="inverted">True</property>
+                                <property name="draw_value">False</property>
+                              </widget>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkToggleButton" id="output_mute_button">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="label" translatable="yes">Mute</property>
+                                <property name="response_id">0</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="padding">5</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                          <packing>
+                            <property name="padding">5</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Volume</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="type">label_item</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkAspectFrame" id="output_video_frame">
+                    <property name="width_request">352</property>
+                    <property name="height_request">288</property>
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="ratio">1.2200000286102295</property>
+                    <property name="obey_child">False</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkVBox" id="vbox3">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <widget class="GtkAspectFrame" id="preview_video_frame">
+                    <property name="width_request">176</property>
+                    <property name="height_request">144</property>
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label_xalign">0</property>
+                    <property name="ratio">1.2200000286102295</property>
+                    <property name="obey_child">False</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="video_button">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Send Video</property>
+                    <property name="response_id">0</property>
+                    <property name="active">True</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">10</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkHSeparator" id="hseparator2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="padding">5</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="start_call_button">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Start Call</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">10</property>
+                    <property name="pack_type">GTK_PACK_END</property>
+                    <property name="position">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="end_call_button">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">End Call</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="pack_type">GTK_PACK_END</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="padding">10</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
 </glade-interface>
index c8c6d7f0ed70385d149561042da2a3e00646d7db..7d65aaeaec79258f4caf2930cbbc8b21e2064585 100644 (file)
@@ -1,36 +1,34 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2007 Elliot Fairweather
- * Copyright (C) 2007 Collabora Ltd.
+ *  Copyright (C) 2007 Elliot Fairweather
  *
- * 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 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.
+ *  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
+ *  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
  *
- * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
- *          Xavier Claessens <xclaesse@gmail.com>
+ *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
  */
 
 #ifndef __EMPATHY_CALL_WINDOW_H__
 #define __EMPATHY_CALL_WINDOW_H__
 
+#include <gtk/gtk.h>
+
 #include <libempathy/empathy-tp-call.h>
 
 G_BEGIN_DECLS
 
-GtkWidget * empathy_call_window_show (EmpathyTpCall *call);
+GtkWidget *empathy_call_window_new (EmpathyTpCall *call);
 
 G_END_DECLS
 
 #endif /* __EMPATHY_CALL_WINDOW_H__ */
-
index 3e84679945ae43e37f4a10288a94f33d4a730095..1e2473e148afbe8082745cfa4b90e6322fefd6a0 100644 (file)
@@ -1,44 +1,45 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2007 Elliot Fairweather
- * Copyright (C) 2007 Collabora Ltd.
+ *  Copyright (C) 2007 Elliot Fairweather
  *
- * 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 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.
+ *  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
+ *  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
  *
- * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
- *          Xavier Claessens <xclaesse@gmail.com>
+ *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
  */
 
-#include "config.h"
+#include <string.h>
+#include <dbus/dbus-glib.h>
 
 #include <libtelepathy/tp-chan-type-streamed-media-gen.h>
+#include <libtelepathy/tp-connmgr.h>
 #include <libtelepathy/tp-helpers.h>
-#include <libtelepathy/tp-conn.h>
 
-#include <libmissioncontrol/mission-control.h>
+#include <libmissioncontrol/mc-account.h>
+
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-tp-group.h>
+#include <libempathy/empathy-utils.h>
 
-#include "empathy-tp-call.h"
-#include "empathy-tp-group.h"
-#include "empathy-utils.h"
-#include "empathy-debug.h"
-#include "empathy-enum-types.h"
 #include "tp-stream-engine-gen.h"
 
+#include "empathy-tp-call.h"
+
 #define DEBUG_DOMAIN "TpCall"
 
-#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_TP_CALL, EmpathyTpCallPriv))
+#define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE \
+    ((object), EMPATHY_TYPE_TP_CALL, EmpathyTpCallPriv))
 
 #define STREAM_ENGINE_BUS_NAME "org.freedesktop.Telepathy.StreamEngine"
 #define STREAM_ENGINE_OBJECT_PATH "/org/freedesktop/Telepathy/StreamEngine"
 
 typedef struct _EmpathyTpCallPriv EmpathyTpCallPriv;
 
-struct _EmpathyTpCallPriv {
-       TpChan              *tp_chan;
-       DBusGProxy          *streamed_iface;
-       DBusGProxy          *se_ch_proxy;
-       DBusGProxy          *se_proxy;
-       McAccount           *account;
-       EmpathyTpGroup      *group;
-       EmpathyContact      *contact;
-       EmpathyTpCallStatus  status;
-       gboolean             is_incoming;
-       guint                audio_stream;
-       guint                video_stream;
+struct _EmpathyTpCallPriv
+{
+  TpConn *connection;
+  TpChan *channel;
+  EmpathyTpGroup *group;
+  EmpathyContact *contact;
+  gboolean is_incoming;
+  guint status;
+
+  EmpathyTpCallStream *audio;
+  EmpathyTpCallStream *video;
 };
 
-static void empathy_tp_call_class_init (EmpathyTpCallClass *klass);
-static void empathy_tp_call_init       (EmpathyTpCall      *call);
-
-enum {
-       PROP_0,
-       PROP_ACCOUNT,
-       PROP_TP_CHAN,
-       PROP_STATUS
+enum
+{
+  STATUS_CHANGED_SIGNAL,
+  RECEIVING_VIDEO_SIGNAL,
+  SENDING_VIDEO_SIGNAL,
+  LAST_SIGNAL
 };
 
-enum {
-       DESTROY,
-       LAST_SIGNAL
+enum
+{
+  PROP_0,
+  PROP_CONNECTION,
+  PROP_CHANNEL,
+  PROP_CONTACT,
+  PROP_IS_INCOMING,
+  PROP_STATUS,
+  PROP_AUDIO_STREAM,
+  PROP_VIDEO_STREAM
 };
 
 static guint signals[LAST_SIGNAL];
@@ -81,575 +86,836 @@ static guint signals[LAST_SIGNAL];
 G_DEFINE_TYPE (EmpathyTpCall, empathy_tp_call, G_TYPE_OBJECT)
 
 static void
-tp_call_set_status (EmpathyTpCall       *call,
-                   EmpathyTpCallStatus  status)
+tp_call_stream_state_changed_cb (DBusGProxy *channel,
+                                 guint stream_id,
+                                 guint stream_state,
+                                 EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       priv->status = status;
-       g_object_notify (G_OBJECT (call), "status");
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  empathy_debug (DEBUG_DOMAIN,
+      "Stream state changed - stream id: %d, state state: %d",
+      stream_id, stream_state);
+
+  if (stream_id == priv->audio->id)
+    {
+      priv->audio->state = stream_state;
+    }
+  else if (stream_id == priv->video->id)
+    {
+      priv->video->state = stream_state;
+    }
+
+  g_signal_emit_by_name (call, "status-changed");
 }
 
 static void
-tp_call_set_property (GObject      *object,
-                     guint         prop_id,
-                     const GValue *value,
-                     GParamSpec   *pspec)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (object);
-
-       switch (prop_id) {
-       case PROP_ACCOUNT:
-               priv->account = g_object_ref (g_value_get_object (value));
-               break;
-       case PROP_TP_CHAN:
-               priv->tp_chan = g_object_ref (g_value_get_object (value));
-               break;
-       case PROP_STATUS:
-               tp_call_set_status (EMPATHY_TP_CALL (object),
-                                   g_value_get_enum (value));
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-               break;
-       }
+tp_call_identify_streams (EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  GPtrArray *stream_infos;
+  DBusGProxy *streamed_iface;
+  GError *error = NULL;
+  guint i;
+
+  empathy_debug (DEBUG_DOMAIN, "Identifying audio/video streams");
+
+  streamed_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+
+  if (!tp_chan_type_streamed_media_list_streams (streamed_iface, &stream_infos,
+        &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't list audio/video streams: %s",
+          error->message);
+      g_clear_error (&error);
+    }
+
+  for (i = 0; i < stream_infos->len; i++)
+    {
+      GValueArray *values;
+      guint stream_id;
+      guint stream_handle;
+      guint stream_type;
+      guint stream_state;
+      guint stream_direction;
+
+      values = g_ptr_array_index (stream_infos, i);
+      stream_id = g_value_get_uint (g_value_array_get_nth (values, 0));
+      stream_handle = g_value_get_uint (g_value_array_get_nth (values, 1));
+      stream_type = g_value_get_uint (g_value_array_get_nth (values, 2));
+      stream_state = g_value_get_uint (g_value_array_get_nth (values, 3));
+      stream_direction = g_value_get_uint (g_value_array_get_nth (values, 4));
+
+      switch (stream_type)
+        {
+        case TP_MEDIA_STREAM_TYPE_AUDIO:
+          empathy_debug (DEBUG_DOMAIN,
+              "Audio stream - id: %d, state: %d, direction: %d",
+              stream_id, stream_state, stream_direction);
+          priv->audio->exists = TRUE;
+          priv->audio->id = stream_id;
+          priv->audio->state = stream_state;
+          priv->audio->direction = stream_direction;
+          break;
+        case TP_MEDIA_STREAM_TYPE_VIDEO:
+          empathy_debug (DEBUG_DOMAIN,
+              "Video stream - id: %d, state: %d, direction: %d",
+              stream_id, stream_state, stream_direction);
+          priv->video->exists = TRUE;
+          priv->video->id = stream_id;
+          priv->video->state = stream_state;
+          priv->video->direction = stream_direction;
+          break;
+        default:
+          empathy_debug (DEBUG_DOMAIN, "Unknown stream type: %d",
+              stream_type);
+        }
+
+      g_value_array_free (values);
+    }
 }
 
 static void
-tp_call_get_property (GObject    *object,
-                     guint       prop_id,
-                     GValue     *value,
-                     GParamSpec *pspec)
+tp_call_stream_added_cb (DBusGProxy *channel,
+                         guint stream_id,
+                         guint contact_handle,
+                         guint stream_type,
+                         EmpathyTpCall *call)
 {
-  EmpathyTpCallPriv *priv = GET_PRIV (object);
+  empathy_debug (DEBUG_DOMAIN,
+      "Stream added - stream id: %d, contact handle: %d, stream type: %d",
+      stream_id, contact_handle, stream_type);
 
-       switch (prop_id) {
-       case PROP_ACCOUNT:
-               g_value_set_object (value, priv->account);
-               break;
-       case PROP_TP_CHAN:
-               g_value_set_object (value, priv->tp_chan);
-               break;
-       case PROP_STATUS:
-               g_value_set_enum (value, priv->status);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-               break;
-       }
+  tp_call_identify_streams (call);
 }
 
+
 static void
-tp_call_destroy_cb (TpChan        *call_chan,
-                   EmpathyTpCall *call)
+tp_call_stream_removed_cb (DBusGProxy *channel,
+                           guint stream_id,
+                           EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       empathy_debug (DEBUG_DOMAIN, "Channel Closed or CM crashed");
-
-       g_object_unref  (priv->tp_chan);
-       priv->tp_chan = NULL;
-       priv->streamed_iface = NULL;
-
-       g_signal_emit (call, signals[DESTROY], 0);
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  empathy_debug (DEBUG_DOMAIN, "Stream removed - stream id: %d", stream_id);
+
+  if (stream_id == priv->audio->id)
+    {
+      priv->audio->exists = FALSE;
+    }
+  else if (stream_id == priv->video->id)
+    {
+      priv->video->exists = FALSE;
+    }
 }
 
 static void
-tp_call_closed_cb (TpChan        *call_chan,
-                  EmpathyTpCall *call)
+tp_call_channel_closed_cb (TpChan *channel,
+                           EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       /* The channel is closed, do just like if the proxy was destroyed */
-       g_signal_handlers_disconnect_by_func (priv->tp_chan,
-                                             tp_call_destroy_cb,
-                                             call);
-       tp_call_destroy_cb (call_chan, call);
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  DBusGProxy *streamed_iface;
+  DBusGProxy *group_iface;
+
+  empathy_debug (DEBUG_DOMAIN, "Channel closed");
+
+  priv->status = EMPATHY_TP_CALL_STATUS_CLOSED;
+  g_signal_emit_by_name (call, "status-changed");
+
+  streamed_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+  group_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_GROUP_QUARK);
+
+  dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->channel), "Closed",
+      G_CALLBACK (tp_call_channel_closed_cb), (gpointer) call);
+  dbus_g_proxy_disconnect_signal (streamed_iface, "StreamStateChanged",
+      G_CALLBACK (tp_call_stream_state_changed_cb), (gpointer) call);
+  dbus_g_proxy_disconnect_signal (streamed_iface, "StreamAdded",
+      G_CALLBACK (tp_call_stream_added_cb), (gpointer) call);
+  dbus_g_proxy_disconnect_signal (streamed_iface, "StreamRemoved",
+      G_CALLBACK (tp_call_stream_removed_cb), (gpointer) call);
 }
 
 static void
-tp_call_stream_added_cb (DBusGProxy    *streamed_iface,
-                        guint          stream_id,
-                        guint          contact_handle,
-                        guint          stream_type,
-                        EmpathyTpCall *call)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       empathy_debug (DEBUG_DOMAIN, "Stream added: id=%d, stream_type=%d",
-                      stream_id, stream_type);
-
-       switch (stream_type) {
-       case TP_MEDIA_STREAM_TYPE_AUDIO:
-               priv->audio_stream = stream_id;
-               break;
-       case TP_MEDIA_STREAM_TYPE_VIDEO:
-               priv->video_stream = stream_id;
-               break;
-       default:
-               empathy_debug (DEBUG_DOMAIN, "Unknown stream type: %d", stream_type);
-       }
+tp_call_stream_direction_changed_cb (DBusGProxy *channel,
+                                     guint stream_id,
+                                     guint stream_direction,
+                                     guint flags,
+                                     EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  empathy_debug (DEBUG_DOMAIN,
+      "Stream direction changed - stream: %d, direction: %d",
+      stream_id, stream_direction);
+
+  if (stream_id == priv->audio->id)
+    {
+      priv->audio->direction = stream_direction;
+    }
+  else if (stream_id == priv->video->id)
+    {
+      priv->video->direction = stream_direction;
+
+      if (stream_direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE)
+        {
+          empathy_debug (DEBUG_DOMAIN, "RECEIVING");
+          g_signal_emit_by_name (call, "receiving-video", TRUE);
+        }
+      else
+        {
+          empathy_debug (DEBUG_DOMAIN, "NOT RECEIVING");
+          g_signal_emit_by_name (call, "receiving-video", FALSE);
+        }
+
+      if (stream_direction & TP_MEDIA_STREAM_DIRECTION_SEND)
+        {
+          empathy_debug (DEBUG_DOMAIN, "SENDING");
+          g_signal_emit_by_name (call, "sending-video", TRUE);
+        }
+      else
+        {
+          empathy_debug (DEBUG_DOMAIN, "NOT SENDING");
+          g_signal_emit_by_name (call, "sending-video", FALSE);
+        }
+    }
 }
 
+static void
+tp_call_request_streams_for_capabilities (EmpathyTpCall *call,
+                                          EmpathyCapabilities capabilities)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  DBusGProxy *streamed_iface;
+  GArray *stream_types;
+  guint handle;
+  guint stream_type;
+  GError *error = NULL;
+
+  empathy_debug (DEBUG_DOMAIN, "Requesting new stream for capabilities %d",
+      capabilities);
+
+  streamed_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+  stream_types = g_array_new (FALSE, FALSE, sizeof (guint));
+  handle = empathy_contact_get_handle (priv->contact);
+
+  if (capabilities & EMPATHY_CAPABILITIES_AUDIO)
+    {
+      stream_type = TP_MEDIA_STREAM_TYPE_AUDIO;
+      g_array_append_val (stream_types, stream_type);
+    }
+  if (capabilities & EMPATHY_CAPABILITIES_VIDEO)
+    {
+      stream_type = TP_MEDIA_STREAM_TYPE_VIDEO;
+      g_array_append_val (stream_types, stream_type);
+    }
+
+  if (!tp_chan_type_streamed_media_request_streams (streamed_iface, handle,
+        stream_types, NULL, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't request new stream: %s",
+          error->message);
+      g_clear_error (&error);
+    }
+
+  g_array_free (stream_types, TRUE);
+}
 
 static void
-tp_call_stream_removed_cb (DBusGProxy    *streamed_iface,
-                          guint          stream_id,
-                          EmpathyTpCall *call)
+tp_call_request_streams (EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  EmpathyCapabilities capabilities;
+  DBusGProxy *capabilities_iface;
+
+  empathy_debug (DEBUG_DOMAIN,
+      "Requesting appropriate audio/video streams from contact");
+
+  capabilities = empathy_contact_get_capabilities (priv->contact);
 
-       empathy_debug (DEBUG_DOMAIN, "Stream removed: %d", stream_id);
+  /* FIXME: SIP don't have capabilities interface but we know it supports
+   *        only audio and not video. */
+  capabilities_iface = tp_conn_get_interface (priv->connection,
+      TP_IFACE_QUARK_CONNECTION_INTERFACE_CAPABILITIES);
+  if (!capabilities_iface)
+    {
+      capabilities = EMPATHY_CAPABILITIES_AUDIO;
+    }
 
-       if (stream_id == priv->audio_stream) {
-               priv->audio_stream = 0;
-       }
-       else if (stream_id == priv->video_stream) {
-               priv->video_stream = 0;
-       }
+  tp_call_request_streams_for_capabilities (call, capabilities);
 }
 
 static void
-tp_call_list_streams_cb (DBusGProxy *proxy,
-                        GPtrArray  *streams,
-                        GError     *error,
-                        gpointer    user_data)
-{
-       guint i;
-
-       if (error) {
-               empathy_debug (DEBUG_DOMAIN, "Failed to list streams: %s",
-                              error->message);
-               return;
-       }
-
-       for (i = 0; i < streams->len; i++) {
-               GValueArray *values;
-               guint        stream_id;
-               guint        contact_handle;
-               guint        stream_type;
-
-               values = g_ptr_array_index (streams, i);
-               stream_id = g_value_get_uint (g_value_array_get_nth (values, 0));
-               contact_handle = g_value_get_uint (g_value_array_get_nth (values, 1));
-               stream_type = g_value_get_uint (g_value_array_get_nth (values, 2));
-
-               tp_call_stream_added_cb (proxy,
-                                        stream_id,
-                                        contact_handle,
-                                        stream_type,
-                                        user_data);
-       }
+tp_call_is_ready (EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  EmpathyContact *self_contact;
+  GList *members;
+  GList *local_pendings;
+  GList *remote_pendings;
+
+  if (priv->status > EMPATHY_TP_CALL_STATUS_READYING)
+    return;
+
+  members = empathy_tp_group_get_members (priv->group);
+  if (!members)
+    return;
+
+  self_contact = empathy_tp_group_get_self_contact (priv->group);
+  local_pendings = empathy_tp_group_get_local_pendings (priv->group);
+  remote_pendings = empathy_tp_group_get_remote_pendings (priv->group);
+
+  if (local_pendings &&
+      empathy_contact_equal (EMPATHY_CONTACT (((EmpathyPendingInfo *)
+            local_pendings->data)->member), self_contact))
+    {
+      empathy_debug (DEBUG_DOMAIN,
+          "Incoming call is ready - %p",
+          ((EmpathyPendingInfo *) local_pendings->data)->member);
+      priv->is_incoming = TRUE;
+      priv->contact = g_object_ref (members->data);
+    }
+  else if (remote_pendings &&
+      empathy_contact_equal (EMPATHY_CONTACT (members->data), self_contact))
+    {
+      empathy_debug (DEBUG_DOMAIN,
+          "Outgoing call is ready - %p", remote_pendings->data);
+      priv->is_incoming = FALSE;
+      priv->contact = g_object_ref (remote_pendings->data);
+      tp_call_request_streams (call);
+    }
+
+  g_object_unref (self_contact);
+  g_list_foreach (members, (GFunc) g_object_unref, NULL);
+  g_list_free (members);
+  g_list_foreach (local_pendings, (GFunc) empathy_pending_info_free, NULL);
+  g_list_free (local_pendings);
+  g_list_foreach (remote_pendings, (GFunc) g_object_unref, NULL);
+  g_list_free (remote_pendings);
+
+  if (priv->contact)
+    {
+      priv->status = EMPATHY_TP_CALL_STATUS_PENDING;
+      g_signal_emit (call, signals[STATUS_CHANGED_SIGNAL], 0);
+    }
 }
 
 static void
 tp_call_member_added_cb (EmpathyTpGroup *group,
-                        EmpathyContact *contact,
-                        EmpathyContact *actor,
-                        guint           reason,
-                        const gchar    *message,
-                        EmpathyTpCall  *call)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       empathy_debug (DEBUG_DOMAIN, "Members added %s (%d)",
-                      empathy_contact_get_id (contact),
-                      empathy_contact_get_handle (contact));
-
-       if (!priv->contact) {
-               if (!empathy_contact_is_user (contact)) {
-                       priv->is_incoming = TRUE;
-                       priv->contact = g_object_ref (contact);
-                       tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RINGING);
-               }
-               return;
-       }
-
-       /* We already have the other contact, that means we now have 2 members,
-        * so we can start the call */
-       tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RUNNING);
+                         EmpathyContact *contact,
+                         EmpathyContact *actor,
+                         guint reason,
+                         const gchar *message,
+                         EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  empathy_debug (DEBUG_DOMAIN, "New member added callback %p", contact);
+  tp_call_is_ready (call);
+
+  if (priv->status == EMPATHY_TP_CALL_STATUS_PENDING)
+    {
+      if ((priv->is_incoming &&
+            !empathy_contact_equal (contact, priv->contact))
+          || (!priv->is_incoming &&
+            empathy_contact_equal (contact, priv->contact)))
+        {
+          priv->status = EMPATHY_TP_CALL_STATUS_ACCEPTED;
+          g_signal_emit (call, signals[STATUS_CHANGED_SIGNAL], 0);
+        }
+    }
+}
+
+static void
+tp_call_local_pending_cb (EmpathyTpGroup *group,
+                          EmpathyContact *contact,
+                          EmpathyContact *actor,
+                          guint reason,
+                          const gchar *message,
+                          EmpathyTpCall *call)
+{
+  empathy_debug (DEBUG_DOMAIN, "New local pending added callback %p", contact);
+  tp_call_is_ready (call);
 }
 
 static void
 tp_call_remote_pending_cb (EmpathyTpGroup *group,
-                          EmpathyContact *contact,
-                          EmpathyContact *actor,
-                          guint           reason,
-                          const gchar    *message,
-                          EmpathyTpCall  *call)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       empathy_debug (DEBUG_DOMAIN, "Remote pending: %s (%d)",
-                      empathy_contact_get_id (contact),
-                      empathy_contact_get_handle (contact));
-
-       if (!priv->contact) {
-               priv->is_incoming = FALSE;
-               priv->contact = g_object_ref (contact);
-               tp_call_set_status (call, EMPATHY_TP_CALL_STATUS_RINGING);
-       }
+                           EmpathyContact *contact,
+                           EmpathyContact *actor,
+                           guint reason,
+                           const gchar *message,
+                           EmpathyTpCall *call)
+{
+  empathy_debug (DEBUG_DOMAIN, "New remote pending added callback %p", contact);
+  tp_call_is_ready (call);
 }
 
 static void
-tp_call_async_cb (DBusGProxy *proxy,
-                 GError     *error,
-                 gpointer    user_data)
-{
-       if (error) {
-               empathy_debug (DEBUG_DOMAIN, "Failed to %s: %s",
-                              user_data,
-                              error->message);
-       }
+tp_call_start_stream_engine (EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  DBusGProxy *ch_proxy;
+  GError *error = NULL;
+
+  empathy_debug (DEBUG_DOMAIN, "Revving up the stream engine");
+
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, CHANNEL_HANDLER_INTERFACE);
+
+  if (!org_freedesktop_Telepathy_ChannelHandler_handle_channel (ch_proxy,
+        dbus_g_proxy_get_bus_name (DBUS_G_PROXY (priv->connection)),
+        dbus_g_proxy_get_path (DBUS_G_PROXY (priv->connection)),
+        priv->channel->type,
+        dbus_g_proxy_get_path (DBUS_G_PROXY (priv->channel)),
+        priv->channel->handle_type, priv->channel->handle, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't start stream engine: %s",
+          error->message);
+      g_clear_error (&error);
+    }
 }
 
 static GObject *
-tp_call_constructor (GType                  type,
-                    guint                  n_props,
-                    GObjectConstructParam *props)
-{
-       GObject           *call;
-       EmpathyTpCallPriv *priv;
-       TpConn            *tp_conn;
-       MissionControl    *mc;
-
-       call = G_OBJECT_CLASS (empathy_tp_call_parent_class)->constructor (type, n_props, props);
-       priv = GET_PRIV (call);
-
-       priv->group = empathy_tp_group_new (priv->account, priv->tp_chan);
-       priv->streamed_iface = tp_chan_get_interface (priv->tp_chan,
-                                                     TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA);
-
-       /* Connect signals */
-       dbus_g_proxy_connect_signal (priv->streamed_iface, "StreamAdded",
-                                    G_CALLBACK (tp_call_stream_added_cb),
-                                    call, NULL);
-       dbus_g_proxy_connect_signal (priv->streamed_iface, "StreamRemoved",
-                                    G_CALLBACK (tp_call_stream_removed_cb), 
-                                    call, NULL);
-       dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->tp_chan), "Closed",
-                                    G_CALLBACK (tp_call_closed_cb),
-                                    call, NULL);
-       g_signal_connect (priv->tp_chan, "destroy",
-                         G_CALLBACK (tp_call_destroy_cb),
-                         call);
-       g_signal_connect (priv->group, "member-added",
-                         G_CALLBACK (tp_call_member_added_cb),
-                         call);
-       g_signal_connect (priv->group, "remote-pending",
-                         G_CALLBACK (tp_call_remote_pending_cb),
-                         call);
-
-       /* Start stream engine */
-       mc = empathy_mission_control_new ();
-       tp_conn = mission_control_get_connection (mc, priv->account, NULL);
-       priv->se_ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
-                                                      STREAM_ENGINE_BUS_NAME,
-                                                      STREAM_ENGINE_OBJECT_PATH,
-                                                      CHANNEL_HANDLER_INTERFACE);
-       priv->se_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
-                                                   STREAM_ENGINE_BUS_NAME,
-                                                   STREAM_ENGINE_OBJECT_PATH,
-                                                   STREAM_ENGINE_INTERFACE);
-       org_freedesktop_Telepathy_ChannelHandler_handle_channel_async (priv->se_ch_proxy,
-               dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn)),
-               dbus_g_proxy_get_path (DBUS_G_PROXY (tp_conn)),
-               priv->tp_chan->type,
-               dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
-               priv->tp_chan->handle_type,
-               priv->tp_chan->handle,
-               tp_call_async_cb,
-               "handle channel");
-       g_object_unref (tp_conn);
-       g_object_unref (mc);
-
-       /* Get streams */
-       tp_chan_type_streamed_media_list_streams_async (priv->streamed_iface,
-                                                       tp_call_list_streams_cb,
-                                                       call);
-
-       return call;
+tp_call_constructor (GType type,
+                     guint n_construct_params,
+                     GObjectConstructParam *construct_params)
+{
+  GObject *object;
+  EmpathyTpCall *call;
+  EmpathyTpCallPriv *priv;
+  DBusGProxy *streamed_iface;
+  MissionControl *mc;
+  McAccount *account;
+
+  object = G_OBJECT_CLASS (empathy_tp_call_parent_class)->constructor (type,
+      n_construct_params, construct_params);
+
+  call = EMPATHY_TP_CALL (object);
+  priv = GET_PRIV (call);
+
+  dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->channel), "Closed",
+     G_CALLBACK (tp_call_channel_closed_cb), (gpointer) call, NULL);
+
+  streamed_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+  dbus_g_proxy_connect_signal (streamed_iface, "StreamStateChanged",
+      G_CALLBACK (tp_call_stream_state_changed_cb),
+      (gpointer) call, NULL);
+  dbus_g_proxy_connect_signal (streamed_iface, "StreamDirectionChanged",
+      G_CALLBACK (tp_call_stream_direction_changed_cb),
+      (gpointer) call, NULL);
+  dbus_g_proxy_connect_signal (streamed_iface, "StreamAdded",
+      G_CALLBACK (tp_call_stream_added_cb), (gpointer) call, NULL);
+  dbus_g_proxy_connect_signal (streamed_iface, "StreamRemoved",
+      G_CALLBACK (tp_call_stream_removed_cb), (gpointer) call, NULL);
+
+  mc = empathy_mission_control_new ();
+  account = mission_control_get_account_for_connection (mc, priv->connection,
+      NULL);
+  priv->group = empathy_tp_group_new (account, priv->channel);
+
+  g_signal_connect (G_OBJECT (priv->group), "member-added",
+      G_CALLBACK (tp_call_member_added_cb), (gpointer) call);
+  g_signal_connect (G_OBJECT (priv->group), "local-pending",
+      G_CALLBACK (tp_call_local_pending_cb), (gpointer) call);
+  g_signal_connect (G_OBJECT (priv->group), "remote-pending",
+      G_CALLBACK (tp_call_remote_pending_cb), (gpointer) call);
+
+  tp_call_start_stream_engine (call);
+  /* FIXME: unnecessary for outgoing? */
+  tp_call_identify_streams (call);
+
+  return object;
 }
 
-static void
+static void 
 tp_call_finalize (GObject *object)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (object);
-
-       empathy_debug (DEBUG_DOMAIN, "Finalizing: %p", object);
-
-       if (priv->tp_chan) {
-               GError *error = NULL;
-
-               g_signal_handlers_disconnect_by_func (priv->tp_chan,
-                                                     tp_call_destroy_cb,
-                                                     object);
-               empathy_debug (DEBUG_DOMAIN, "Closing channel...");
-               if (!tp_chan_close (DBUS_G_PROXY (priv->tp_chan), &error)) {
-                       empathy_debug (DEBUG_DOMAIN, 
-                                     "Error closing text channel: %s",
-                                     error ? error->message : "No error given");
-                       g_clear_error (&error);
-               }
-               g_object_unref (priv->tp_chan);
-       }
-
-       g_object_unref (priv->group);
-       g_object_unref (priv->contact);
-       g_object_unref (priv->account);
-       g_object_unref (priv->se_ch_proxy);
-       g_object_unref (priv->se_proxy);
-
-       G_OBJECT_CLASS (empathy_tp_call_parent_class)->finalize (object);
+  EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+  empathy_debug (DEBUG_DOMAIN, "Finalizing: %p", object);
+
+  g_slice_free (EmpathyTpCallStream, priv->audio);
+  g_slice_free (EmpathyTpCallStream, priv->video);
+  g_object_unref (priv->group);
+  if (priv->contact)
+    {
+      g_object_unref (priv->contact);
+    }
+
+  (G_OBJECT_CLASS (empathy_tp_call_parent_class)->finalize) (object);
+}
+
+static void 
+tp_call_set_property (GObject *object,
+                      guint prop_id,
+                      const GValue *value,
+                      GParamSpec *pspec)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONNECTION:
+      priv->connection = g_value_get_object (value);
+      break;
+    case PROP_CHANNEL:
+      priv->channel = g_value_get_object (value);
+      break;
+    case PROP_CONTACT:
+      priv->contact = g_value_get_object (value);
+      break;
+    case PROP_IS_INCOMING:
+      priv->is_incoming = g_value_get_boolean (value);
+      break;
+    case PROP_STATUS:
+      priv->status = g_value_get_uint (value);
+      break;
+    case PROP_AUDIO_STREAM:
+      priv->audio = g_value_get_pointer (value);
+      break;
+    case PROP_VIDEO_STREAM:
+      priv->video = g_value_get_pointer (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+
+static void
+tp_call_get_property (GObject *object,
+                      guint prop_id,
+                      GValue *value,
+                      GParamSpec *pspec)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (object);
+
+  switch (prop_id)
+    {
+    case PROP_CONNECTION:
+      g_value_set_object (value, priv->connection);
+      break;
+    case PROP_CHANNEL:
+      g_value_set_object (value, priv->channel);
+      break;
+    case PROP_CONTACT:
+      g_value_set_object (value, priv->contact);
+      break;
+    case PROP_IS_INCOMING:
+      g_value_set_boolean (value, priv->is_incoming);
+      break;
+    case PROP_STATUS:
+      g_value_set_uint (value, priv->status);
+      break;
+    case PROP_AUDIO_STREAM:
+      g_value_set_pointer (value, priv->audio);
+      break;
+    case PROP_VIDEO_STREAM:
+      g_value_set_pointer (value, priv->video);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
 }
 
 static void
 empathy_tp_call_class_init (EmpathyTpCallClass *klass)
 {
-       GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-       object_class->constructor = tp_call_constructor;
-       object_class->finalize = tp_call_finalize;
-       object_class->set_property = tp_call_set_property;
-       object_class->get_property = tp_call_get_property;
-
-       /* Construct-only properties */
-       g_object_class_install_property (object_class,
-                                        PROP_ACCOUNT,
-                                        g_param_spec_object ("account",
-                                                             "channel Account",
-                                                             "The account associated with the channel",
-                                                             MC_TYPE_ACCOUNT,
-                                                             G_PARAM_READWRITE |
-                                                             G_PARAM_CONSTRUCT_ONLY));
-       g_object_class_install_property (object_class,
-                                        PROP_TP_CHAN,
-                                        g_param_spec_object ("tp-chan",
-                                                             "telepathy channel",
-                                                             "The media channel for the call",
-                                                             TELEPATHY_CHAN_TYPE,
-                                                             G_PARAM_READWRITE |
-                                                             G_PARAM_CONSTRUCT_ONLY));
-
-       /* Normal properties */
-       g_object_class_install_property (object_class,
-                                        PROP_STATUS,
-                                        g_param_spec_enum ("status",
-                                                           "call status",
-                                                           "The status of the call",
-                                                           EMPATHY_TYPE_TP_CALL_STATUS,
-                                                           EMPATHY_TP_CALL_STATUS_PREPARING,
-                                                           G_PARAM_READABLE));
-
-       /* Signals */
-       signals[DESTROY] =
-               g_signal_new ("destroy",
-                             G_TYPE_FROM_CLASS (klass),
-                             G_SIGNAL_RUN_LAST,
-                             0,
-                             NULL, NULL,
-                             g_cclosure_marshal_VOID__VOID,
-                             G_TYPE_NONE,
-                             0);
-
-
-       g_type_class_add_private (klass, sizeof (EmpathyTpCallPriv));
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructor = tp_call_constructor;
+  object_class->finalize = tp_call_finalize;
+  object_class->set_property = tp_call_set_property;
+  object_class->get_property = tp_call_get_property;
+
+  g_type_class_add_private (klass, sizeof (EmpathyTpCallPriv));
+
+  signals[STATUS_CHANGED_SIGNAL] =
+      g_signal_new ("status-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+      G_TYPE_NONE, 0);
+  signals[RECEIVING_VIDEO_SIGNAL] =
+      g_signal_new ("receiving-video", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+  signals[SENDING_VIDEO_SIGNAL] =
+      g_signal_new ("sending-video", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  g_object_class_install_property (object_class, PROP_CONNECTION,
+      g_param_spec_object ("connection", "connection", "connection",
+      TELEPATHY_CONN_TYPE,
+      G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_CHANNEL,
+      g_param_spec_object ("channel", "channel", "channel",
+      TELEPATHY_CHAN_TYPE,
+      G_PARAM_CONSTRUCT | G_PARAM_READWRITE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_CONTACT,
+      g_param_spec_object ("contact", "Call contact", "Call contact",
+      EMPATHY_TYPE_CONTACT,
+      G_PARAM_READABLE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_IS_INCOMING,
+      g_param_spec_boolean ("is-incoming", "Is media stream incoming",
+      "Is media stream incoming", FALSE, G_PARAM_READABLE |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_STATUS,
+      g_param_spec_uint ("status", "Call status",
+      "Call status", 0, 255, 0, G_PARAM_READABLE | G_PARAM_STATIC_NICK |
+      G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_AUDIO_STREAM,
+      g_param_spec_pointer ("audio-stream", "Audio stream data",
+      "Audio stream data",
+      G_PARAM_READABLE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class, PROP_VIDEO_STREAM,
+      g_param_spec_pointer ("video-stream", "Video stream data",
+      "Video stream data",
+      G_PARAM_READABLE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
 }
 
 static void
 empathy_tp_call_init (EmpathyTpCall *call)
 {
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  priv->status = EMPATHY_TP_CALL_STATUS_READYING;
+  priv->contact = NULL;
+  priv->audio = g_slice_new0 (EmpathyTpCallStream);
+  priv->video = g_slice_new0 (EmpathyTpCallStream);
+  priv->audio->exists = FALSE;
+  priv->video->exists = FALSE;
 }
 
 EmpathyTpCall *
-empathy_tp_call_new (McAccount *account, TpChan *channel)
+empathy_tp_call_new (TpConn *connection, TpChan *channel)
 {
-       return g_object_new (EMPATHY_TYPE_TP_CALL,
-                            "account", account,
-                            "tp_chan", channel,
-                            NULL);
+  return g_object_new (EMPATHY_TYPE_TP_CALL,
+      "connection", connection,
+      "channel", channel,
+      NULL);
 }
 
-gboolean
-empathy_tp_call_is_incoming (EmpathyTpCall *call)
+void
+empathy_tp_call_accept_incoming_call (EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  GList *local_pendings;
 
-       return priv->is_incoming;
-}
+  empathy_debug (DEBUG_DOMAIN, "Accepting incoming call");
 
-EmpathyTpCallStatus
-empathy_tp_call_get_status (EmpathyTpCall *call)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  local_pendings = empathy_tp_group_get_local_pendings (priv->group);
 
-       return priv->status;
+  empathy_tp_group_add_member (priv->group, EMPATHY_CONTACT
+      (((EmpathyPendingInfo *) local_pendings->data)->member), NULL);
+
+  g_list_foreach (local_pendings, (GFunc) empathy_pending_info_free, NULL);
+  g_list_free (local_pendings);
 }
 
-EmpathyContact *
-empathy_tp_call_get_contact (EmpathyTpCall *call)
+void
+empathy_tp_call_request_video_stream_direction (EmpathyTpCall *call,
+                                                gboolean is_sending)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       return priv->contact;
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  DBusGProxy *streamed_iface;
+  guint new_direction;
+  GError *error = NULL;
+
+  empathy_debug (DEBUG_DOMAIN,
+      "Requesting video stream direction - is_sending: %d", is_sending);
+
+  if (!priv->video->exists)
+    {
+      tp_call_request_streams_for_capabilities (call, EMPATHY_CAPABILITIES_VIDEO);
+      return;
+    }
+
+  streamed_iface = tp_chan_get_interface (priv->channel,
+      TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+
+  if (is_sending)
+    {
+      new_direction = priv->video->direction | TP_MEDIA_STREAM_DIRECTION_SEND;
+    }
+  else
+    {
+      new_direction = priv->video->direction & ~TP_MEDIA_STREAM_DIRECTION_SEND;
+    }
+
+  if (!tp_chan_type_streamed_media_request_stream_direction (streamed_iface,
+        priv->video->id, new_direction, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN,
+          "Couldn't request video stream direction: %s", error->message);
+      g_clear_error (&error);
+    }
 }
 
 void
-empathy_tp_call_accept (EmpathyTpCall *call)
+empathy_tp_call_close_channel (EmpathyTpCall *call)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-       EmpathyContact    *contact;
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  GError *error = NULL;
+
+  empathy_debug (DEBUG_DOMAIN, "Closing channel");
 
-       contact = empathy_tp_group_get_self_contact (priv->group);
-       empathy_tp_group_add_member (priv->group, contact, "");
+  if (!tp_chan_close (DBUS_G_PROXY (priv->channel), &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Error closing channel: %s",
+          error ? error->message : "No error given");
+      g_clear_error (&error);
+    }
 }
 
 void
-empathy_tp_call_invite (EmpathyTpCall  *call,
-                       EmpathyContact *contact)
+empathy_tp_call_add_preview_video (guint preview_video_socket_id)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  GError *error = NULL;
+  DBusGProxy *ch_proxy;
 
-       empathy_tp_group_add_member (priv->group, contact, "you're welcome");
-}
+  empathy_debug (DEBUG_DOMAIN, "Adding preview video");
 
-void
-empathy_tp_call_request_streams (EmpathyTpCall *call,
-                                gboolean       audio,
-                                gboolean       video)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-       GArray            *stream_types;
-       guint              handle;
-       guint              type;
-
-       empathy_debug (DEBUG_DOMAIN, "Requesting streams for audio=%s video=%s",
-                      audio ? "Yes" : "No",
-                      video ? "Yes" : "No");
-
-       stream_types = g_array_new (FALSE, FALSE, sizeof (guint));
-       if (audio) {
-               type = TP_MEDIA_STREAM_TYPE_AUDIO;
-               g_array_append_val (stream_types, type);
-       }
-       if (video) {
-               type = TP_MEDIA_STREAM_TYPE_VIDEO;
-               g_array_append_val (stream_types, type);
-       }
-
-       handle = empathy_contact_get_handle (priv->contact);
-       tp_chan_type_streamed_media_request_streams_async (priv->streamed_iface,
-                                                          handle,
-                                                          stream_types,
-                                                          tp_call_list_streams_cb,
-                                                          call);
-
-       g_array_free (stream_types, TRUE);
-}
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
 
-void
-empathy_tp_call_send_video (EmpathyTpCall *call,
-                           gboolean       send)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-       guint              new_direction;
-
-       if (!priv->video_stream) {
-               return;
-       }
-
-       if (send) {
-               new_direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL;
-       } else {
-               new_direction = TP_MEDIA_STREAM_DIRECTION_RECEIVE;
-       }
-
-       tp_chan_type_streamed_media_request_stream_direction_async (priv->streamed_iface,
-                                                                   priv->video_stream,
-                                                                   new_direction,
-                                                                   tp_call_async_cb,
-                                                                   "request stream direction");
+  if (!org_freedesktop_Telepathy_StreamEngine_add_preview_window (ch_proxy,
+        preview_video_socket_id, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't set video preview: %s",
+          error->message);
+      g_clear_error (&error);
+    }
 }
 
 void
-empathy_tp_call_add_preview_window (EmpathyTpCall *call,
-                                   guint          socket_id)
+empathy_tp_call_remove_preview_video (guint preview_video_socket_id)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  GError *error = NULL;
+  DBusGProxy *ch_proxy;
 
-       org_freedesktop_Telepathy_StreamEngine_add_preview_window_async (priv->se_proxy,
-                                                                        socket_id,
-                                                                        tp_call_async_cb,
-                                                                        "add preview window");
-}
+  empathy_debug (DEBUG_DOMAIN, "Removing preview video");
 
-void
-empathy_tp_call_remove_preview_window (EmpathyTpCall *call,
-                                      guint          socket_id)
-{
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
 
-       org_freedesktop_Telepathy_StreamEngine_remove_preview_window_async (priv->se_proxy,
-                                                                           socket_id,
-                                                                           tp_call_async_cb,
-                                                                           "remove preview window");
+  if (!org_freedesktop_Telepathy_StreamEngine_remove_preview_window (ch_proxy,
+        preview_video_socket_id, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't set video preview: %s",
+          error->message);
+      g_clear_error (&error);
+    }
 }
 
 void
-empathy_tp_call_set_output_window (EmpathyTpCall *call,
-                                  guint          socket_id)
+empathy_tp_call_add_output_video (EmpathyTpCall *call,
+                                  guint output_video_socket_id)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       org_freedesktop_Telepathy_StreamEngine_set_output_window_async (priv->se_proxy,
-                                                                       dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
-                                                                       priv->video_stream,
-                                                                       socket_id,
-                                                                       tp_call_async_cb,
-                                                                       "set output window");
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  const gchar *object_path;
+  DBusGProxy *ch_proxy;
+  GError *error = NULL;
+
+  empathy_debug (DEBUG_DOMAIN, "Adding output video - socket: %d",
+      output_video_socket_id);
+
+  object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (priv->channel));
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
+
+  if (!org_freedesktop_Telepathy_StreamEngine_set_output_window (ch_proxy,
+        object_path, priv->video->id, output_video_socket_id, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't set video output: %s",
+          error->message);
+      g_clear_error (&error);
+    }
 }
 
 void
 empathy_tp_call_set_output_volume (EmpathyTpCall *call,
-                                  guint          volume)
+                                   guint volume)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       org_freedesktop_Telepathy_StreamEngine_set_output_volume_async (priv->se_proxy,
-                                                                       dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
-                                                                       priv->audio_stream,
-                                                                       volume,
-                                                                       tp_call_async_cb,
-                                                                       "set output volume");
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  const gchar *object_path;
+  DBusGProxy *ch_proxy;
+  GError *error = NULL;
+
+  if (priv->status == EMPATHY_TP_CALL_STATUS_CLOSED)
+    return;
+
+  empathy_debug (DEBUG_DOMAIN, "Setting output volume: %d", volume);
+
+  object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (priv->channel));
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
+
+  if (!org_freedesktop_Telepathy_StreamEngine_set_output_volume (ch_proxy,
+        object_path, priv->audio->id, volume, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't set volume: %s", error->message);
+      g_clear_error (&error);
+    }
 }
 
 
 void
 empathy_tp_call_mute_output (EmpathyTpCall *call,
-                             gboolean       is_muted)
+                             gboolean is_muted)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       org_freedesktop_Telepathy_StreamEngine_mute_output_async (priv->se_proxy,
-                                                                 dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
-                                                                 priv->audio_stream,
-                                                                 is_muted,
-                                                                 tp_call_async_cb,
-                                                                 "mute output");
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  const gchar *object_path;
+  DBusGProxy *ch_proxy;
+  GError *error = NULL;
+
+  if (priv->status == EMPATHY_TP_CALL_STATUS_CLOSED)
+    return;
+
+  empathy_debug (DEBUG_DOMAIN, "Setting output mute: %d", is_muted);
+
+  object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (priv->channel));
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
+
+  if (!org_freedesktop_Telepathy_StreamEngine_mute_output (ch_proxy,
+        object_path, priv->audio->id, is_muted, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't mute output: %s", error->message);
+      g_clear_error (&error);
+    }
 }
 
-
 void
 empathy_tp_call_mute_input (EmpathyTpCall *call,
-                            gboolean       is_muted)
+                            gboolean is_muted)
 {
-       EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-       org_freedesktop_Telepathy_StreamEngine_mute_input_async (priv->se_proxy,
-                                                                dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan)),
-                                                                priv->audio_stream,
-                                                                is_muted,
-                                                                tp_call_async_cb,
-                                                                "mute output");
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+  const gchar *object_path;
+  DBusGProxy *ch_proxy;
+  GError *error = NULL;
+
+  if (priv->status == EMPATHY_TP_CALL_STATUS_CLOSED)
+    return;
+
+  empathy_debug (DEBUG_DOMAIN, "Setting input mute: %d", is_muted);
+
+  object_path = dbus_g_proxy_get_path (DBUS_G_PROXY (priv->channel));
+  ch_proxy = dbus_g_proxy_new_for_name (tp_get_bus (), STREAM_ENGINE_BUS_NAME,
+      STREAM_ENGINE_OBJECT_PATH, STREAM_ENGINE_INTERFACE);
+
+  if (!org_freedesktop_Telepathy_StreamEngine_mute_input (ch_proxy,
+        object_path, priv->audio->id, is_muted, &error))
+    {
+      empathy_debug (DEBUG_DOMAIN, "Couldn't mute input: %s", error->message);
+      g_clear_error (&error);
+    }
 }
 
index 13ab33fcbf676458469c98e67ffc8b2bd58a11c4..69f873425d946f65b842f4ad8b2ababcd9017d3d 100644 (file)
@@ -1,88 +1,90 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * Copyright (C) 2007 Elliot Fairweather
- * Copyright (C) 2007 Collabora Ltd.
+ *  Copyright (C) 2007 Elliot Fairweather
  *
- * 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 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.
+ *  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
+ *  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
  *
- * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
- *          Xavier Claessens <xclaesse@gmail.com>
+ *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
  */
 
 #ifndef __EMPATHY_TP_CALL_H__
 #define __EMPATHY_TP_CALL_H__
 
 #include <libtelepathy/tp-chan.h>
-#include <libtelepathy/tp-constants.h>
+#include <libtelepathy/tp-conn.h>
 
-#include <libmissioncontrol/mc-account.h>
+#include <libmissioncontrol/mission-control.h>
 
-#include "empathy-contact.h"
+#include <libempathy/empathy-chandler.h>
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-tp-group.h>
 
 G_BEGIN_DECLS
 
-#define EMPATHY_TYPE_TP_CALL              (empathy_tp_call_get_type ())
-#define EMPATHY_TP_CALL(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), EMPATHY_TYPE_TP_CALL, EmpathyTpCall))
-#define EMPATHY_TP_CALL_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
-#define EMPATHY_IS_TP_CALL(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), EMPATHY_TYPE_TP_CALL))
-#define EMPATHY_IS_TP_CALL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_TP_CALL))
-#define EMPATHY_TP_CALL_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
+#define EMPATHY_TYPE_TP_CALL (empathy_tp_call_get_type ())
+#define EMPATHY_TP_CALL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), \
+    EMPATHY_TYPE_TP_CALL, EmpathyTpCall))
+#define EMPATHY_TP_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \
+    EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
+#define EMPATHY_IS_TP_CALL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), \
+    EMPATHY_TYPE_TP_CALL))
+#define EMPATHY_IS_TP_CALL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+    EMPATHY_TYPE_TP_CALL))
+#define EMPATHY_TP_CALL_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), \
+    EMPATHY_TYPE_TP_CALL, EmpathyTpCallClass))
 
 typedef struct _EmpathyTpCall EmpathyTpCall;
 typedef struct _EmpathyTpCallClass EmpathyTpCallClass;
 
 struct _EmpathyTpCall {
-       GObject parent;
+    GObject parent;
 };
 
 struct _EmpathyTpCallClass {
-       GObjectClass parent_class;
+    GObjectClass parent_class;
 };
 
-typedef enum {
-       EMPATHY_TP_CALL_STATUS_PREPARING,
-       EMPATHY_TP_CALL_STATUS_RINGING,
-       EMPATHY_TP_CALL_STATUS_RUNNING
+typedef enum
+{
+  EMPATHY_TP_CALL_STATUS_READYING,
+  EMPATHY_TP_CALL_STATUS_PENDING,
+  EMPATHY_TP_CALL_STATUS_ACCEPTED,
+  EMPATHY_TP_CALL_STATUS_CLOSED
 } EmpathyTpCallStatus;
 
-GType               empathy_tp_call_get_type              (void) G_GNUC_CONST;
-EmpathyTpCall *     empathy_tp_call_new                   (McAccount      *account,
-                                                          TpChan         *tp_chan);
-gboolean            empathy_tp_call_is_incoming           (EmpathyTpCall  *call);
-EmpathyTpCallStatus empathy_tp_call_get_status            (EmpathyTpCall  *call);
-EmpathyContact *    empathy_tp_call_get_contact           (EmpathyTpCall  *call);
-void                empathy_tp_call_accept                (EmpathyTpCall  *call);
-void                empathy_tp_call_invite                (EmpathyTpCall  *call,
-                                                          EmpathyContact *contact);
-void                empathy_tp_call_request_streams       (EmpathyTpCall  *call,
-                                                          gboolean        audio,
-                                                          gboolean        video);
-void                empathy_tp_call_send_video            (EmpathyTpCall  *call,
-                                                          gboolean        send);
-void                empathy_tp_call_add_preview_window    (EmpathyTpCall  *call,
-                                                          guint           socket_id);
-void                empathy_tp_call_remove_preview_window (EmpathyTpCall  *call,
-                                                          guint           socket_id);
-void                empathy_tp_call_set_output_window     (EmpathyTpCall  *call,
-                                                          guint           socket_id);
-void                empathy_tp_call_set_output_volume     (EmpathyTpCall  *call,
-                                                          guint           volume);
-void                empathy_tp_call_mute_output           (EmpathyTpCall  *call,
-                                                          gboolean        is_muted);
-void                empathy_tp_call_mute_input            (EmpathyTpCall  *call,
-                                                          gboolean        is_muted);
+typedef struct
+{
+  gboolean exists;
+  guint id;
+  guint state;
+  guint direction;
+} EmpathyTpCallStream;
+
+GType empathy_tp_call_get_type (void) G_GNUC_CONST;
+EmpathyTpCall *empathy_tp_call_new (TpConn *connection, TpChan *channel);
+
+void empathy_tp_call_accept_incoming_call (EmpathyTpCall *call);
+void empathy_tp_call_close_channel (EmpathyTpCall *call);
+void empathy_tp_call_request_video_stream_direction (EmpathyTpCall *call,
+    gboolean is_sending);
+void empathy_tp_call_add_preview_video (guint preview_video_socket_id);
+void empathy_tp_call_remove_preview_video (guint preview_video_socket_id);
+void empathy_tp_call_add_output_video (EmpathyTpCall *call,
+    guint output_video_socket_id);
+void empathy_tp_call_set_output_volume (EmpathyTpCall *call, guint volume);
+void empathy_tp_call_mute_output (EmpathyTpCall *call, gboolean is_muted);
+void empathy_tp_call_mute_input (EmpathyTpCall *call, gboolean is_muted);
 
 G_END_DECLS
 
index 796d23ddf1675b2b30b64d05d145be97b8d22a6c..8c6edafc5ce37f3a04d37163f02b3c587ec82abc 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "empathy-debug.h"
 #include "empathy-utils.h"
+#include "empathy-contact-factory.h"
 #include "empathy-contact-manager.h"
 #include "empathy-tp-group.h"
 
@@ -397,19 +398,61 @@ empathy_inspect_handle (McAccount *account,
 }
 
 void
-empathy_call_with_contact (EmpathyContact  *contact)
+empathy_call_with_contact (EmpathyContact *contact)
 {
 #ifdef HAVE_VOIP
        MissionControl *mc;
+       McAccount      *account;
+       TpConn         *tp_conn;
+       gchar          *object_path;
+       const gchar    *bus_name;
+       TpChan         *new_chan;
+       EmpathyTpGroup *group;
+       GError         *error = NULL;
+
+       g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+
+       /* StreamedMedia channels must have handle=0 and handle_type=none.
+        * To call a contact we have to add him in the group interface of the
+        * channel. MissionControl will detect the channel creation and 
+        * dispatch it to the VoIP chandler automatically. */
 
        mc = empathy_mission_control_new ();
-       mission_control_request_channel (mc,
-                                        empathy_contact_get_account (contact),
-                                        TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
-                                        empathy_contact_get_handle (contact),
-                                        TP_HANDLE_TYPE_CONTACT,
-                                        NULL, NULL);
+       account = empathy_contact_get_account (contact);
+       tp_conn = mission_control_get_connection (mc, account, NULL);
+       /* FIXME: Should be async */
+       if (!tp_conn_request_channel (DBUS_G_PROXY (tp_conn),
+                                     TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+                                     TP_HANDLE_TYPE_NONE,
+                                     0,
+                                     FALSE,
+                                     &object_path,
+                                     &error)) {
+               empathy_debug (DEBUG_DOMAIN, 
+                             "Couldn't request channel: %s",
+                             error ? error->message : "No error given");
+               g_clear_error (&error);
+               g_object_unref (mc);
+               g_object_unref (tp_conn);
+               return;
+       }
+
+       bus_name = dbus_g_proxy_get_bus_name (DBUS_G_PROXY (tp_conn));
+       new_chan = tp_chan_new (tp_get_bus (),
+                               bus_name,
+                               object_path,
+                               TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+                               TP_HANDLE_TYPE_NONE,
+                               0);
+
+       group = empathy_tp_group_new (account, new_chan);
+       empathy_tp_group_add_member (group, contact, "");
+
+       g_object_unref (group);
        g_object_unref (mc);
+       g_object_unref (tp_conn);
+       g_object_unref (new_chan);
+       g_free (object_path);
 #endif
 }
 
@@ -417,16 +460,14 @@ void
 empathy_call_with_contact_id (McAccount *account, const gchar *contact_id)
 {
 #ifdef HAVE_VOIP
-       MissionControl *mc;
-
-       mc = empathy_mission_control_new ();
-       mission_control_request_channel_with_string_handle (mc,
-                                                           account,
-                                                           TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
-                                                           contact_id,
-                                                           TP_HANDLE_TYPE_CONTACT,
-                                                           NULL, NULL);
-       g_object_unref (mc);
+       EmpathyContactFactory *factory;
+       EmpathyContact        *contact;
+
+       factory = empathy_contact_factory_new ();
+       contact = empathy_contact_factory_get_from_id (factory, account, contact_id);
+       empathy_call_with_contact (contact);
+       g_object_unref (contact);
+       g_object_unref (factory);
 #endif
 }
 
index 116248f7086cc9e242f967b6e7d049c8ef729eeb..8d8f7c7eada8612f90d563c306090f0f650c30d4 100644 (file)
   (c-name "EmpathyTpCallStatus")
   (gtype-id "EMPATHY_TYPE_TP_CALL_STATUS")
   (values
-    '("preparing" "EMPATHY_TP_CALL_STATUS_PREPARING")
-    '("ringing" "EMPATHY_TP_CALL_STATUS_RINGING")
-    '("running" "EMPATHY_TP_CALL_STATUS_RUNNING")
+    '("readying" "EMPATHY_TP_CALL_STATUS_READYING")
+    '("pending" "EMPATHY_TP_CALL_STATUS_PENDING")
+    '("accepted" "EMPATHY_TP_CALL_STATUS_ACCEPTED")
+    '("closed" "EMPATHY_TP_CALL_STATUS_CLOSED")
   )
 )
 
   (is-constructor-of "EmpathyTpCall")
   (return-type "EmpathyTpCall*")
   (parameters
-    '("McAccount*" "account")
-    '("TpChan*" "tp_chan")
+    '("TpConn*" "connection")
+    '("TpChan*" "channel")
   )
 )
 
-(define-method is_incoming
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_is_incoming")
-  (return-type "gboolean")
-)
-
-(define-method get_status
+(define-method accept_incoming_call
   (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_get_status")
-  (return-type "EmpathyTpCallStatus")
-)
-
-(define-method get_contact
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_get_contact")
-  (return-type "EmpathyContact*")
-)
-
-(define-method accept
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_accept")
-  (return-type "none")
-)
-
-(define-method invite
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_invite")
+  (c-name "empathy_tp_call_accept_incoming_call")
   (return-type "none")
-  (parameters
-    '("EmpathyContact*" "contact")
-  )
 )
 
-(define-method request_streams
+(define-method close_channel
   (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_request_streams")
+  (c-name "empathy_tp_call_close_channel")
   (return-type "none")
-  (parameters
-    '("gboolean" "audio")
-    '("gboolean" "video")
-  )
 )
 
-(define-method send_video
+(define-method request_video_stream_direction
   (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_send_video")
+  (c-name "empathy_tp_call_request_video_stream_direction")
   (return-type "none")
   (parameters
-    '("gboolean" "send")
+    '("gboolean" "is_sending")
   )
 )
 
-(define-method add_preview_window
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_add_preview_window")
+(define-function empathy_tp_call_add_preview_video
+  (c-name "empathy_tp_call_add_preview_video")
   (return-type "none")
   (parameters
-    '("guint" "socket_id")
+    '("guint" "preview_video_socket_id")
   )
 )
 
-(define-method remove_preview_window
-  (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_remove_preview_window")
+(define-function empathy_tp_call_remove_preview_video
+  (c-name "empathy_tp_call_remove_preview_video")
   (return-type "none")
   (parameters
-    '("guint" "socket_id")
+    '("guint" "preview_video_socket_id")
   )
 )
 
-(define-method set_output_window
+(define-method add_output_video
   (of-object "EmpathyTpCall")
-  (c-name "empathy_tp_call_set_output_window")
+  (c-name "empathy_tp_call_add_output_video")
   (return-type "none")
   (parameters
-    '("guint" "socket_id")
+    '("guint" "output_video_socket_id")
   )
 )
 
index 7425972ea6d7fd575c2cfddd3403a4b7bb9c3534..7a7e6820d944bb300591002d1d0d299827cbfb5f 100644 (file)
@@ -17,6 +17,7 @@ headers
 #include "empathy-message.h"
 #include "empathy-status-presets.h"
 #include "empathy-time.h"
+#include "empathy-tp-call.h"
 #include "empathy-tp-chat.h"
 #include "empathy-tp-chatroom.h"
 #include "empathy-tp-contact-factory.h"
index 8b7929e3dc1bbfb43fe1f7c5af4ba9ae9e53b5c2..0d5a3e5cac8e8b30ae17f28b5c6ad5d4bbdc8879 100644 (file)
 
 ;; From empathy-call-window.h
 
-(define-function empathy_call_window_show
-  (c-name "empathy_call_window_show")
+(define-function empathy_call_window_new
+  (c-name "empathy_call_window_new")
+  (is-constructor-of "EmpathyCallWindow")
   (return-type "GtkWidget*")
   (parameters
     '("EmpathyTpCall*" "call")
index be9de117510847f117521c0352007ffc1bb286d8..e1568c18cf2cb21b2d3c71b37c1b594b7fd1bbd5 100644 (file)
  *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
  */
 
-#include <config.h>
-
-#include <stdlib.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
-#include <libgnomevfs/gnome-vfs.h>
-
 #include <libmissioncontrol/mission-control.h>
 
-#include <libempathy/empathy-chandler.h>
-#include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-tp-call.h>
+#include <libempathy/empathy-chandler.h>
 #include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-utils.h>
 
 #include <libempathy-gtk/empathy-call-window.h>
 
-#define DEBUG_DOMAIN "EmpathyCall"
-
-#define BUS_NAME "org.gnome.Empathy.CallChandler"
-#define OBJECT_PATH "/org/gnome/Empathy/CallChandler"
+#define DEBUG_DOMAIN "CallChandler"
 
 static guint nb_calls = 0;
 
 static void
-call_chandler_weak_notify (gpointer  data,
-                          GObject  *where_the_object_was)
+weak_notify (gpointer data,
+             GObject *where_the_object_was)
 {
-       nb_calls--;
-       if (nb_calls == 0) {
-               empathy_debug (DEBUG_DOMAIN, "No more calls, leaving...");
-               gtk_main_quit ();
-       }
+  nb_calls--;
+  if (nb_calls == 0)
+    {
+      empathy_debug (DEBUG_DOMAIN, "No more calls, leaving...");
+      gtk_main_quit ();
+    }
 }
 
 static void
-call_chandler_new_channel_cb (EmpathyChandler *chandler,
-                             TpConn          *tp_conn,
-                             TpChan          *tp_chan,
-                             MissionControl  *mc)
+new_channel_cb (EmpathyChandler *chandler,
+                TpConn *connection,
+                TpChan *channel,
+                MissionControl *mc)
 {
-       EmpathyTpCall *call;
-       McAccount     *account;
-       GtkWidget     *window;
-
-       account = mission_control_get_account_for_connection (mc, tp_conn, NULL);
+  EmpathyTpCall *call;
 
-       call = empathy_tp_call_new (account, tp_chan);
-       window = empathy_call_window_show (call);
-       g_object_unref (account);
-       g_object_unref (call);
+  call = empathy_tp_call_new (connection, channel);
+  empathy_call_window_new (call);
+  g_object_unref (call);
 
-       nb_calls++;
-       g_object_weak_ref (G_OBJECT (window), call_chandler_weak_notify, NULL);
+  nb_calls++;
+  g_object_weak_ref (G_OBJECT (call), weak_notify, NULL);
 }
 
 int
 main (int argc, char *argv[])
 {
-       EmpathyChandler *chandler;
-       MissionControl  *mc;
+  MissionControl *mc;
+  EmpathyChandler *chandler;
 
-       empathy_debug_set_log_file_from_env ();
+  gtk_init (&argc, &argv);
 
-       bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
-       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-       textdomain (GETTEXT_PACKAGE);
+  mc = empathy_mission_control_new ();
 
-       gtk_init (&argc, &argv);
+  chandler = empathy_chandler_new ("org.gnome.Empathy.CallChandler",
+      "/org/gnome/Empathy/CallChandler");
+  g_signal_connect (chandler, "new-channel",
+      G_CALLBACK (new_channel_cb), mc);
 
-       gtk_window_set_default_icon_name ("empathy");
-       gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
-                                          PKGDATADIR G_DIR_SEPARATOR_S "icons");
+  empathy_debug (DEBUG_DOMAIN, "Ready to handle new streamed media channels");
 
-       mc = empathy_mission_control_new ();
-       chandler = empathy_chandler_new (BUS_NAME, OBJECT_PATH);
-       g_signal_connect (chandler, "new-channel",
-                         G_CALLBACK (call_chandler_new_channel_cb),
-                         mc);
+  gtk_main ();
 
-       empathy_debug (DEBUG_DOMAIN, "Ready to handle new streamed media channels");
+  g_object_unref (chandler);
+  g_object_unref (mc);
 
-       gtk_main ();
-
-       g_object_unref (chandler);
-       g_object_unref (mc);
-
-       return EXIT_SUCCESS;
+  return EXIT_SUCCESS;
 }
-