]> git.0d.be Git - empathy.git/blobdiff - libempathy/empathy-tp-call.c
add myself to AUTHORS
[empathy.git] / libempathy / empathy-tp-call.c
index 41f573fd261486d5cb5315576a2e3c1d434dc3f5..6d0941c396d47115cb8b78b9b942576dfc2c644c 100644 (file)
 #include <telepathy-glib/proxy-subclass.h>
 #include <telepathy-glib/dbus.h>
 #include <telepathy-glib/interfaces.h>
-#include <telepathy-farsight/channel.h>
-#include <telepathy-farsight/stream.h>
-
-#include <gst/gst.h>
 
 #include "empathy-tp-call.h"
-#include "empathy-contact-factory.h"
+#include "empathy-tp-contact-factory.h"
 #include "empathy-utils.h"
+#include "empathy-marshal.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TP
 #include "empathy-debug.h"
@@ -42,17 +39,23 @@ typedef struct
 {
   gboolean dispose_has_run;
   TpChannel *channel;
-  TfChannel *tfchannel;
   EmpathyContact *contact;
   gboolean is_incoming;
   guint status;
 
-  GstElement *pipeline;
-
   EmpathyTpCallStream *audio;
   EmpathyTpCallStream *video;
 } EmpathyTpCallPriv;
 
