Initial Voice+Video support Fixes bug #468204 (Elliot Fairweather, Xavier
authorXavier Claessens <xclaesse@gmail.com>
Sat, 29 Sep 2007 12:08:45 +0000 (12:08 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Sat, 29 Sep 2007 12:08:45 +0000 (12:08 +0000)
2007-09-29  Xavier Claessens  <xclaesse@gmail.com>

* libempathy-gtk/empathy-call-window.c:
* libempathy-gtk/empathy-call-window.h:
* libempathy-gtk/empathy-contact-list-view.c:
* libempathy-gtk/empathy-call-window.glade:
* libempathy-gtk/Makefile.am:
* libempathy-gtk/empathy-chat-window.c:
* src/empathy-call-chandler.c:
* src/empathy-call.chandler:
* src/org.gnome.Empathy.Call.service.in:
* src/Makefile.am:
* libempathy/empathy-utils.c:
* libempathy/empathy-utils.h:
* libempathy/empathy-tp-call.c:
* libempathy/empathy-tp-call.h:
* libempathy/Makefile.am:
* libempathy/tp-stream-engine.xml:
* configure.ac:
* doc/libempathy-gtk/libempathy-gtk-docs.sgml:
* doc/libempathy/libempathy.types:
* doc/libempathy/libempathy-docs.sgml:
* doc/libempathy/Makefile.am:
* doc/libempathy/tmpl/empathy-utils.sgml: Initial Voice+Video support
Fixes bug #468204 (Elliot Fairweather, Xavier Claessens).

svn path=/trunk/; revision=339

23 files changed:
ChangeLog
configure.ac
doc/libempathy-gtk/libempathy-gtk-docs.sgml
doc/libempathy/Makefile.am
doc/libempathy/libempathy-docs.sgml
doc/libempathy/libempathy.types
doc/libempathy/tmpl/empathy-utils.sgml
libempathy-gtk/Makefile.am
libempathy-gtk/empathy-call-window.c [new file with mode: 0644]
libempathy-gtk/empathy-call-window.glade [new file with mode: 0644]
libempathy-gtk/empathy-call-window.h [new file with mode: 0644]
libempathy-gtk/empathy-chat-window.c
libempathy-gtk/empathy-contact-list-view.c
libempathy/Makefile.am
libempathy/empathy-tp-call.c [new file with mode: 0644]
libempathy/empathy-tp-call.h [new file with mode: 0644]
libempathy/empathy-utils.c
libempathy/empathy-utils.h
libempathy/tp-stream-engine.xml [new file with mode: 0644]
src/Makefile.am
src/empathy-call-chandler.c [new file with mode: 0644]
src/empathy-call.chandler [new file with mode: 0644]
src/org.gnome.Empathy.Call.service.in [new file with mode: 0644]

index 9a716210d18ffffbbfb1babd75bb15353ac96386..108cb1f401dfcc1f6248fcf8ba7f0bb570c97c6b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,28 @@
-2007-09-28  Xavier Claessens  <xclaesse@gmail.com>
+2007-09-29  Xavier Claessens  <xclaesse@gmail.com>
 
+       * libempathy-gtk/empathy-call-window.c:
+       * libempathy-gtk/empathy-call-window.h:
        * libempathy-gtk/empathy-contact-list-view.c:
+       * libempathy-gtk/empathy-call-window.glade:
+       * libempathy-gtk/Makefile.am:
        * libempathy-gtk/empathy-chat-window.c:
+       * src/empathy-call-chandler.c:
+       * src/empathy-call.chandler:
+       * src/org.gnome.Empathy.Call.service.in:
        * src/Makefile.am:
-       * libempathy/empathy-tp-group.c:
-       * libempathy/Makefile.am: Ported from VOIP branch.
+       * libempathy/empathy-utils.c:
+       * libempathy/empathy-utils.h:
+       * libempathy/empathy-tp-call.c:
+       * libempathy/empathy-tp-call.h:
+       * libempathy/Makefile.am:
+       * libempathy/tp-stream-engine.xml:
+       * configure.ac:
+       * doc/libempathy-gtk/libempathy-gtk-docs.sgml:
+       * doc/libempathy/libempathy.types:
+       * doc/libempathy/libempathy-docs.sgml:
+       * doc/libempathy/Makefile.am:
+       * doc/libempathy/tmpl/empathy-utils.sgml: Initial Voice+Video support
+       Fixes bug #468204 (Elliot Fairweather, Xavier Claessens).
 
 2007-09-28  Xavier Claessens  <xclaesse@gmail.com>
 
        they are not owned by dbus-glib. This fix big leaks, thanks again to
        valgrind.
 
+2007-09-28  Xavier Claessens  <xclaesse@gmail.com>
+
+       * src/Makefile.am: Correctly modify service.in files to expand bindir.
+
 2007-09-28  Xavier Claessens  <xclaesse@gmail.com>
 
        * libempathy/empathy-tp-group.c: Look in the local_pendings list if a
 2007-03-16  Xavier Claessens  <xclaesse@gmail.com>
 
        * Initial version
+2007-09-28  Xavier Claessens  <xclaesse@gmail.com>
+
+       * libempathy/empathy-tp-group.c: Look in the local_pendings list if a
+       contact is already local pending.
+       * tests/contact-manager.c: Fix white space typo.
 
index f3fe4694560a705809f3f97d8940c07f1c967440..9fd3a1c36d125d13ac884e2b3bfb63297b40fd6b 100644 (file)
@@ -250,6 +250,20 @@ fi
 
 AM_CONDITIONAL(HAVE_PYTHON, test "x$have_python" = "xyes")
 
+dnl -----------------------------------------------------------
+dnl VoIP support
+dnl -----------------------------------------------------------
+AC_ARG_ENABLE(voip,
+              AS_HELP_STRING([--enable-voip=@<:@no/yes@:>@],
+                             [Add support for Voice and Video call]), ,
+                             enable_voip=no)
+
+if test "x$enable_voip" = "xyes"; then
+   AC_DEFINE(HAVE_VOIP, 1, [Define if we have voip])
+fi
+
+AM_CONDITIONAL(HAVE_VOIP, test "x$enable_voip" = "xyes")
+
 dnl -----------------------------------------------------------
 
 AC_OUTPUT([
@@ -273,7 +287,8 @@ AC_OUTPUT([
    megaphone/data/Makefile
    nothere/Makefile
    nothere/src/Makefile
-   nothere/data/Makefile   doc/Makefile
+   nothere/data/Makefile
+   doc/Makefile
    doc/libempathy/Makefile
    doc/libempathy-gtk/Makefile
    python/Makefile
index 05f9bd2bcac7200b291a561a4c7576d843ed0366..f66ffa1f4784250c0b020b7cae417a7af98805a4 100644 (file)
@@ -43,5 +43,6 @@
     <xi:include href="xml/empathy-contact-groups.xml"/>
     <xi:include href="xml/empathy-log-window.xml"/>
     <xi:include href="xml/empathy-spell-dialog.xml"/>
+    <xi:include href="xml/empathy-call-window.xml"/>
   </chapter>
 </book>
index 0988c364ff035f6441833f515b350f9b2e79e9ce..206e2218a760281dbd04eb54c4ee645dc76a65ca 100644 (file)
@@ -43,7 +43,11 @@ CFILE_GLOB=$(top_srcdir)/libempathy/*.c
 
 # Header files to ignore when scanning.
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES=empathy-filter-glue.h empathy-debug.h empathy-marshal.h
+IGNORE_HFILES=                 \
+       empathy-filter-glue.h   \
+       empathy-debug.h         \
+       empathy-marshal.h       \
+       tp-stream-engine-gen.h
 
 # Images to copy into HTML directory.
 # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
index 6c1bd79d1e692fbe7afe86951679ff8e8e1d026f..942c5f21decd6c316de2e17ba3cdc70d9f56dbc9 100644 (file)
@@ -19,6 +19,7 @@
     <xi:include href="xml/empathy-tp-contact-list.xml"/>
     <xi:include href="xml/empathy-tp-chat.xml"/>
     <xi:include href="xml/empathy-tp-chatroom.xml"/>
+    <xi:include href="xml/empathy-tp-call.xml"/>
     <xi:include href="xml/empathy-contact-factory.xml"/>
     <xi:include href="xml/empathy-chatroom.xml"/>
     <xi:include href="xml/empathy-chatroom-manager.xml"/>
index 3f8d7bf0144de227d24380826673071021873cd0..dbebb0bc06799a487cffef9cc5352f16831b5c63 100644 (file)
@@ -17,6 +17,7 @@
 #include <libempathy/empathy-tp-chatroom.h>
 #include <libempathy/empathy-enum-types.h>
 #include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-tp-call.h>
 
 empathy_avatar_get_type
 empathy_chatroom_manager_get_type
@@ -38,4 +39,5 @@ empathy_tp_chatroom_get_type
 empathy_reg_ex_type_get_type
 empathy_message_type_get_type
 empathy_contact_factory_get_type
+empathy_tp_call_get_type
 
index fb8edba30851864028fbd6105bae35995ca9e22b..f25e0f6a3f0cfec14c27377028a96df3e7446971 100644 (file)
@@ -188,3 +188,11 @@ empathy-utils
 @Returns: 
 
 
+<!-- ##### FUNCTION empathy_call_contact ##### -->
+<para>
+
+</para>
+
+@contact: 
+
+
index a825f4427c20f04f60fa9942dbb1145c5b5fb5e9..fa13e27ccc420a658409bbd3d1a127954daba9a7 100644 (file)
@@ -47,6 +47,7 @@ libempathy_gtk_la_SOURCES =                   \
        empathy-new-chatroom-dialog.c           \
        empathy-chatrooms-window.c              \
        empathy-log-window.c                    \
+       empathy-call-window.c                   \
        empathy-ui-utils.c
 
 # do not distribute generated files
@@ -96,6 +97,7 @@ libempathy_gtk_headers =                      \
        empathy-new-chatroom-dialog.h           \
        empathy-chatrooms-window.h              \
        empathy-log-window.h                    \
+       empathy-call-window.h                   \
        empathy-ui-utils.h
 
 libempathy_gtk_includedir = $(includedir)/libempathy-gtk/
@@ -120,6 +122,7 @@ glade_DATA =                                        \
        empathy-chatrooms-window.glade          \
        empathy-spell-dialog.glade              \
        empathy-log-window.glade                \
+       empathy-call-window.glade               \
        empathy-chat.glade
 
 empathy-gtk-enum-types.h: stamp-empathy-gtk-enum-types.h
diff --git a/libempathy-gtk/empathy-call-window.c b/libempathy-gtk/empathy-call-window.c
new file mode 100644 (file)
index 0000000..baa1697
--- /dev/null
@@ -0,0 +1,198 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-call-window.h"
+#include "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;
+} EmpathyCallWindow;
+
+static void
+call_window_output_volume_changed_cb (GtkWidget         *scale,
+                                     EmpathyCallWindow *window)
+{
+       guint volume;
+
+       volume = (guint) gtk_range_get_value (GTK_RANGE (scale));
+       empathy_tp_call_set_output_volume (window->call, volume);
+}
+
+
+static void
+call_window_output_mute_toggled_cb (GtkWidget         *button,
+                                   EmpathyCallWindow *window)
+{
+       gboolean is_muted;
+
+       is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       empathy_tp_call_mute_output (window->call, is_muted);
+}
+
+
+static void
+call_window_input_mute_toggled_cb (GtkWidget         *button,
+                                  EmpathyCallWindow *window)
+{
+       gboolean is_muted;
+
+       is_muted = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       empathy_tp_call_mute_input (window->call, is_muted);
+}
+
+
+static void
+call_window_send_video_toggled_cb (GtkWidget         *button,
+                                  EmpathyCallWindow *window)
+{
+       gboolean is_sending;
+
+       is_sending = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       empathy_tp_call_send_video (window->call, is_sending);
+}
+
+static void
+call_window_capabilities_notify_cb (EmpathyContact    *contact,
+                                   GParamSpec        *param,
+                                   EmpathyCallWindow *window)
+{
+       EmpathyCapabilities capabilities;
+
+       capabilities = empathy_contact_get_capabilities (contact);
+       empathy_tp_call_request_streams (window->call,
+                                        capabilities & EMPATHY_CAPABILITIES_AUDIO,
+                                        capabilities & EMPATHY_CAPABILITIES_VIDEO);
+}
+
+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);
+                       call_window_capabilities_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)));
+       }
+}
+
+static void
+call_window_destroy_cb (GtkWidget         *widget,
+                       EmpathyCallWindow *window)
+{
+       g_object_unref (window->call);
+       g_slice_free (EmpathyCallWindow, window);
+}
+
+void
+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);
+}
+
diff --git a/libempathy-gtk/empathy-call-window.glade b/libempathy-gtk/empathy-call-window.glade
new file mode 100644 (file)
index 0000000..bc18952
--- /dev/null
@@ -0,0 +1,335 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<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>
+
+</glade-interface>
diff --git a/libempathy-gtk/empathy-call-window.h b/libempathy-gtk/empathy-call-window.h
new file mode 100644 (file)
index 0000000..ea310d6
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_CALL_WINDOW_H__
+#define __EMPATHY_CALL_WINDOW_H__
+
+#include <libempathy/empathy-tp-call.h>
+
+G_BEGIN_DECLS
+
+void empathy_call_window_show (EmpathyTpCall *call);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_CALL_WINDOW_H__ */
+
index 29fe5a521c9b7d78d41600030e0507f966696f8d..41402f2526b841ec8bc76c8181608fe96ede1979 100644 (file)
@@ -883,9 +883,7 @@ chat_window_call_activate_cb (GtkWidget         *menuitem,
                chat = EMPATHY_PRIVATE_CHAT (priv->current_chat);
                contact = empathy_private_chat_get_contact (chat);
 
-               /* FIXME: See contact_list_view_voip_activated() to know how to
-                * call a contact. We need a function to call a contact and use
-                * it here and in EmpathyContactListView. */
+               empathy_call_contact (contact);
        }
 }
 
index c959eec01eaae5de9b6a87c8950dad853112a4f7..1fcbf4440c608f1817002a42a51554c6923d4028 100644 (file)
@@ -1438,59 +1438,6 @@ static void
 contact_list_view_voip_activated (EmpathyContactListView *view,
                                  EmpathyContact         *contact)
 {
-       MissionControl *mc;
-       McAccount      *account;
-       TpConn         *tp_conn;
-       gchar          *object_path;
-       const gchar    *bus_name;
-       TpChan         *new_chan;
-       EmpathyTpGroup *group;
-       GError         *error;
-
-       /* 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 ();
-       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);
-
-       /* FIXME: group is leaked, we can't unref it directly because
-        * _add_member is async so we have to wait for it to return before
-        * finalizing the group. I think EmpathyTpGroup should ref itself
-        * when it does async calls to avoid finalizing when there is calls
-        * in fligth like that we could unref it here. */
-       group = empathy_tp_group_new (account, new_chan);
-       empathy_tp_group_add_member (group, contact, "");
-
-       g_object_unref (mc);
-       g_object_unref (tp_conn);
-       g_object_unref (new_chan);
-       g_free (object_path);
+       empathy_call_contact (contact);
 }
 
index 9dc4021e2abc11e23154ba057f402fbf028b3ece..0480d0bff1263da5596ddcee8fa5c3834143ac6f 100644 (file)
@@ -34,6 +34,7 @@ libempathy_la_SOURCES =                                       \
        empathy-tp-chat.c                               \
        empathy-tp-chatroom.c                           \
        empathy-tp-roomlist.c                           \
+       empathy-tp-call.c                               \
        empathy-chandler.c                              \
        empathy-filter.c                                \
        empathy-idle.c                                  \
@@ -68,10 +69,12 @@ libempathy_headers =                                \
        empathy-tp-chat.h                       \
        empathy-tp-chatroom.h                   \
        empathy-tp-roomlist.h                   \
+       empathy-tp-call.h                       \
        empathy-chandler.h                      \
        empathy-filter.h                        \
        empathy-idle.h                          \
-       empathy-log-manager.h
+       empathy-log-manager.h                   \
+       tp-stream-engine-gen.h
 
 libempathy_includedir = $(includedir)/libempathy/
 libempathy_include_HEADERS =                   \
@@ -90,6 +93,10 @@ empathy-chandler-glue.h: empathy-chandler.xml Makefile
 empathy-filter-glue.h: empathy-filter.xml Makefile
        $(LIBTOOL) --mode=execute $(DBUS_BINDING_TOOL) --prefix=empathy_filter --mode=glib-server --output=$@ $<
 
+tp-stream-engine-gen.h: tp-stream-engine.xml Makefile.am
+       $(LIBTOOL) --mode=execute $(DBUS_BINDING_TOOL) --prefix=tp_stream_engine --mode=glib-client --output=$@ $<
+
+
 empathy-enum-types.h: stamp-empathy-enum-types.h
        @true
 stamp-empathy-enum-types.h: $(libempathy_headers) Makefile
diff --git a/libempathy/empathy-tp-call.c b/libempathy/empathy-tp-call.c
new file mode 100644 (file)
index 0000000..e0347ba
--- /dev/null
@@ -0,0 +1,655 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <libtelepathy/tp-chan-type-streamed-media-gen.h>
+#include <libtelepathy/tp-helpers.h>
+#include <libtelepathy/tp-conn.h>
+
+#include <libmissioncontrol/mission-control.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"
+
+#define DEBUG_DOMAIN "TpCall"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_TP_CALL, EmpathyTpCallPriv))
+
+#define STREAM_ENGINE_BUS_NAME "org.freedesktop.Telepathy.StreamEngine"
+#define STREAM_ENGINE_OBJECT_PATH "/org/freedesktop/Telepathy/StreamEngine"
+#define STREAM_ENGINE_INTERFACE "org.freedesktop.Telepathy.StreamEngine"
+#define CHANNEL_HANDLER_INTERFACE "org.freedesktop.Telepathy.ChannelHandler"
+
+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;
+};
+
+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 {
+       DESTROY,
+       LAST_SIGNAL
+};
+
+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)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       priv->status = status;
+       g_object_notify (G_OBJECT (call), "status");
+}
+
+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;
+       }
+}
+
+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_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;
+       }
+}
+
+static void
+tp_call_destroy_cb (TpChan        *call_chan,
+                   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);
+}
+
+static void
+tp_call_closed_cb (TpChan        *call_chan,
+                  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);
+}
+
+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);
+       }
+}
+
+
+static void
+tp_call_stream_removed_cb (DBusGProxy    *streamed_iface,
+                          guint          stream_id,
+                          EmpathyTpCall *call)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       empathy_debug (DEBUG_DOMAIN, "Stream removed: %d", stream_id);
+
+       if (stream_id == priv->audio_stream) {
+               priv->audio_stream = 0;
+       }
+       else if (stream_id == priv->video_stream) {
+               priv->video_stream = 0;
+       }
+}
+
+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);
+       }
+}
+
+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);
+}
+
+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);
+       }
+}
+
+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);
+       }
+}
+
+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,
+                                                     TELEPATHY_CHAN_IFACE_STREAMED_QUARK);
+
+       /* 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;
+}
+
+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;
+
+               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);
+}
+
+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));
+}
+
+static void
+empathy_tp_call_init (EmpathyTpCall *call)
+{
+}
+
+EmpathyTpCall *
+empathy_tp_call_new (McAccount *account, TpChan *channel)
+{
+       return g_object_new (EMPATHY_TYPE_TP_CALL,
+                            "account", account,
+                            "tp_chan", channel,
+                            NULL);
+}
+
+gboolean
+empathy_tp_call_is_incoming (EmpathyTpCall *call)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       return priv->is_incoming;
+}
+
+EmpathyTpCallStatus
+empathy_tp_call_get_status (EmpathyTpCall *call)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       return priv->status;
+}
+
+EmpathyContact *
+empathy_tp_call_get_contact (EmpathyTpCall *call)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       return priv->contact;
+}
+
+void
+empathy_tp_call_accept (EmpathyTpCall *call)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+       EmpathyContact    *contact;
+
+       contact = empathy_tp_group_get_self_contact (priv->group);
+       empathy_tp_group_add_member (priv->group, contact, "");
+}
+
+void
+empathy_tp_call_invite (EmpathyTpCall  *call,
+                       EmpathyContact *contact)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       empathy_tp_group_add_member (priv->group, contact, "you're welcome");
+}
+
+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);
+}
+
+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");
+}
+
+void
+empathy_tp_call_add_preview_window (EmpathyTpCall *call,
+                                   guint          socket_id)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       org_freedesktop_Telepathy_StreamEngine_add_preview_window_async (priv->se_proxy,
+                                                                        socket_id,
+                                                                        tp_call_async_cb,
+                                                                        "add preview window");
+}
+
+void
+empathy_tp_call_remove_preview_window (EmpathyTpCall *call,
+                                      guint          socket_id)
+{
+       EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+       org_freedesktop_Telepathy_StreamEngine_remove_preview_window_async (priv->se_proxy,
+                                                                           socket_id,
+                                                                           tp_call_async_cb,
+                                                                           "remove preview window");
+}
+
+void
+empathy_tp_call_set_output_window (EmpathyTpCall *call,
+                                  guint          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");
+}
+
+void
+empathy_tp_call_set_output_volume (EmpathyTpCall *call,
+                                  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");
+}
+
+
+void
+empathy_tp_call_mute_output (EmpathyTpCall *call,
+                             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");
+}
+
+
+void
+empathy_tp_call_mute_input (EmpathyTpCall *call,
+                            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");
+}
+
diff --git a/libempathy/empathy-tp-call.h b/libempathy/empathy-tp-call.h
new file mode 100644 (file)
index 0000000..13ab33f
--- /dev/null
@@ -0,0 +1,89 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2007 Elliot Fairweather
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_TP_CALL_H__
+#define __EMPATHY_TP_CALL_H__
+
+#include <libtelepathy/tp-chan.h>
+#include <libtelepathy/tp-constants.h>
+
+#include <libmissioncontrol/mc-account.h>
+
+#include "empathy-contact.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))
+
+typedef struct _EmpathyTpCall EmpathyTpCall;
+typedef struct _EmpathyTpCallClass EmpathyTpCallClass;
+
+struct _EmpathyTpCall {
+       GObject parent;
+};
+
+struct _EmpathyTpCallClass {
+       GObjectClass parent_class;
+};
+
+typedef enum {
+       EMPATHY_TP_CALL_STATUS_PREPARING,
+       EMPATHY_TP_CALL_STATUS_RINGING,
+       EMPATHY_TP_CALL_STATUS_RUNNING
+} 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);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_TP_CALL_H__ */
index e0c6cfc9d886c92177b2a952c58c3794a71c3c8f..f33d83e48b122232ab52a275c580dbf5b27971ee 100644 (file)
@@ -38,6 +38,7 @@
 #include "empathy-debug.h"
 #include "empathy-utils.h"
 #include "empathy-contact-manager.h"
