#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"
{
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,
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
{
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 &&
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;
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
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 *
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;
}
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,
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);
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
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)
{
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);
+}