+/* signal enum */
+enum {
+  AUDIO_STREAM_ERROR,
+  VIDEO_STREAM_ERROR,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
 enum
 {
   PROP_0,
@@ -260,22 +263,27 @@ tp_call_request_streams_for_capabilities (EmpathyTpCall *call,
   g_array_free (stream_types, TRUE);
 }
 
-static EmpathyContact *
-tp_call_dup_contact_from_handle (EmpathyTpCall *call, TpHandle handle)
+static void
+tp_call_got_contact_cb (EmpathyTpContactFactory *factory,
+                        EmpathyContact          *contact,
+                        const GError            *error,
+                        gpointer                 user_data,
+                        GObject                 *call)
 {
   EmpathyTpCallPriv *priv = GET_PRIV (call);
-  EmpathyContactFactory *factory;
-  McAccount *account;
-  EmpathyContact *contact;
-
-  factory = empathy_contact_factory_dup_singleton ();
-  account = empathy_channel_get_account (priv->channel);
-  contact = empathy_contact_factory_get_from_handle (factory, account, handle);
 
-  g_object_unref (factory);
-  g_object_unref (account);
+  if (error)
+    {
+      DEBUG ("Error: %s", error->message);
+      return;
+    }
 
-  return contact;
+  priv->contact = g_object_ref (contact);
+  priv->is_incoming = TRUE;
+  priv->status = EMPATHY_TP_CALL_STATUS_PENDING;
+  g_object_notify (G_OBJECT (call), "is-incoming");
+  g_object_notify (G_OBJECT (call), "contact");
+  g_object_notify (G_OBJECT (call), "status");
 }
 
 static void
@@ -295,13 +303,15 @@ tp_call_update_status (EmpathyTpCall *call)
     {
       if (priv->contact == NULL && iter.element != self_handle)
         {
+          EmpathyTpContactFactory *factory;
+          TpConnection *connection;
+
           /* We found the remote contact */
-          priv->contact = tp_call_dup_contact_from_handle (call, iter.element);
-          priv->is_incoming = TRUE;
-          priv->status = EMPATHY_TP_CALL_STATUS_PENDING;
-          g_object_notify (G_OBJECT (call), "is-incoming");
-          g_object_notify (G_OBJECT (call), "contact");
-          g_object_notify (G_OBJECT (call), "status");
+          connection = tp_channel_borrow_connection (priv->channel);
+          factory = empathy_tp_contact_factory_dup_singleton (connection);
+          empathy_tp_contact_factory_get_from_handle (factory, iter.element,
+              tp_call_got_contact_cb, NULL, NULL, G_OBJECT (call));
+          g_object_unref (factory);
         }
 
       if (priv->status == EMPATHY_TP_CALL_STATUS_PENDING &&
@@ -316,24 +326,14 @@ tp_call_update_status (EmpathyTpCall *call)
   g_object_unref (call);
 }
 
-static void
-tp_call_members_changed_cb (TpChannel *channel,
-                            gchar *message,
-                            GArray *added,
-                            GArray *removed,
-                            GArray *local_pending,
-                            GArray *remote_pending,
-                            guint actor,
-                            guint reason,
-                            EmpathyTpCall *call)
-{
-  tp_call_update_status (call);
-}
-
 void
-empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact)
+empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact,
+  gboolean audio, gboolean video)
 {
   EmpathyTpCallPriv *priv = GET_PRIV (call);
+  EmpathyCapabilities capabilities = 0;
+
+  g_assert (audio || video);
 
   priv->contact = g_object_ref (contact);
   priv->is_incoming = FALSE;
@@ -341,8 +341,13 @@ empathy_tp_call_to (EmpathyTpCall *call, EmpathyContact *contact)
   g_object_notify (G_OBJECT (call), "is-incoming");
   g_object_notify (G_OBJECT (call), "contact");
   g_object_notify (G_OBJECT (call), "status");
-  tp_call_request_streams_for_capabilities (call,
-     EMPATHY_CAPABILITIES_AUDIO);
+
+  if (video)
+    capabilities |= EMPATHY_CAPABILITIES_VIDEO;
+  if (audio)
+    capabilities |= EMPATHY_CAPABILITIES_AUDIO;
+
+  tp_call_request_streams_for_capabilities (call, capabilities);
 }
 
 static void
@@ -366,135 +371,35 @@ tp_call_async_cb (TpProxy *proxy,
                   GObject *call)
 {
   if (error)
-      DEBUG ("Error %s: %s", (gchar*) user_data, error->message);
-}
-
-static void
-tp_call_close_channel (EmpathyTpCall *call)
-{
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  if (priv->status == EMPATHY_TP_CALL_STATUS_CLOSED)
-      return;
-
-  DEBUG ("Closing channel");
-
-  tp_cli_channel_call_close (priv->channel, -1,
-      NULL, NULL, NULL, NULL);
-
-  priv->status = EMPATHY_TP_CALL_STATUS_CLOSED;
-  g_object_notify (G_OBJECT (call), "status");
-}
-
-static gboolean
-tp_call_pipeline_bus_watch (GstBus *bus, GstMessage *message,
-  gpointer user_data)
-{
-  EmpathyTpCall *call = EMPATHY_TP_CALL (user_data);
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_assert (priv->tfchannel != NULL);
-
-  tf_channel_bus_message (priv->tfchannel, message);
-
-  return TRUE;
+      DEBUG ("Error %s: %s", (gchar *) user_data, error->message);
 }
 
 static void
-tp_call_tf_channel_session_created_cb (TfChannel *tfchannel,
-  FsConference *conference, FsParticipant *participant, EmpathyTpCall *call)
+tp_call_stream_error_cb (TpChannel *channel,
+    guint stream_id,
+    guint error_code,
+    const gchar *msg,
+    gpointer user_data,
+    GObject *call)
 {
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-  GstBus *bus;
-
-  g_assert (priv->pipeline == NULL);
+  EmpathyTpCall *self = EMPATHY_TP_CALL (call);
+  EmpathyTpCallPriv *priv = GET_PRIV (self);
 
-  priv->pipeline = gst_pipeline_new ("call-pipeline");
+  DEBUG ("Stream error on stream %u: %s (code: %u)", stream_id, msg,
+      error_code);
 
-  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
-  gst_bus_add_watch (bus, tp_call_pipeline_bus_watch, call);
-  gst_object_unref (bus);
-
-  gst_bin_add ( GST_BIN (priv->pipeline), GST_ELEMENT (conference));
-  gst_element_set_state ( GST_ELEMENT(priv->pipeline), GST_STATE_PLAYING);
-}
-
-static void
-tp_call_tf_stream_src_pad_added_cb (TfStream *stream, GstPad   *pad,
-  FsCodec  *codec, EmpathyTpCall  *call)
-{
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-  guint media_type;
-  GstElement *sink;
-  GstPad *spad;
-
-  g_object_get (stream, "media-type", &media_type, NULL);
-
-  switch (media_type)
+  if (priv->audio->id == stream_id)
     {
-      case TP_MEDIA_STREAM_TYPE_AUDIO:
-        sink = gst_element_factory_make ("gconfaudiosink", NULL);
-        break;
-      case TP_MEDIA_STREAM_TYPE_VIDEO:
-        sink = gst_element_factory_make ("gconfvideosink", NULL);
-        break;
-      default:
-        g_assert_not_reached();
+      g_signal_emit (call, signals[AUDIO_STREAM_ERROR], 0, error_code, msg);
     }
-
-  gst_bin_add ( GST_BIN (priv->pipeline), sink);
-  gst_element_set_state (sink, GST_STATE_PLAYING);
-
-  spad = gst_element_get_static_pad (sink, "sink");
-  gst_pad_link (pad, spad);
-  gst_object_unref (spad);
-}
-
-
-static gboolean
-tp_call_tf_stream_request_resource_cb (TfStream *stream,
-  guint direction, EmpathyTpCall *call)
-{
-  return TRUE;
-}
-
-static void
-tp_call_tf_channel_stream_created_cb (TfChannel *tfchannel, TfStream *stream,
-  EmpathyTpCall *call)
-{
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-  guint media_type;
-  GstElement *src;
-  GstPad *pad, *spad;
-
-  g_signal_connect (stream, "src-pad-added",
-      G_CALLBACK (tp_call_tf_stream_src_pad_added_cb), call);
-  g_signal_connect (stream, "request-resource",
-      G_CALLBACK (tp_call_tf_stream_request_resource_cb), call);
-
-
-  g_object_get (stream, "media-type", &media_type,
-    "sink-pad", &spad, NULL);
-
-  switch (media_type)
+  else if (priv->video->id == stream_id)
     {
-      case TP_MEDIA_STREAM_TYPE_AUDIO:
-        src = gst_element_factory_make ("gconfaudiosrc", NULL);
-        break;
-      case TP_MEDIA_STREAM_TYPE_VIDEO:
-        src = gst_element_factory_make ("gconfvideosrc", NULL);
-        break;
-      default:
-        g_assert_not_reached();
+      g_signal_emit (call, signals[VIDEO_STREAM_ERROR], 0, error_code, msg);
+    }
+  else
+    {
+      DEBUG ("Unknown stream id: %u", stream_id);
     }
-
-  gst_bin_add (GST_BIN (priv->pipeline), src);
-
-  pad = gst_element_get_static_pad (src, "src");
-  gst_pad_link (pad, spad);
-  gst_object_unref (spad);
-
-  gst_element_set_state (src, GST_STATE_PLAYING);
 }
 
 static GObject *
@@ -523,21 +428,15 @@ tp_call_constructor (GType type,
       tp_call_stream_state_changed_cb, NULL, NULL, G_OBJECT (call), NULL);
   tp_cli_channel_type_streamed_media_connect_to_stream_direction_changed (priv->channel,
       tp_call_stream_direction_changed_cb, NULL, NULL, G_OBJECT (call), NULL);
+  tp_cli_channel_type_streamed_media_connect_to_stream_error (priv->channel,
+      tp_call_stream_error_cb, NULL, NULL, G_OBJECT (call), NULL);
   tp_cli_channel_type_streamed_media_call_list_streams (priv->channel, -1,
       tp_call_request_streams_cb, NULL, NULL, G_OBJECT (call));
 
   /* Update status when members changes */
   tp_call_update_status (call);
-  g_signal_connect (priv->channel, "group-members-changed",
-      G_CALLBACK (tp_call_members_changed_cb), call);
-
-
-  /* Set up the telepathy farsight channel */
-  priv->tfchannel = tf_channel_new (priv->channel);
-  g_signal_connect (priv->tfchannel, "session-created",
-      G_CALLBACK (tp_call_tf_channel_session_created_cb), call);
-  g_signal_connect (priv->tfchannel, "stream-created",
-      G_CALLBACK (tp_call_tf_channel_stream_created_cb), call);
+  g_signal_connect_swapped (priv->channel, "group-members-changed",
+      G_CALLBACK (tp_call_update_status), call);
 
   return object;
 }