+#include "empathy-tp-group.h"
 
 #define DEBUG_DOMAIN "Utils"
 
@@ -462,3 +463,64 @@ empathy_inspect_handle (McAccount *account,
        return name;
 }
 
+void
+empathy_call_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;
+
+       /* 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 ();
+       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);
+
+       /* FIXME: group is leaked, we can't unref it directly because
+        * _add_member is async so we have to wait for it to return before
+        * finalizing the group. I think EmpathyTpGroup should ref itself
+        * when it does async calls to avoid finalizing when there is calls
+        * in fligth like that we could unref it here. */
+       group = empathy_tp_group_new (account, new_chan);
+       empathy_tp_group_add_member (group, contact, "");
+
+       g_object_unref (mc);
+       g_object_unref (tp_conn);
+       g_object_unref (new_chan);
+       g_free (object_path);
+#endif
+}
+
index 88d533728e3fc5c51ab68cdf1b918edeec243605..587adaedce5d78cb545976851b8b23461a1af819 100644 (file)
@@ -91,6 +91,7 @@ gchar *      empathy_inspect_handle                 (McAccount       *account,
                                                     guint            handle_type);
 gchar *      empathy_inspect_channel                (McAccount       *account,
                                                     TpChan          *tp_chan);
+void         empathy_call_contact                   (EmpathyContact  *contact);
 G_END_DECLS
 
 #endif /*  __EMPATHY_UTILS_H__ */
