/*
* empathy-call-handler.c - Source for EmpathyCallHandler
- * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2008-2009 Collabora Ltd.
* @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
#include <stdlib.h>
#include <telepathy-glib/util.h>
+#include <telepathy-glib/interfaces.h>
#include <telepathy-farsight/channel.h>
#include <telepathy-farsight/stream.h>
CONFERENCE_ADDED,
SRC_PAD_ADDED,
SINK_PAD_ADDED,
+ REQUEST_RESOURCE,
CLOSED,
+ STREAM_CLOSED,
LAST_SIGNAL
};
enum {
PROP_TP_CALL = 1,
PROP_GST_BUS,
- PROP_CONTACT
+ PROP_CONTACT,
+ PROP_INITIAL_AUDIO,
+ PROP_INITIAL_VIDEO
};
/* private structure */
EmpathyTpCall *call;
EmpathyContact *contact;
TfChannel *tfchannel;
+ gboolean initial_audio;
+ gboolean initial_video;
} EmpathyCallHandlerPriv;
#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCallHandler)
obj->priv = priv;
}
+static void
+empathy_call_handler_constructed (GObject *object)
+{
+ EmpathyCallHandlerPriv *priv = GET_PRIV (object);
+
+ if (priv->contact == NULL)
+ {
+ g_object_get (priv->call, "contact", &(priv->contact), NULL);
+ }
+}
+
static void
empathy_call_handler_set_property (GObject *object,
guint property_id, const GValue *value, GParamSpec *pspec)
case PROP_TP_CALL:
priv->call = g_value_dup_object (value);
break;
+ case PROP_INITIAL_AUDIO:
+ priv->initial_audio = g_value_get_boolean (value);
+ break;
+ case PROP_INITIAL_VIDEO:
+ priv->initial_video = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
case PROP_TP_CALL:
g_value_set_object (value, priv->call);
break;
+ case PROP_INITIAL_AUDIO:
+ g_value_set_boolean (value, priv->initial_audio);
+ break;
+ case PROP_INITIAL_VIDEO:
+ g_value_set_boolean (value, priv->initial_video);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
g_type_class_add_private (klass, sizeof (EmpathyCallHandlerPriv));
+ object_class->constructed = empathy_call_handler_constructed;
object_class->set_property = empathy_call_handler_set_property;
object_class->get_property = empathy_call_handler_get_property;
object_class->dispose = empathy_call_handler_dispose;
param_spec = g_param_spec_object ("contact",
"contact", "The remote contact",
EMPATHY_TYPE_CONTACT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_CONTACT, param_spec);
param_spec = g_param_spec_object ("tp-call",
"tp-call", "The calls channel wrapper",
EMPATHY_TYPE_TP_CALL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_TP_CALL, param_spec);
+ param_spec = g_param_spec_boolean ("initial-audio",
+ "initial-audio", "Whether the call should start with audio",
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIAL_AUDIO,
+ param_spec);
+
+ param_spec = g_param_spec_boolean ("initial-video",
+ "initial-video", "Whether the call should start with video",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_INITIAL_VIDEO,
+ param_spec);
+
signals[CONFERENCE_ADDED] =
g_signal_new ("conference-added", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
G_TYPE_NONE,
2, GST_TYPE_PAD, G_TYPE_UINT);
+ signals[REQUEST_RESOURCE] =
+ g_signal_new ("request-resource", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0,
+ g_signal_accumulator_true_handled, NULL,
+ _empathy_marshal_BOOLEAN__UINT_UINT,
+ G_TYPE_BOOLEAN, 2, G_TYPE_UINT, G_TYPE_UINT);
+
signals[CLOSED] =
g_signal_new ("closed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+
+ signals[STREAM_CLOSED] =
+ g_signal_new ("stream-closed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, TF_TYPE_STREAM);
}
+/**
+ * empathy_call_handler_new_for_contact:
+ * @contact: an #EmpathyContact
+ *
+ * Creates a new #EmpathyCallHandler with contact @contact.
+ *
+ * Return value: a new #EmpathyCallHandler
+ */
EmpathyCallHandler *
empathy_call_handler_new_for_contact (EmpathyContact *contact)
{
"contact", contact, NULL));
}
+/**
+ * empathy_call_handler_new_for_contact_with_streams:
+ * @contact: an #EmpathyContact
+ * @audio: if %TRUE the call will be started with audio
+ * @video: if %TRUE the call will be started with video
+ *
+ * Creates a new #EmpathyCallHandler with contact @contact.
+ *
+ * Return value: a new #EmpathyCallHandler
+ */
+EmpathyCallHandler *
+empathy_call_handler_new_for_contact_with_streams (EmpathyContact *contact,
+ gboolean audio, gboolean video)
+{
+ return EMPATHY_CALL_HANDLER (g_object_new (EMPATHY_TYPE_CALL_HANDLER,
+ "contact", contact,
+ "initial-audio", audio,
+ "initial-video", video,
+ NULL));
+}
+
EmpathyCallHandler *
empathy_call_handler_new_for_channel (EmpathyTpCall *call)
{
return EMPATHY_CALL_HANDLER (g_object_new (EMPATHY_TYPE_CALL_HANDLER,
- "tp-call", call, NULL));
+ "tp-call", call,
+ "initial-video", empathy_tp_call_is_receiving_video (call),
+ NULL));
}
void
empathy_call_handler_tf_stream_request_resource_cb (TfStream *stream,
guint direction, EmpathyTpCall *call)
{
- return TRUE;
+ gboolean ret;
+ guint media_type;
+
+ g_object_get (G_OBJECT (stream), "media-type", &media_type, NULL);
+
+ g_signal_emit (G_OBJECT (call),
+ signals[REQUEST_RESOURCE], 0, media_type, direction, &ret);
+
+ return ret;
+}
+
+static void
+empathy_call_handler_tf_stream_closed_cb (TfStream *stream,
+ EmpathyCallHandler *handler)
+{
+ g_signal_emit (handler, signals[STREAM_CLOSED], 0, stream);
}
static void
g_signal_connect (stream, "request-resource",
G_CALLBACK (empathy_call_handler_tf_stream_request_resource_cb),
handler);
+ g_signal_connect (stream, "closed",
+ G_CALLBACK (empathy_call_handler_tf_stream_closed_cb), handler);
g_object_get (stream, "media-type", &media_type,
"sink-pad", &spad, NULL);
g_signal_emit (G_OBJECT (handler), signals[CLOSED], 0);
}
-static GList *
-empathy_call_handler_tf_channel_codec_config_get_defaults (FsCodec *codecs)
-{
- GList *l = NULL;
- int i;
-
- for (i = 0; codecs[i].encoding_name != NULL; i++)
- l = g_list_append (l, fs_codec_copy (codecs + i));
-
- return l;
-}
-
static GList *
empathy_call_handler_tf_channel_codec_config_cb (TfChannel *channel,
guint stream_id, FsMediaType media_type, guint direction, gpointer user_data)
{
- FsCodec audio_codecs[] = {
- { FS_CODEC_ID_ANY, "SPEEX", FS_MEDIA_TYPE_AUDIO, 16000, },
- { FS_CODEC_ID_ANY, "SPEEX", FS_MEDIA_TYPE_AUDIO, 8000, },
-
- { FS_CODEC_ID_DISABLE, "DV", FS_MEDIA_TYPE_AUDIO, },
- { FS_CODEC_ID_DISABLE, "MPA", FS_MEDIA_TYPE_AUDIO, },
- { FS_CODEC_ID_DISABLE, "VORBIS", FS_MEDIA_TYPE_AUDIO, },
- { FS_CODEC_ID_DISABLE, "MP3", FS_MEDIA_TYPE_AUDIO, },
- { 0, NULL, 0,}
- };
- FsCodec video_codecs[] = {
- { FS_CODEC_ID_ANY, "H264", FS_MEDIA_TYPE_VIDEO, },
- { FS_CODEC_ID_ANY, "THEORA", FS_MEDIA_TYPE_VIDEO, },
- { FS_CODEC_ID_ANY, "H263", FS_MEDIA_TYPE_VIDEO, },
-
- { FS_CODEC_ID_DISABLE, "DV", FS_MEDIA_TYPE_VIDEO, },
- { FS_CODEC_ID_DISABLE, "JPEG", FS_MEDIA_TYPE_VIDEO, },
- { FS_CODEC_ID_DISABLE, "MPV", FS_MEDIA_TYPE_VIDEO, },
- { 0, NULL, 0}
- };
-
- switch (media_type)
+ gchar *filename = empathy_file_lookup ("codec-preferences", "data");
+ GList *codecs;
+ GError *error = NULL;
+
+ codecs = fs_codec_list_from_keyfile (filename, &error);
+ g_free (filename);
+
+ if (!codecs)
{
- case FS_MEDIA_TYPE_AUDIO:
- return empathy_call_handler_tf_channel_codec_config_get_defaults
- (audio_codecs);
- case FS_MEDIA_TYPE_VIDEO:
- return empathy_call_handler_tf_channel_codec_config_get_defaults
- (video_codecs);
+ g_warning ("No codec-preferences file: %s",
+ error ? error->message : "No error message");
}
+ g_clear_error (&error);
- return NULL;
+ return codecs;
}
static void
empathy_dispatch_operation_get_channel_wrapper (operation));
g_object_ref (priv->call);
+ g_object_notify (G_OBJECT (self), "tp-call");
empathy_call_handler_start_tpfs (self);
- empathy_tp_call_to (priv->call, priv->contact);
+ empathy_tp_call_to (priv->call, priv->contact,
+ priv->initial_audio, priv->initial_video);
empathy_dispatch_operation_claim (operation);
}
-static void
-empathy_call_handler_contact_ready_cb (EmpathyContact *contact,
- const GError *error, gpointer user_data, GObject *object)
+void
+empathy_call_handler_start_call (EmpathyCallHandler *handler)
{
- EmpathyCallHandler *self = EMPATHY_CALL_HANDLER (object);
- EmpathyCallHandlerPriv *priv = GET_PRIV (self);
+
+ EmpathyCallHandlerPriv *priv = GET_PRIV (handler);
EmpathyDispatcher *dispatcher;
- McAccount *account;
- GStrv allowed;
+ TpConnection *connection;
+ GList *classes;
GValue *value;
- GHashTable *request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
- (GDestroyNotify) tp_g_value_slice_free);
+ GHashTable *request;
+
+ if (priv->call != NULL)
+ {
+ empathy_call_handler_start_tpfs (handler);
+ empathy_tp_call_accept_incoming_call (priv->call);
+ return;
+ }
g_assert (priv->contact != NULL);
dispatcher = empathy_dispatcher_dup_singleton ();
- account = empathy_contact_get_account (priv->contact);
- allowed = empathy_dispatcher_find_channel_class (dispatcher, account,
- TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, TP_HANDLE_TYPE_CONTACT);
+ connection = empathy_contact_get_connection (priv->contact);
+ classes = empathy_dispatcher_find_requestable_channel_classes
+ (dispatcher, connection, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ TP_HANDLE_TYPE_CONTACT, NULL);
- if (!tp_strv_contains ((const gchar * const *)allowed,
- TP_IFACE_CHANNEL ".TargetHandle"))
- g_assert_not_reached ();
+ if (classes == NULL)
+ return;
+
+ g_list_free (classes);
+
+ request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+ (GDestroyNotify) tp_g_value_slice_free);
/* org.freedesktop.Telepathy.Channel.ChannelType */
value = tp_g_value_slice_new (G_TYPE_STRING);
g_value_set_uint (value, empathy_contact_get_handle (priv->contact));
g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value);
- empathy_dispatcher_create_channel (dispatcher, account,
- request, empathy_call_handler_request_cb, self);
+ empathy_dispatcher_create_channel (dispatcher, connection,
+ request, empathy_call_handler_request_cb, handler);
g_object_unref (dispatcher);
}
+/**
+ * empathy_call_handler_stop_call:
+ * @handler: an #EmpathyCallHandler
+ *
+ * Closes the #EmpathyCallHandler's call and frees its resources.
+ */
void
-empathy_call_handler_start_call (EmpathyCallHandler *handler)
+empathy_call_handler_stop_call (EmpathyCallHandler *handler)
{
-
EmpathyCallHandlerPriv *priv = GET_PRIV (handler);
- if (priv->call == NULL)
- {
- empathy_contact_call_when_ready (priv->contact,
- EMPATHY_CONTACT_READY_HANDLE,
- empathy_call_handler_contact_ready_cb, NULL, NULL, G_OBJECT (handler));
- }
- else
+ if (priv->call != NULL)
{
- empathy_call_handler_start_tpfs (handler);
- empathy_tp_call_accept_incoming_call (priv->call);
+ empathy_tp_call_close (priv->call);
+ g_object_unref (priv->call);
}
+
+ priv->call = NULL;
+}
+
+/**
+ * empathy_call_handler_has_initial_video:
+ * @handler: an #EmpathyCallHandler
+ *
+ * Return %TRUE if the call managed by this #EmpathyCallHandler was
+ * created with video enabled
+ *
+ * Return value: %TRUE if the call was created as a video conversation.
+ */
+gboolean
+empathy_call_handler_has_initial_video (EmpathyCallHandler *handler)
+{
+ EmpathyCallHandlerPriv *priv = GET_PRIV (handler);
+
+ return priv->initial_video;
}
+