@@ -553,9 +452,6 @@ tp_call_dispose (GObject *object)
 
   priv->dispose_has_run = TRUE;
 
-  g_slice_free (EmpathyTpCallStream, priv->audio);
-  g_slice_free (EmpathyTpCallStream, priv->video);
-
   if (priv->channel != NULL)
     {
       g_signal_handlers_disconnect_by_func (priv->channel,
@@ -565,19 +461,6 @@ tp_call_dispose (GObject *object)
       priv->channel = NULL;
     }
 
-  if (priv->pipeline != NULL)
-    {
-      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-      gst_object_unref (priv->pipeline);
-      priv->pipeline = NULL;
-    }
-
-  if (priv->tfchannel != NULL)
-    {
-      g_object_unref (priv->tfchannel);
-      priv->tfchannel = NULL;
-    }
-
   if (priv->contact != NULL)
       g_object_unref (priv->contact);
 
@@ -689,6 +572,24 @@ empathy_tp_call_class_init (EmpathyTpCallClass *klass)
       g_param_spec_pointer ("video-stream", "Video stream data",
       "Video stream data",
       G_PARAM_READABLE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  signals[AUDIO_STREAM_ERROR] =
+    g_signal_new ("audio-stream-error",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0,
+      NULL, NULL,
+      _empathy_marshal_VOID__UINT_STRING,
+      G_TYPE_NONE,
+      2, G_TYPE_UINT, G_TYPE_STRING);
+
+  signals[VIDEO_STREAM_ERROR] =
+    g_signal_new ("video-stream-error",
+      G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0,
+      NULL, NULL,
+      _empathy_marshal_VOID__UINT_STRING,
+      G_TYPE_NONE,
+      2, G_TYPE_UINT, G_TYPE_STRING);
 }
 
 static void
@@ -784,84 +685,6 @@ empathy_tp_call_request_video_stream_direction (EmpathyTpCall *call,
       tp_call_async_cb, NULL, NULL, G_OBJECT (call));
 }
 