diff --git a/libempathy/tp-stream-engine.xml b/libempathy/tp-stream-engine.xml
new file mode 100644 (file)
index 0000000..5a8783d
--- /dev/null
@@ -0,0 +1,54 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/TpMediaEngine">
+  <interface name="org.freedesktop.Telepathy.ChannelHandler">
+    <method name="HandleChannel">
+      <arg direction="in" type="s" name="bus_name" />
+      <arg direction="in" type="o" name="connection" />
+      <arg direction="in" type="s" name="channel_type" />
+      <arg direction="in" type="o" name="channel" />
+      <arg direction="in" type="u" name="handle_type" />
+      <arg direction="in" type="u" name="handle" />
+    </method>
+  </interface>
+  <interface name="org.freedesktop.Telepathy.StreamEngine">
+    <method name="SetOutputVolume">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="u" name="volume" />
+    </method>
+    <method name="MuteInput">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="b" name="mute_state" />
+    </method>
+    <method name="MuteOutput">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="b" name="mute_state" />
+    </method>
+    <method name="SetOutputWindow">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <method name="AddPreviewWindow">
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <method name="RemovePreviewWindow">
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <signal name="Receiving">
+      <arg type="o" name="channel_path" />
+      <arg type="u" name="stream_id" />
+      <arg type="b" name="state" />
+    </signal>
+    <signal name="StreamStateChanged">
+      <arg type="o" name="channel_path" />
+      <arg type="u" name="stream_id" />
+      <arg type="u" name="state" />
+      <arg type="u" name="direction" />
+    </signal>
+    <method name="Shutdown">
+    </method>
+  </interface>
+</node>
index d81601ed0b402ccb01a092136e7a71ed5a18e2a2..ae336df09df77508f64d23180e5124d5a902ffaf 100644 (file)
@@ -15,15 +15,18 @@ LDADD =                                                             \
 
 bin_PROGRAMS =                 \
        empathy                 \
