diff options
Diffstat (limited to 'rakia/media-manager.c')
-rw-r--r-- | rakia/media-manager.c | 349 |
1 files changed, 192 insertions, 157 deletions
diff --git a/rakia/media-manager.c b/rakia/media-manager.c index a630926..db4631e 100644 --- a/rakia/media-manager.c +++ b/rakia/media-manager.c @@ -28,12 +28,14 @@ #include <telepathy-glib/dbus.h> #include <telepathy-glib/interfaces.h> -#include "rakia/media-channel.h" #include "rakia/base-connection.h" +#include "rakia/call-channel.h" #include "rakia/handles.h" +#include "rakia/sip-session.h" #include <sofia-sip/sip_status.h> + #define DEBUG_FLAG RAKIA_DEBUG_CONNECTION #include "rakia/debug.h" @@ -41,6 +43,10 @@ static void channel_manager_iface_init (gpointer, gpointer); static void rakia_media_manager_constructed (GObject *object); static void rakia_media_manager_close_all (RakiaMediaManager *fac); + +static RakiaSipSession * new_session (RakiaMediaManager *fac, nua_handle_t *nh, + TpHandle handle); + G_DEFINE_TYPE_WITH_CODE (RakiaMediaManager, rakia_media_manager, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, @@ -54,12 +60,11 @@ enum LAST_PROPERTY }; -typedef struct _RakiaMediaManagerPrivate RakiaMediaManagerPrivate; struct _RakiaMediaManagerPrivate { /* unreferenced (since it owns this manager) */ TpBaseConnection *conn; - /* array of referenced (RakiaMediaChannel *) */ + /* array of referenced (RakiaCallChannel *) */ GPtrArray *channels; /* for unique channel object paths, currently always increments */ guint channel_index; @@ -73,15 +78,26 @@ struct _RakiaMediaManagerPrivate gboolean dispose_has_run; }; -#define RAKIA_MEDIA_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RAKIA_TYPE_MEDIA_MANAGER, RakiaMediaManagerPrivate)) +#define RAKIA_MEDIA_MANAGER_GET_PRIVATE(fac) ((fac)->priv) + +static void +close_channel_and_unref (gpointer data) +{ + TpBaseChannel *chan = data; + tp_base_channel_close (chan); + g_object_unref (chan); +} static void rakia_media_manager_init (RakiaMediaManager *fac) { - RakiaMediaManagerPrivate *priv = RAKIA_MEDIA_MANAGER_GET_PRIVATE (fac); + RakiaMediaManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (fac, + RAKIA_TYPE_MEDIA_MANAGER, RakiaMediaManagerPrivate); + + fac->priv = priv; priv->conn = NULL; - priv->channels = g_ptr_array_sized_new (1); + priv->channels = g_ptr_array_new_with_free_func (close_channel_and_unref); priv->channel_index = 0; priv->dispose_has_run = FALSE; } @@ -214,17 +230,10 @@ rakia_media_manager_close_all (RakiaMediaManager *fac) if (priv->channels != NULL) { GPtrArray *channels; - guint i; channels = priv->channels; priv->channels = NULL; - for (i = 0; i < channels->len; i++) - { - RakiaMediaChannel *chan = g_ptr_array_index (channels, i); - g_object_unref (chan); - } - g_ptr_array_unref (channels); } } @@ -235,7 +244,7 @@ rakia_media_manager_close_all (RakiaMediaManager *fac) * that #RakiaMediaManager holds to them. */ static void -media_channel_closed_cb (RakiaMediaChannel *chan, gpointer user_data) +call_channel_closed_cb (RakiaCallChannel *chan, gpointer user_data) { RakiaMediaManager *fac = RAKIA_MEDIA_MANAGER (user_data); RakiaMediaManagerPrivate *priv = RAKIA_MEDIA_MANAGER_GET_PRIVATE (fac); @@ -246,35 +255,36 @@ media_channel_closed_cb (RakiaMediaChannel *chan, gpointer user_data) if (priv->channels) { g_ptr_array_remove_fast (priv->channels, chan); - g_object_unref (chan); } } /** - * new_media_channel + * new_call_channel * - * Creates a new empty RakiaMediaChannel. + * Creates a new empty RakiaCallChannel. */ -static RakiaMediaChannel * -new_media_channel (RakiaMediaManager *fac, +static RakiaCallChannel * +new_call_channel (RakiaMediaManager *fac, TpHandle initiator, TpHandle maybe_peer, - GHashTable *request_properties) + GHashTable *request_properties, + RakiaSipSession *session) { RakiaMediaManagerPrivate *priv; - RakiaMediaChannel *chan = NULL; + RakiaCallChannel *chan = NULL; gchar *object_path; - const gchar *nat_traversal = "none"; gboolean initial_audio = FALSE; gboolean initial_video = FALSE; gboolean immutable_streams = FALSE; const gchar *dtmf_initial_tones = NULL; + const gchar *initial_audio_name = NULL; + const gchar *initial_video_name = NULL; g_assert (initiator != 0); priv = RAKIA_MEDIA_MANAGER_GET_PRIVATE (fac); - object_path = g_strdup_printf ("%s/MediaChannel%u", priv->conn->object_path, + object_path = g_strdup_printf ("%s/CallChannel%u", priv->conn->object_path, priv->channel_index++); DEBUG("channel object path %s", object_path); @@ -282,68 +292,122 @@ new_media_channel (RakiaMediaManager *fac, if (request_properties != NULL) { initial_audio = tp_asv_get_boolean (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialAudio", NULL); + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, NULL); initial_video = tp_asv_get_boolean (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialVideo", NULL); + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, NULL); + initial_audio_name = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO_NAME); + initial_video_name = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO_NAME); dtmf_initial_tones = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL_INTERFACE_DTMF ".InitialTones"); + TP_PROP_CHANNEL_INTERFACE_DTMF_INITIAL_TONES); } g_object_get (priv->conn, "immutable-streams", &immutable_streams, NULL); - if (priv->stun_server != NULL) - { - nat_traversal = "stun"; - } - - chan = g_object_new (RAKIA_TYPE_MEDIA_CHANNEL, + chan = g_object_new (RAKIA_TYPE_CALL_CHANNEL, "connection", priv->conn, "object-path", object_path, "handle", maybe_peer, - "initiator", initiator, + "initiator-handle", initiator, "initial-audio", initial_audio, "initial-video", initial_video, - "immutable-streams", immutable_streams, - "nat-traversal", nat_traversal, + "initial-audio-name", initial_audio_name, + "initial-video-name", initial_video_name, + "initial-transport", TP_STREAM_TRANSPORT_TYPE_RAW_UDP, + "mutable-contents", !immutable_streams, "initial-tones", dtmf_initial_tones, + "sip-session", session, + "stun-server", priv->stun_server ? priv->stun_server : + "", + "stun-port", priv->stun_port, + "requested", (initiator == priv->conn->self_handle), NULL); g_free (object_path); - if (priv->stun_server != NULL) - { - g_object_set ((GObject *) chan, "stun-server", priv->stun_server, NULL); - if (priv->stun_port != 0) - g_object_set ((GObject *) chan, "stun-port", priv->stun_port, NULL); - } - g_signal_connect (chan, "closed", G_CALLBACK (media_channel_closed_cb), fac); + g_signal_connect (chan, "closed", G_CALLBACK (call_channel_closed_cb), fac); g_ptr_array_add (priv->channels, chan); + tp_base_channel_register (TP_BASE_CHANNEL (chan)); + return chan; } + +static RakiaSipSession * +new_session (RakiaMediaManager *fac, + nua_handle_t *nh, + TpHandle handle) +{ + RakiaMediaManagerPrivate *priv = RAKIA_MEDIA_MANAGER_GET_PRIVATE (fac); + RakiaSipSession *session; + gboolean outgoing = (nh == NULL); + gboolean immutable_streams = FALSE; + + g_object_get (priv->conn, + "immutable-streams", &immutable_streams, + NULL); + + if (outgoing) + { + nh = rakia_base_connection_create_handle ( + RAKIA_BASE_CONNECTION (priv->conn), handle); + } + + session = rakia_sip_session_new (nh, RAKIA_BASE_CONNECTION (priv->conn), + !outgoing, immutable_streams); + + if (outgoing) + { + nua_handle_unref (nh); + } + + return session; +} + + +struct InviteData { + RakiaMediaManager *fac; + TpHandle handle; +}; + static void -incoming_call_cb (RakiaMediaChannel *channel, - RakiaMediaManager *fac) +incoming_call_cb (RakiaSipSession *session, + struct InviteData *idata) { - g_signal_handlers_disconnect_by_func (channel, - G_CALLBACK (incoming_call_cb), fac); - tp_channel_manager_emit_new_channel (fac, + RakiaCallChannel *channel; + RakiaMediaManagerPrivate *priv = + RAKIA_MEDIA_MANAGER_GET_PRIVATE (idata->fac); + + g_signal_handlers_disconnect_by_func (session, + G_CALLBACK (incoming_call_cb), idata); + + channel = new_call_channel (idata->fac, idata->handle, idata->handle, NULL, + session); + + tp_channel_manager_emit_new_channel (idata->fac, TP_EXPORTABLE_CHANNEL (channel), NULL); + + g_object_unref (session); + rakia_handle_unref (priv->conn, idata->handle); + g_slice_free (struct InviteData, idata); } + static gboolean rakia_nua_i_invite_cb (TpBaseConnection *conn, const RakiaNuaEvent *ev, tagi_t tags[], RakiaMediaManager *fac) { - RakiaMediaChannel *channel; TpHandle handle; + RakiaSipSession *session; + struct InviteData *idata; /* figure out a handle for the identity */ @@ -362,19 +426,20 @@ rakia_nua_i_invite_cb (TpBaseConnection *conn, { DEBUG("cannot handle calls from self"); nua_respond (ev->nua_handle, 501, "Calls from self are not supported", TAG_END()); + /* FIXME: Possible handle leak.. needs double checking ? */ return TRUE; } - channel = new_media_channel (fac, handle, handle, NULL); - - rakia_handle_unref (conn, handle); + session = new_session (fac, ev->nua_handle, 0); /* We delay emission of NewChannel(s) until we have the data on * initial media */ - g_signal_connect (channel, "incoming-call", - G_CALLBACK (incoming_call_cb), fac); + idata = g_slice_new (struct InviteData); + idata->fac = fac; + idata->handle = handle; - rakia_media_channel_attach_to_nua_handle (channel, ev->nua_handle); + g_signal_connect (session, "incoming-call", + G_CALLBACK (incoming_call_cb), idata); return TRUE; } @@ -446,17 +511,20 @@ rakia_media_manager_foreach_channel (TpChannelManager *manager, } static const gchar * const media_channel_fixed_properties[] = { - TP_IFACE_CHANNEL ".ChannelType", - TP_IFACE_CHANNEL ".TargetHandleType", + TP_PROP_CHANNEL_CHANNEL_TYPE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL }; static const gchar * const named_channel_allowed_properties[] = { - TP_IFACE_CHANNEL ".TargetHandle", - TP_IFACE_CHANNEL ".TargetID", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialAudio", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA ".InitialVideo", - TP_IFACE_CHANNEL_INTERFACE_DTMF ".InitialTones", + TP_PROP_CHANNEL_TARGET_HANDLE, + TP_PROP_CHANNEL_TARGET_ID, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO_NAME, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO_NAME, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_TRANSPORT, + TP_PROP_CHANNEL_INTERFACE_DTMF_INITIAL_TONES, NULL }; @@ -476,15 +544,26 @@ rakia_media_manager_type_foreach_channel_class (GType type, GValue *value, *handle_type_value; value = tp_g_value_slice_new (G_TYPE_STRING); - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); - g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value); + g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CALL); + g_hash_table_insert (table, TP_PROP_CHANNEL_CHANNEL_TYPE, value); handle_type_value = tp_g_value_slice_new (G_TYPE_UINT); /* no uint value yet - we'll change it for each channel class */ - g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType", + g_hash_table_insert (table, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, handle_type_value); g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_CONTACT); + + g_hash_table_insert (table, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, + tp_g_value_slice_new_boolean (TRUE)); + + func (type, table, named_channel_allowed_properties, user_data); + + g_hash_table_remove (table, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO); + + g_hash_table_insert (table, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, + tp_g_value_slice_new_boolean (TRUE)); + func (type, table, named_channel_allowed_properties, user_data); g_hash_table_unref (table); @@ -508,16 +587,15 @@ rakia_media_manager_requestotron (TpChannelManager *manager, TpBaseConnection *conn = (TpBaseConnection *) priv->conn; TpHandleType handle_type; TpHandle handle; - RakiaMediaChannel *channel = NULL; + RakiaSipSession *session; + RakiaCallChannel *channel = NULL; GError *error = NULL; GSList *request_tokens; - gboolean require_target_handle; - gboolean add_peer_to_remote_pending; + gboolean valid = FALSE; + gboolean initial_audio = FALSE; + gboolean initial_video = FALSE; /* Supported modes of operation: - * - RequestChannel(None, 0): - * channel is anonymous; - * caller uses RequestStreams to set the peer and start the call. * - RequestChannel(Contact, n) where n != 0: * channel has TargetHandle=n; * n is in remote pending; @@ -531,24 +609,20 @@ rakia_media_manager_requestotron (TpChannelManager *manager, * whatever properties and group membership it has; * otherwise the same as into CreateChannel */ - switch (method) - { - case METHOD_REQUEST: - require_target_handle = FALSE; - add_peer_to_remote_pending = TRUE; - break; - case METHOD_CREATE: - case METHOD_ENSURE: - require_target_handle = TRUE; - add_peer_to_remote_pending = FALSE; - break; - default: - g_assert_not_reached (); - } if (tp_strdiff (tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL ".ChannelType"), - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) + TP_PROP_CHANNEL_CHANNEL_TYPE), + TP_IFACE_CHANNEL_TYPE_CALL)) + return FALSE; + + if (tp_asv_get_boolean (request_properties, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, &valid) && valid) + initial_audio = TRUE; + if (tp_asv_get_boolean (request_properties, + TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, &valid) && valid) + initial_audio = TRUE; + + if (!initial_audio && !initial_video) return FALSE; handle_type = tp_asv_get_uint32 (request_properties, @@ -557,95 +631,56 @@ rakia_media_manager_requestotron (TpChannelManager *manager, handle = tp_asv_get_uint32 (request_properties, TP_IFACE_CHANNEL ".TargetHandle", NULL); - switch (handle_type) - { - case TP_HANDLE_TYPE_NONE: - g_assert (handle == 0); - - if (require_target_handle) - { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "A valid Contact handle must be provided when requesting a media " - "channel"); - goto error; - } - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - media_channel_fixed_properties, anon_channel_allowed_properties, - &error)) - goto error; + if (handle_type != TP_HANDLE_TYPE_CONTACT) + return FALSE; - channel = new_media_channel (self, conn->self_handle, 0, NULL); - break; + g_assert (handle != 0); - case TP_HANDLE_TYPE_CONTACT: - g_assert (handle != 0); + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + media_channel_fixed_properties, named_channel_allowed_properties, + &error)) + goto error; - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - media_channel_fixed_properties, named_channel_allowed_properties, - &error)) - goto error; + /* Calls to self are problematic in terms of StreamedMedia channel + * interface and its semantically required Group member changes; + * we disable them until a better API is available through + * Call channel type */ + if (handle == conn->self_handle) + { + g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + "Cannot call self"); + goto error; + } - /* Calls to self are problematic in terms of StreamedMedia channel - * interface and its semantically required Group member changes; - * we disable them until a better API is available through - * Call channel type */ - if (handle == conn->self_handle) - { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "Cannot call self"); - goto error; - } + if (method == METHOD_ENSURE) + { + guint i; + TpHandle peer = 0; - if (method == METHOD_ENSURE) + for (i = 0; i < priv->channels->len; i++) { - guint i; - TpHandle peer = 0; + channel = g_ptr_array_index (priv->channels, i); + g_object_get (channel, "peer", &peer, NULL); - for (i = 0; i < priv->channels->len; i++) + if (peer == handle) { - channel = g_ptr_array_index (priv->channels, i); - g_object_get (channel, "peer", &peer, NULL); - - if (peer == handle) - { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (channel)); - return TRUE; - } + tp_channel_manager_emit_request_already_satisfied (self, + request_token, TP_EXPORTABLE_CHANNEL (channel)); + return TRUE; } } - - channel = new_media_channel (self, conn->self_handle, handle, - request_properties); - - if (add_peer_to_remote_pending) - { - if (!_rakia_media_channel_add_member ((GObject *) channel, handle, - "", &error)) - { - /* FIXME: do we really want to emit Closed in this case? - * There wasn't a NewChannel/NewChannels emission */ - rakia_media_channel_close (channel); - goto error; - } - } - - break; - - default: - return FALSE; } - g_assert (channel != NULL); + session = new_session (self, NULL, handle); + channel = new_call_channel (self, conn->self_handle, handle, + request_properties, session); + g_object_unref (session); request_tokens = g_slist_prepend (NULL, request_token); tp_channel_manager_emit_new_channel (self, TP_EXPORTABLE_CHANNEL (channel), request_tokens); g_slist_free (request_tokens); - rakia_media_channel_create_initial_streams (channel); - return TRUE; error: |