-void
-empathy_tp_call_add_preview_video (EmpathyTpCall *call,
-                                   guint preview_video_socket_id)
-{
-  //EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-
-  DEBUG ("Adding preview video");
-
-  /* FIXME add the preview window */
-}
-
-void
-empathy_tp_call_remove_preview_video (EmpathyTpCall *call,
-                                      guint preview_video_socket_id)
-{
-  //EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-
-  DEBUG ("Removing preview video");
-
-  /* FIXME remove the preview window */
-}
-
-void
-empathy_tp_call_add_output_video (EmpathyTpCall *call,
-                                  guint output_video_socket_id)
-{
-  //EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-
-  DEBUG ("Adding output video - socket: %d", output_video_socket_id);
-
-  /* FIXME add output window */
-}
-
-void
-empathy_tp_call_set_output_volume (EmpathyTpCall *call,
-                                   guint volume)
-{
-  EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-  g_return_if_fail (priv->status != EMPATHY_TP_CALL_STATUS_CLOSED);
-
-  DEBUG ("Setting output volume: %d", volume);
-
-  /* FIXME set volume */
-}
-
-void
-empathy_tp_call_mute_output (EmpathyTpCall *call,
-                             gboolean is_muted)
-{
-  //EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-
-  DEBUG ("Setting output mute: %d", is_muted);
-  /* FIXME mute output */
-}
-
-void
-empathy_tp_call_mute_input (EmpathyTpCall *call,
-                            gboolean is_muted)
-{
-  //EmpathyTpCallPriv *priv = GET_PRIV (call);
-
-  g_return_if_fail (EMPATHY_IS_TP_CALL (call));
-
-  DEBUG ("Setting input mute: %d", is_muted);
-
-  /* FIXME mute input */
-}
-
 void
 empathy_tp_call_start_tone (EmpathyTpCall *call, TpDTMFEvent event)
 {
@@ -907,3 +730,67 @@ empathy_tp_call_has_dtmf (EmpathyTpCall *call)
       TP_IFACE_QUARK_CHANNEL_INTERFACE_DTMF);
 }
 
+/**
+ * empathy_tp_call_is_receiving_video:
+ * @call: the call
+ *
+ * Indicates if the call is receiving video or not.
+ *
+ * Returns: %TRUE if the call is currently receiving video, %FALSE otherwise.
+ */
+gboolean
+empathy_tp_call_is_receiving_video (EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), FALSE);
+
+  if (!priv->video->exists)
+    return FALSE;
+
+  return priv->video->direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE ?
+      TRUE : FALSE;
+}
+
+/**
+ * empathy_tp_call_is_sending_video:
+ * @call: the call
+ *
+ * Indicates if the call is sending video or not.
+ *
+ * Returns: %TRUE if the call is currently sending video, %FALSE otherwise.
+ */
+gboolean
+empathy_tp_call_is_sending_video (EmpathyTpCall *call)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (call);
+
+  g_return_val_if_fail (EMPATHY_IS_TP_CALL (call), FALSE);
+
+  if (!priv->video->exists)
+    return FALSE;
+
+  return priv->video->direction & TP_MEDIA_STREAM_DIRECTION_SEND ?
+      TRUE : FALSE;
+}
+
+const gchar *
+empathy_tp_call_get_connection_manager (EmpathyTpCall *self)
+{
+  EmpathyTpCallPriv *priv = GET_PRIV (self);
+  TpConnection *conn;
+  TpAccount *account;
+
+  if (priv->channel == NULL)
+    return NULL;
+
+  conn = tp_channel_borrow_connection (priv->channel);
+  if (conn == NULL)
+    return NULL;
+
+  account = empathy_get_account_for_connection (conn);
+  if (account == NULL)
+    return NULL;
+
+  return tp_account_get_connection_manager (account);
+}