-       empathy-accounts
+       empathy-accounts        \
+       empathy-call-chandler
 
 empathy_SOURCES = empathy.c
 empathy_accounts_SOURCES = empathy-accounts.c
+empathy_call_chandler_SOURCES = empathy-call-chandler.c
 
-# Dbus service file
+# Dbus service files
 servicedir = $(datadir)/dbus-1/services
 service_DATA =                                                 \
-       org.gnome.Empathy.Chat.service
+       org.gnome.Empathy.Chat.service                          \
+       org.gnome.Empathy.Call.service
 %.service: %.service.in Makefile
        @sed -e "s|\@bindir\@|$(bindir)|" $< > $@
 
@@ -31,11 +34,17 @@ chandlerdir = $(datadir)/telepathy/managers
 chandler_DATA =                                                        \
        empathy-chat.chandler
 
+if HAVE_VOIP
+chandler_DATA += empathy-call.chandler
+endif
+
 BUILT_SOURCES =                                                        \
-       org.gnome.Empathy.Chat.service
+       org.gnome.Empathy.Chat.service                          \
+       org.gnome.Empathy.Call.service
 
 EXTRA_DIST =                                                   \
        org.gnome.Empathy.Chat.service.in                       \
+       org.gnome.Empathy.Call.service.in                       \
        $(autostart_DATA)                                       \
        $(chandler_DATA)
 
diff --git a/src/empathy-call-chandler.c b/src/empathy-call-chandler.c
new file mode 100644 (file)
index 0000000..bb88747
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  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 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
+ *
+ *  Authors: Elliot Fairweather <elliot.fairweather@collabora.co.uk>
+ */
+
+#include <stdlib.h>
+
+#include <gtk/gtk.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-debug.h>
+
+#include <libempathy-gtk/empathy-call-window.h>
+
+#define DEBUG_DOMAIN "EmpathyCall"
+
+#define BUS_NAME "org.gnome.Empathy.Call"
+#define OBJECT_PATH "/org/freedesktop/Telepathy/ChannelHandler"
+
+static void
+call_chandler_new_channel_cb (EmpathyChandler *chandler,
+                             TpConn          *tp_conn,
+                             TpChan          *tp_chan,
+                             MissionControl  *mc)
+{
+       EmpathyTpCall *call;
+       McAccount     *account;
+
+       account = mission_control_get_account_for_connection (mc, tp_conn, NULL);
+
+       call = empathy_tp_call_new (account, tp_chan);
+       empathy_call_window_show (call);
+       g_object_unref (account);
+       g_object_unref (call);
+}
+
+int
+main (int argc, char *argv[])
+{
+       EmpathyChandler *chandler;
+       MissionControl  *mc;
+
+       gtk_init (&argc, &argv);
+
+       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);
+
+       empathy_debug (DEBUG_DOMAIN, "Ready to handle new streamed media channels");
+
+       gtk_main ();
+
+       g_object_unref (chandler);
+       g_object_unref (mc);
+
+       return EXIT_SUCCESS;
+}
+
diff --git a/src/empathy-call.chandler b/src/empathy-call.chandler
new file mode 100644 (file)
index 0000000..190494d
--- /dev/null
@@ -0,0 +1,5 @@
+[ChannelHandler]
+BusName = org.gnome.Empathy.Call
+ObjectPath = /org/freedesktop/Telepathy/ChannelHandler
+ChannelType = org.freedesktop.Telepathy.Channel.Type.StreamedMedia
+TypeSpecificCapabilities = 15
diff --git a/src/org.gnome.Empathy.Call.service.in b/src/org.gnome.Empathy.Call.service.in
new file mode 100644 (file)
index 0000000..38d0e76
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.Empathy.Call
+Exec=@bindir@/empathy-call-chandler