diff options
author | Olivier CrĂȘte <olivier.crete@collabora.com> | 2012-02-29 15:36:44 -0500 |
---|---|---|
committer | Olivier CrĂȘte <olivier.crete@collabora.com> | 2012-02-29 15:36:44 -0500 |
commit | d90b713b5198cb6e0bb3e4c79b99198dec122806 (patch) | |
tree | e4d332b3498cba9c22a0648f2a87dab69791c8f1 | |
parent | 1d3e7ce04fa738443b382455625503d2d258ddfe (diff) |
Remove old streamed media files
-rw-r--r-- | rakia/media-channel.c | 2032 | ||||
-rw-r--r-- | rakia/media-channel.h | 94 | ||||
-rw-r--r-- | rakia/media-session.c | 1249 | ||||
-rw-r--r-- | rakia/media-session.h | 105 | ||||
-rw-r--r-- | rakia/media-stream.c | 1532 | ||||
-rw-r--r-- | rakia/media-stream.h | 93 |
6 files changed, 0 insertions, 5105 deletions
diff --git a/rakia/media-channel.c b/rakia/media-channel.c deleted file mode 100644 index dc0c5b7..0000000 --- a/rakia/media-channel.c +++ /dev/null @@ -1,2032 +0,0 @@ -/* - * sip-media-channel.c - Source for RakiaMediaChannel - * Copyright (C) 2005-2008 Collabora Ltd. - * Copyright (C) 2005-2010 Nokia Corporation - * @author Kai Vehmanen <first.surname@nokia.com> - * @author Mikhail Zabaluev <mikhail.zabaluev@nokia.com> - * - * Based on telepathy-gabble implementation (gabble-media-channel). - * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk> - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include "rakia/media-channel.h" - -#include <stdlib.h> -#include <string.h> - -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/dtmf.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> - -#include <rakia/event-target.h> - -#define DEBUG_FLAG RAKIA_DEBUG_MEDIA -#include "rakia/debug.h" - -#include <rakia/media-session.h> -#include <rakia/base-connection.h> -#include <rakia/sip-session.h> - -#define RAKIA_CHANNEL_CALL_STATE_PROCEEDING_MASK \ - (TP_CHANNEL_CALL_STATE_RINGING | \ - TP_CHANNEL_CALL_STATE_QUEUED | \ - TP_CHANNEL_CALL_STATE_IN_PROGRESS) - -/* DTMF dialstring playback durations in milliseconds */ -#define RAKIA_DTMF_TONE_DURATION 250 -#define RAKIA_DTMF_GAP_DURATION 100 -#define RAKIA_DTMF_PAUSE_DURATION 3000 - -static void event_target_init (gpointer, gpointer); -static void channel_iface_init (gpointer, gpointer); -static void media_signalling_iface_init (gpointer, gpointer); -static void streamed_media_iface_init (gpointer, gpointer); -static void dtmf_iface_init (gpointer, gpointer); -static void call_state_iface_init (gpointer, gpointer); -static void hold_iface_init (gpointer, gpointer); - -static void priv_session_dtmf_ready_cb (RakiaMediaSession *session, - RakiaMediaChannel *channel); - -G_DEFINE_TYPE_WITH_CODE (RakiaMediaChannel, rakia_media_channel, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (RAKIA_TYPE_EVENT_TARGET, event_target_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_PROPERTIES_INTERFACE, - tp_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, - tp_group_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - media_signalling_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DTMF, - dtmf_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CALL_STATE, - call_state_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_HOLD, - hold_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA, - streamed_media_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); - -static const gchar *rakia_media_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - TP_IFACE_CHANNEL_INTERFACE_DTMF, - TP_IFACE_CHANNEL_INTERFACE_CALL_STATE, - TP_IFACE_CHANNEL_INTERFACE_HOLD, - TP_IFACE_PROPERTIES_INTERFACE, - NULL -}; - -/* properties */ -enum -{ - PROP_CONNECTION = 1, - PROP_OBJECT_PATH, - PROP_CHANNEL_TYPE, - PROP_HANDLE_TYPE, - PROP_HANDLE, - PROP_TARGET_ID, - PROP_INITIATOR, - PROP_INITIATOR_ID, - PROP_REQUESTED, - PROP_INTERFACES, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_IMMUTABLE_STREAMS, - PROP_CURRENTLY_SENDING_TONES, - PROP_INITIAL_TONES, - PROP_DEFERRED_TONES, - PROP_SIP_SESSION, - /* Telepathy properties (see below too) */ - PROP_NAT_TRAVERSAL, - PROP_STUN_SERVER, - PROP_STUN_PORT, - LAST_PROPERTY -}; - -/* TP channel properties */ -enum -{ - TP_PROP_NAT_TRAVERSAL = 0, - TP_PROP_STUN_SERVER, - TP_PROP_STUN_PORT, - NUM_TP_PROPS -}; - -static const TpPropertySignature media_channel_property_signatures[NUM_TP_PROPS] = -{ - { "nat-traversal", G_TYPE_STRING }, - { "stun-server", G_TYPE_STRING }, - { "stun-port", G_TYPE_UINT }, -}; - -/* signals */ -enum -{ - NUM_SIGNALS -}; - -//static guint signals[NUM_SIGNALS] = { 0 }; - - -/* private structure */ -struct _RakiaMediaChannelPrivate -{ - RakiaBaseConnection *conn; - RakiaMediaSession *session; - RakiaSipSession *sipsession; - gchar *object_path; - TpHandle handle; - TpHandle initiator; - GHashTable *call_states; - gchar *stun_server; - guint stun_port; - TpDTMFPlayer *dtmf_player; - gchar *initial_tones; - gchar *deferred_tones; - - gboolean initial_audio; - gboolean initial_video; - gboolean immutable_streams; - gboolean closed; - gboolean dispose_has_run; -}; - - - -static void rakia_media_channel_dispose (GObject *object); -static void rakia_media_channel_finalize (GObject *object); -static void rakia_media_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); -static void rakia_media_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); - -static void priv_create_session (RakiaMediaChannel *channel, - TpHandle peer); -static void priv_destroy_session(RakiaMediaChannel *channel); - -static gboolean rakia_media_channel_remove_with_reason ( - GObject *iface, - TpHandle handle, - const gchar *message, - guint reason, - GError **error); -static void priv_session_state_changed_cb (RakiaSipSession *session, - guint old_state, - guint state, - RakiaMediaChannel *channel); - - -#define RAKIA_MEDIA_CHANNEL_GET_PRIVATE(chan) ((chan)->priv) - -/*********************************************************************** - * Set: Gobject interface - ***********************************************************************/ - -static void -rakia_media_channel_init (RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (self, - RAKIA_TYPE_MEDIA_CHANNEL, RakiaMediaChannelPrivate); - - self->priv = priv; - - /* allocate any data required by the object here */ - priv->call_states = g_hash_table_new (NULL, NULL); - - /* initialise the properties mixin *before* GObject - * sets the construct-time properties */ - tp_properties_mixin_init (G_OBJECT (self), - G_STRUCT_OFFSET (RakiaMediaChannel, properties)); -} - - - -static void -session_ringing_cb (RakiaSipSession *sipsession, RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - rakia_media_channel_change_call_state (self, priv->handle, - TP_CHANNEL_CALL_STATE_RINGING, 0); -} - -static void -session_queued_cb (RakiaSipSession *sipsession, RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - rakia_media_channel_change_call_state (self, priv->handle, - TP_CHANNEL_CALL_STATE_QUEUED, 0); -} - -static void -session_in_progress_cb (RakiaSipSession *sipsession, RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - rakia_media_channel_change_call_state (self, priv->handle, - TP_CHANNEL_CALL_STATE_IN_PROGRESS, 0); -} - -static void -session_established_cb (RakiaSipSession *sipsession, RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpIntSet *add = tp_intset_new_containing (priv->handle); - - tp_group_mixin_change_members ((GObject *) self, - "", - add, /* add */ - NULL, /* remove */ - NULL, - NULL, - priv->handle, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - tp_intset_destroy (add); -} - -static void -session_ended_cb (RakiaSipSession *sipsession, gboolean self_actor, - guint cause, gchar *message, RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpGroupMixin *mixin = TP_GROUP_MIXIN (self); - TpIntSet *remove; - TpHandle actor; - TpChannelGroupChangeReason reason; - - remove = tp_intset_new (); - tp_intset_add (remove, priv->handle); - tp_intset_add (remove, mixin->self_handle); - - if (self_actor) - actor = mixin->self_handle; - else - actor = priv->handle; - - if (message == NULL) - message = ""; - - switch (cause) - { - case 410: - case 604: - reason = TP_CHANNEL_GROUP_CHANGE_REASON_INVALID_CONTACT; - break; - case 486: - case 600: - reason = TP_CHANNEL_GROUP_CHANGE_REASON_BUSY; - break; - case 408: - reason = TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER; - break; - case 404: - case 480: - if (rakia_sip_session_get_state (priv->sipsession) <= - RAKIA_SIP_SESSION_STATE_INVITE_SENT) - reason = TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER; - else - reason = TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE; - break; - case 603: - /* No reason means roughly "rejected" */ - reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE; - break; - case 403: - case 401: - case 407: - reason = TP_CHANNEL_GROUP_CHANGE_REASON_PERMISSION_DENIED; - break; - default: - if (cause < 300) - reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE; - else - reason = TP_CHANNEL_GROUP_CHANGE_REASON_ERROR; - break; - } - - tp_group_mixin_change_members ((GObject *) self, message, - NULL, remove, NULL, NULL, actor, reason); - - tp_intset_destroy (remove); - -} - - -static void -rakia_media_channel_constructed (GObject *obj) -{ - RakiaMediaChannel *chan = RAKIA_MEDIA_CHANNEL (obj); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (chan); - TpBaseConnection *conn = (TpBaseConnection *)(priv->conn); - GObjectClass *parent_object_class = - G_OBJECT_CLASS (rakia_media_channel_parent_class); - TpDBusDaemon *bus; - TpHandleRepoIface *contact_repo; - TpIntSet *add; - - if (parent_object_class->constructed != NULL) - parent_object_class->constructed (obj); - - contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - - if (priv->handle != 0) - tp_handle_ref (contact_repo, priv->handle); - - /* register object on the bus */ - bus = tp_base_connection_get_dbus_daemon (conn); - - DEBUG("registering object to dbus path=%s", priv->object_path); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - /* initialize group mixin */ - tp_group_mixin_init (obj, - G_STRUCT_OFFSET (RakiaMediaChannel, group), - contact_repo, - conn->self_handle); - - /* automatically add initiator to channel, but also ref them again (because - * priv->initiator is the InitiatorHandle) */ - g_assert (priv->initiator != 0); - tp_handle_ref (contact_repo, priv->initiator); - - add = tp_intset_new_containing (priv->initiator); - tp_group_mixin_change_members (obj, "", add, NULL, NULL, NULL, 0, 0); - tp_intset_destroy (add); - - /* We start off with lots of flags, and then delete them as we work out what - * kind of channel we are, rather than trying to track what we need to - * add/remove over time. We should always have the right flags before we are - * advertised on the bus. */ - tp_group_mixin_change_flags (obj, - TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | - TP_CHANNEL_GROUP_FLAG_CAN_RESCIND | TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0); - - g_signal_connect_object (priv->sipsession, "ringing", - G_CALLBACK (session_ringing_cb), chan, 0); - g_signal_connect_object (priv->sipsession, "queued", - G_CALLBACK (session_queued_cb), chan, 0); - g_signal_connect_object (priv->sipsession, "in-progress", - G_CALLBACK (session_in_progress_cb), chan, 0); - g_signal_connect_object (priv->sipsession, "established", - G_CALLBACK (session_established_cb), chan, 0); - g_signal_connect_object (priv->sipsession, "ended", - G_CALLBACK (session_ended_cb), chan, 0); - g_signal_connect_object (priv->sipsession, - "state-changed", G_CALLBACK(priv_session_state_changed_cb), chan, 0); - - if (priv->initiator != conn->self_handle) - { - /* Incoming */ - priv->initial_audio = rakia_sip_session_has_media (priv->sipsession, - TP_MEDIA_STREAM_TYPE_AUDIO); - priv->initial_video = rakia_sip_session_has_media (priv->sipsession, - TP_MEDIA_STREAM_TYPE_VIDEO); - priv_create_session (chan, priv->initiator); - - g_assert (priv->session != NULL); - //rakia_sip_session_receive_invite (priv->sipsession); - } - else - { - priv_create_session (chan, priv->handle); - } - -} -static void -rakia_media_channel_class_init (RakiaMediaChannelClass *klass) -{ - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "ChannelType", "channel-type", NULL }, - { "Interfaces", "interfaces", NULL }, - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "TargetID", "target-id", NULL }, - { "InitiatorHandle", "initiator", NULL }, - { "InitiatorID", "initiator-id", NULL }, - { "Requested", "requested", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinPropImpl streamed_media_props[] = { - { "InitialAudio", "initial-audio", NULL }, - { "InitialVideo", "initial-video", NULL }, - { "ImmutableStreams", "immutable-streams", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinPropImpl dtmf_props[] = { - { "CurrentlySendingTones", "currently-sending-tones", NULL }, - { "InitialTones", "initial-tones", NULL }, - { "DeferredTones", "deferred-tones", NULL }, - { NULL } - }; - - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, - { TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - streamed_media_props, - }, - { TP_IFACE_CHANNEL_INTERFACE_DTMF, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - dtmf_props, - }, - { NULL } - }; - - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - DEBUG("enter"); - - g_type_class_add_private (klass, sizeof (RakiaMediaChannelPrivate)); - - object_class->constructed = rakia_media_channel_constructed; - object_class->dispose = rakia_media_channel_dispose; - object_class->finalize = rakia_media_channel_finalize; - - object_class->get_property = rakia_media_channel_get_property; - object_class->set_property = rakia_media_channel_set_property; - - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); - g_object_class_override_property (object_class, PROP_HANDLE, "handle"); - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - - param_spec = g_param_spec_object ("connection", "RakiaConnection object", - "SIP connection object that owns this SIP media channel object.", - RAKIA_TYPE_BASE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - param_spec = g_param_spec_string ("nat-traversal", "NAT traversal mechanism", - "A string representing the type of NAT traversal that should be " - "performed for streams on this channel.", - "none", - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, param_spec); - - param_spec = g_param_spec_object ("sip-session", "RakiaSipSession object", - "SIP session object that is used for this SIP media channel object.", - RAKIA_TYPE_SIP_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SIP_SESSION, param_spec); - - param_spec = g_param_spec_string ("stun-server", "STUN server", - "IP or address of STUN server.", NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVER, param_spec); - - param_spec = g_param_spec_uint ("stun-port", "STUN port", - "UDP port of STUN server.", 0, G_MAXUINT16, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_PORT, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Addition Channel.Interface.* interfaces", G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - - param_spec = g_param_spec_string ("target-id", "Target SIP URI", - "Currently empty, because this channel always has handle 0.", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - - param_spec = g_param_spec_uint ("initiator", "Channel initiator", - "The TpHandle representing the contact who created the channel.", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR, param_spec); - - param_spec = g_param_spec_string ("initiator-id", "Creator URI", - "The URI obtained by inspecting the initiator handle.", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_ID, param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - - param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", - "Whether the channel initially contained an audio stream", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, - param_spec); - - param_spec = g_param_spec_boolean ("initial-video", "InitialVideo", - "Whether the channel initially contained a video stream", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - param_spec = g_param_spec_boolean ("immutable-streams", "ImmutableStreams", - "Whether the set of streams on this channel are fixed once requested", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_IMMUTABLE_STREAMS, - param_spec); - - param_spec = g_param_spec_boolean ("currently-sending-tones", - "Currently sending tones", - "True if the channel is currently sending DTMF tones", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CURRENTLY_SENDING_TONES, - param_spec); - - param_spec = g_param_spec_string ("initial-tones", "Initial tones", - "The initial DTMF tones to send after audio stream(s) are established.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_TONES, - param_spec); - - param_spec = g_param_spec_string ("deferred-tones", "Deferred tones", - "The DTMF tones deferred waiting for user input.", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DEFERRED_TONES, - param_spec); - - - tp_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (RakiaMediaChannelClass, properties_class), - media_channel_property_signatures, NUM_TP_PROPS, NULL); - - klass->dbus_props_class.interfaces = - prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (RakiaMediaChannelClass, dbus_props_class)); - - tp_group_mixin_class_init (object_class, - G_STRUCT_OFFSET (RakiaMediaChannelClass, group_class), - _rakia_media_channel_add_member, - NULL); - tp_group_mixin_class_allow_self_removal (object_class); - tp_group_mixin_class_set_remove_with_reason_func(object_class, - rakia_media_channel_remove_with_reason); - tp_group_mixin_init_dbus_properties (object_class); - -} - -static void -rakia_media_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - RakiaMediaChannel *chan = RAKIA_MEDIA_CHANNEL (object); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (chan); - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); - - switch (property_id) { - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_HANDLE_TYPE: - g_value_set_uint (value, priv->handle? - TP_HANDLE_TYPE_CONTACT : TP_HANDLE_TYPE_NONE); - break; - case PROP_TARGET_ID: - if (priv->handle != 0) - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_value_set_string (value, tp_handle_inspect (repo, priv->handle)); - } - else - g_value_set_static_string (value, ""); - break; - case PROP_INITIATOR: - g_value_set_uint (value, priv->initiator); - break; - case PROP_INITIATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_value_set_string (value, tp_handle_inspect (repo, priv->initiator)); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, (priv->initiator == base_conn->self_handle)); - break; - case PROP_INTERFACES: - g_value_set_static_boxed (value, rakia_media_channel_interfaces); - break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - g_value_take_boxed (value, - tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialAudio", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialVideo", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "ImmutableStreams", - NULL)); - 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; - case PROP_IMMUTABLE_STREAMS: - g_value_set_boolean (value, priv->immutable_streams); - break; - case PROP_STUN_SERVER: - g_value_set_string (value, priv->stun_server); - break; - case PROP_STUN_PORT: - g_value_set_uint (value, priv->stun_port); - break; - case PROP_CURRENTLY_SENDING_TONES: - g_value_set_boolean (value, - priv->dtmf_player != NULL - && tp_dtmf_player_is_active (priv->dtmf_player)); - break; - case PROP_INITIAL_TONES: - if (priv->initial_tones == NULL) - g_value_set_static_string (value, ""); - else - g_value_set_string (value, priv->initial_tones); - break; - case PROP_DEFERRED_TONES: - if (priv->deferred_tones == NULL) - g_value_set_static_string (value, ""); - else - g_value_set_string (value, priv->deferred_tones); - break; - default: - /* Some properties live in the mixin */ - { - const gchar *param_name; - guint tp_property_id; - GValue *tp_property_value; - - param_name = g_param_spec_get_name (pspec); - if (G_LIKELY (tp_properties_mixin_has_property (object, param_name, - &tp_property_id))) - { - tp_property_value = - chan->properties.properties[tp_property_id].value; - - if (G_LIKELY (tp_property_value != NULL)) - { - g_value_copy (tp_property_value, value); - return; - } - } - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static gboolean -rakia_media_channel_set_tp_property (RakiaMediaChannel *chan, - const GValue *value, - GParamSpec *pspec) -{ - GObject *obj = (GObject *) chan; - const gchar *param_name = g_param_spec_get_name (pspec); - guint tp_property_id; - - if (G_LIKELY (tp_properties_mixin_has_property (obj, param_name, - &tp_property_id))) - { - tp_properties_mixin_change_value (obj, tp_property_id, - value, NULL); - tp_properties_mixin_change_flags (obj, tp_property_id, - TP_PROPERTY_FLAG_READ, 0, NULL); - return TRUE; - } - else - { - WARNING("Telepathy property '%s' is not defined for media channels", - param_name); - return FALSE; - } -} - -static void -rakia_media_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - RakiaMediaChannel *chan = RAKIA_MEDIA_CHANNEL (object); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (chan); - - switch (property_id) { - case PROP_HANDLE_TYPE: - case PROP_CHANNEL_TYPE: - /* this property is writable in the interface, but not actually - * meaningfully changable on this channel, so we do nothing */ - break; - case PROP_CONNECTION: - priv->conn = g_value_dup_object (value); - break; - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_HANDLE: - /* XXX: this property is defined as writable, - * but don't set it after construction, mmkay? */ - /* we don't ref it here because we don't necessarily have access to the - * contact repo yet - instead we ref it in constructed. */ - priv->handle = g_value_get_uint (value); - break; - case PROP_INITIATOR: - /* similarly we can't ref this yet */ - priv->initiator = g_value_get_uint (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; - case PROP_IMMUTABLE_STREAMS: - priv->immutable_streams = g_value_get_boolean (value); - break; - case PROP_STUN_SERVER: - priv->stun_server = g_value_dup_string (value); - /* Also expose as a legacy Telepathy property */ - rakia_media_channel_set_tp_property (chan, value, pspec); - break; - case PROP_STUN_PORT: - priv->stun_port = g_value_get_uint (value); - /* Also expose as a legacy Telepathy property */ - rakia_media_channel_set_tp_property (chan, value, pspec); - break; - case PROP_INITIAL_TONES: - priv->initial_tones = g_value_dup_string (value); - break; - case PROP_SIP_SESSION: - priv->sipsession = g_value_dup_object (value); - break; - default: - /* some properties live in the mixin */ - if (rakia_media_channel_set_tp_property (chan, value, pspec)) - return; - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -rakia_media_channel_dispose (GObject *object) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (object); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpHandleRepoIface *contact_handles; - - if (priv->dispose_has_run) - return; - - DEBUG("enter"); - - priv->dispose_has_run = TRUE; - - if (!priv->closed) - rakia_media_channel_close (self); - - if (priv->sipsession) - g_object_unref (priv->sipsession); - - if (priv->dtmf_player != NULL) - g_object_unref (priv->dtmf_player); - - contact_handles = tp_base_connection_get_handles ( - TP_BASE_CONNECTION (priv->conn), TP_HANDLE_TYPE_CONTACT); - - tp_handle_unref (contact_handles, priv->initiator); - priv->initiator = 0; - - g_object_unref (priv->conn); - - if (G_OBJECT_CLASS (rakia_media_channel_parent_class)->dispose) - G_OBJECT_CLASS (rakia_media_channel_parent_class)->dispose (object); - - DEBUG("exit"); -} - -static void -rakia_media_channel_finalize (GObject *object) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (object); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - g_hash_table_unref (priv->call_states); - - g_free (priv->initial_tones); - g_free (priv->deferred_tones); - - g_free (priv->stun_server); - - g_free (priv->object_path); - - tp_group_mixin_finalize (object); - - tp_properties_mixin_finalize (object); - - G_OBJECT_CLASS (rakia_media_channel_parent_class)->finalize (object); - - DEBUG("exit"); -} - -/*********************************************************************** - * Set: Channel interface implementation (same for 0.12/0.13) - ***********************************************************************/ - -/** - * rakia_media_channel_close_async - * - * Implements DBus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -rakia_media_channel_dbus_close (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - - rakia_media_channel_close (self); - tp_svc_channel_return_from_close (context); -} - -void -rakia_media_channel_close (RakiaMediaChannel *obj) -{ - RakiaMediaChannelPrivate *priv; - - DEBUG("enter"); - - g_assert (RAKIA_IS_MEDIA_CHANNEL (obj)); - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (obj); - - if (priv->closed) - return; - - priv->closed = TRUE; - - if (priv->sipsession) { - rakia_sip_session_terminate (priv->sipsession); - } - - tp_svc_channel_emit_closed ((TpSvcChannel *)obj); - - return; -} - -/** - * rakia_media_channel_get_channel_type - * - * Implements DBus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -rakia_media_channel_get_channel_type (TpSvcChannel *obj, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); -} - - -/** - * rakia_media_channel_get_handle - * - * Implements DBus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -rakia_media_channel_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->handle != 0) - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, - priv->handle); - else - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); -} - -/** - * rakia_media_channel_get_interfaces - * - * Implements DBus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -rakia_media_channel_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_interfaces (context, - rakia_media_channel_interfaces); -} - -/*********************************************************************** - * Set: Channel.Interface.MediaSignalling Telepathy-0.13 interface - ***********************************************************************/ - -/** - * rakia_media_channel_get_session_handlers - * - * Implements DBus method GetSessionHandlers - * on interface org.freedesktop.Telepathy.Channel.Interface.MediaSignalling - * - * @error: Used to return a pointer to a GError detailing any error - * that occured, DBus will throw the error only if this - * function returns false. - * - * Returns: TRUE if successful, FALSE if an error was thrown. - */ -static void -rakia_media_channel_get_session_handlers (TpSvcChannelInterfaceMediaSignalling *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - GPtrArray *ret; - GValue handler = { 0 }; - - DEBUG("enter"); - - g_assert (RAKIA_IS_MEDIA_CHANNEL (self)); - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - ret = g_ptr_array_new (); - - if (priv->session) - { - GType handler_type; - gchar *path; - - g_object_get (priv->session, - "object-path", &path, - NULL); - - handler_type = dbus_g_type_get_struct ("GValueArray", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_STRING, - G_TYPE_INVALID); - - g_value_init (&handler, handler_type); - g_value_take_boxed (&handler, - dbus_g_type_specialized_construct (handler_type)); - - dbus_g_type_struct_set (&handler, - 0, path, - 1, "rtp", - G_MAXUINT); - - g_free (path); - - g_ptr_array_add (ret, g_value_get_boxed (&handler)); - } - - tp_svc_channel_interface_media_signalling_return_from_get_session_handlers ( - context, ret); - - if (G_IS_VALUE(&handler)) - g_value_unset (&handler); - - g_ptr_array_unref (ret); -} - - -/*********************************************************************** - * Set: Channel.Type.StreamedMedia Telepathy-0.13 interface - ***********************************************************************/ - -/** - * rakia_media_channel_list_streams - * - * Implements D-Bus method ListStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -rakia_media_channel_list_streams (TpSvcChannelTypeStreamedMedia *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - GPtrArray *ret = NULL; - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - ret = g_ptr_array_new (); - - if (priv->session != NULL) - rakia_media_session_list_streams (priv->session, ret); - - tp_svc_channel_type_streamed_media_return_from_list_streams (context, ret); - - g_boxed_free (TP_ARRAY_TYPE_MEDIA_STREAM_INFO_LIST, ret); -} - -/** - * rakia_media_channel_remove_streams - * - * Implements D-Bus method RemoveStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -rakia_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, - const GArray *streams, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - GError *error = NULL; - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->immutable_streams) - { - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, - "Cannot remove streams from the existing channel"); - } - else if (priv->session != NULL) - { - rakia_media_session_remove_streams(priv->session, - streams, - &error); - } - else - { - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "No session is available"); - } - - if (error != NULL) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - tp_svc_channel_type_streamed_media_return_from_remove_streams (context); -} - -/** - * rakia_media_channel_request_stream_direction - * - * Implements D-Bus method RequestStreamDirection - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -rakia_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *iface, - guint stream_id, - guint stream_direction, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - GError *error = NULL; - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->immutable_streams) - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Cannot change directions on an immutable channel" }; - dbus_g_method_return_error (context, &e); - return; - } - - if (priv->session != NULL) - { - rakia_media_session_request_stream_direction (priv->session, - stream_id, - stream_direction, - &error); - } - else - { - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "The media session is not available"); - } - - if (error == NULL) - { - tp_svc_channel_type_streamed_media_return_from_request_stream_direction (context); - } - else - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - - -/** - * rakia_media_channel_request_streams - * - * Implements D-Bus method RequestStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -rakia_media_channel_request_streams (TpSvcChannelTypeStreamedMedia *iface, - guint contact_handle, - const GArray *types, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - GError *error = NULL; - GPtrArray *ret = NULL; - RakiaMediaChannelPrivate *priv; - TpHandleRepoIface *contact_repo; - - DEBUG("enter"); - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->immutable_streams) - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Cannot add streams to the immutable channel" }; - dbus_g_method_return_error (context, &e); - return; - } - - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *)(priv->conn), TP_HANDLE_TYPE_CONTACT); - - if (!tp_handle_is_valid (contact_repo, contact_handle, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - ret = g_ptr_array_sized_new (types->len); - - if (rakia_media_session_request_streams (priv->session, types, ret, &error)) - { - g_assert (types->len == ret->len); - tp_svc_channel_type_streamed_media_return_from_request_streams (context, - ret); - } - else - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } - - g_boxed_free (TP_ARRAY_TYPE_MEDIA_STREAM_INFO_LIST, ret); - - DEBUG ("exit"); -} - -/*********************************************************************** - * Set: sip-media-channel API towards sip-connection - ***********************************************************************/ - -void -rakia_media_channel_create_initial_streams (RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - g_assert (priv->initiator != priv->handle); - - /* RequestChannel(None, 0) => channel is anonymous: - * caller uses RequestStreams to set the peer and start the call. */ - if (priv->handle == 0) - return; - - g_assert (priv->session != NULL); - - if (priv->initial_audio) - rakia_media_session_add_stream (priv->session, - TP_MEDIA_STREAM_TYPE_AUDIO, - TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TRUE); - - if (priv->initial_video) - rakia_media_session_add_stream (priv->session, - TP_MEDIA_STREAM_TYPE_VIDEO, - TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TRUE); -} - - - -guint -rakia_media_channel_change_call_state (RakiaMediaChannel *self, - TpHandle peer, - guint flags_add, - guint flags_remove) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - gpointer key = GUINT_TO_POINTER (peer); - guint old_state; - guint new_state; - - /* XXX: check if the peer is a member? */ - - old_state = GPOINTER_TO_UINT (g_hash_table_lookup (priv->call_states, key)); - new_state = (old_state | flags_add) & ~flags_remove; - - if (new_state != old_state) - { - DEBUG ("setting call state %u for peer %u", new_state, peer); - if (new_state == 0) - g_hash_table_remove (priv->call_states, key); - else - g_hash_table_replace (priv->call_states, key, - GUINT_TO_POINTER (new_state)); - - tp_svc_channel_interface_call_state_emit_call_state_changed (self, - peer, - new_state); - } - - return new_state; -} - - - - -static void priv_session_state_changed_cb (RakiaSipSession *session, - guint old_state, - guint state, - RakiaMediaChannel *channel) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (channel); - TpGroupMixin *mixin = TP_GROUP_MIXIN (channel); - TpHandle self_handle; - TpHandle peer; - TpIntSet *set = NULL; - - DEBUG("enter"); - - self_handle = mixin->self_handle; - peer = rakia_media_session_get_peer (priv->session); - - switch (state) - { - case RAKIA_SIP_SESSION_STATE_INVITE_SENT: - g_assert (priv->initiator == self_handle); - - /* add the peer to remote pending */ - set = tp_intset_new_containing (peer); - tp_group_mixin_change_members ((GObject *)channel, - "", - NULL, /* add */ - NULL, /* remove */ - NULL, /* local pending */ - set, /* remote pending */ - self_handle, /* actor */ - TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - - /* update flags: no more adding */ - tp_group_mixin_change_flags ((GObject *)channel, 0, - TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - break; - - case RAKIA_SIP_SESSION_STATE_INVITE_RECEIVED: - /* add ourself to local pending */ - set = tp_intset_new_containing (self_handle); - tp_group_mixin_change_members ((GObject *) channel, "", - NULL, /* add */ - NULL, /* remove */ - set, /* local pending */ - NULL, /* remote pending */ - priv->initiator, /* actor */ - TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - - /* No adding more members to the incoming call. Therefore also not - * possible to add anyone to remote-pending, so rescinding would make - * utterly no sense. We also disallow removing the remote peer if - * we are not the initiator, so disallow that too. - * Removing yourself to end the call is not represented by group flags. - */ - tp_group_mixin_change_flags ((GObject *) channel, 0, - TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_REMOVE | - TP_CHANNEL_GROUP_FLAG_CAN_RESCIND); - - break; - - case RAKIA_SIP_SESSION_STATE_ACTIVE: - if (priv->initiator == self_handle) - { - if (!tp_handle_set_is_member (mixin->remote_pending, peer)) - break; /* no-op */ - - /* the peer has promoted itself to members */ - set = tp_intset_new_containing (peer); - tp_group_mixin_change_members ((GObject *)channel, "", - set, /* add */ - NULL, /* remove */ - NULL, - NULL, - peer, 0); - } - else - { - if (!tp_handle_set_is_member (mixin->local_pending, self_handle)) - break; /* no-op */ - - /* promote ourselves to members */ - set = tp_intset_new_containing (self_handle); - tp_group_mixin_change_members ((GObject *)channel, "", - set, /* add */ - NULL, /* remove */ - NULL, - NULL, - self_handle, 0); - } - - /* update flags: deny adding and rescinding. Removing the remote peer is - * still allowed. - * Removing yourself to end the call is not represented by group flags. - */ - tp_group_mixin_change_flags ((GObject *)channel, 0, - TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND); - - break; - - case RAKIA_SIP_SESSION_STATE_ENDED: - set = tp_intset_new (); - - /* remove us and the peer from the member list */ - tp_intset_add (set, self_handle); - tp_intset_add (set, peer); - tp_group_mixin_change_members ((GObject *)channel, "", - NULL, /* add */ - set, /* remove */ - NULL, - NULL, - 0, 0); - - /* Close the channel; destroy the session first to avoid - * the rakia_media_session_terminate() path in this case */ - priv_destroy_session (channel); - rakia_media_channel_close (channel); - break; - } - - if (set != NULL) - tp_intset_destroy (set); -} - -/** - * priv_create_session: - * - * Creates a RakiaMediaSession object for given peer. - **/ -static void -priv_create_session (RakiaMediaChannel *channel, - TpHandle peer) -{ - RakiaMediaChannelPrivate *priv; - RakiaMediaSession *session; - TpBaseConnection *conn; - TpHandleRepoIface *contact_repo; - gchar *object_path; - gchar *local_ip_address = NULL; - - DEBUG("enter"); - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (channel); - conn = (TpBaseConnection *)(priv->conn); - contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - - g_assert (priv->session == NULL); - - object_path = g_strdup_printf ("%s/MediaSession%u", priv->object_path, peer); - - DEBUG("allocating session, peer=%u", peer); - - /* The channel manages references to the peer handle for the session */ - tp_handle_ref (contact_repo, peer); - - g_object_get (priv->conn, - "local-ip-address", &local_ip_address, - NULL); - - session = g_object_new (RAKIA_TYPE_MEDIA_SESSION, - "dbus-daemon", - tp_base_connection_get_dbus_daemon (conn), - "media-channel", channel, - "object-path", object_path, - "sip-session", priv->sipsession, - "peer", peer, - "local-ip-address", local_ip_address, - NULL); - - g_free (local_ip_address); - - g_signal_connect_object (session, - "dtmf-ready", - G_CALLBACK (priv_session_dtmf_ready_cb), - channel, - 0); - - priv->session = session; - - tp_svc_channel_interface_media_signalling_emit_new_session_handler ( - (TpSvcChannelInterfaceMediaSignalling *)channel, object_path, "rtp"); - - g_free (object_path); - - DEBUG ("exit"); -} - -static void -priv_destroy_session(RakiaMediaChannel *channel) -{ - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (channel); - RakiaMediaSession *session; - TpBaseConnection *conn; - TpHandleRepoIface *contact_repo; - - session = priv->session; - if (session == NULL) - return; - - DEBUG("enter"); - - /* Release the peer handle */ - conn = (TpBaseConnection *)(priv->conn); - contact_repo = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - tp_handle_unref (contact_repo, rakia_media_session_get_peer (session)); - - priv->session = NULL; - g_object_unref (session); - - DEBUG("exit"); -} - -gboolean -_rakia_media_channel_add_member (GObject *iface, - TpHandle handle, - const gchar *message, - GError **error) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpGroupMixin *mixin = TP_GROUP_MIXIN (iface); - - DEBUG("mixin->self_handle=%d, handle=%d", mixin->self_handle, handle); - - if (priv->initiator == mixin->self_handle) - { - TpIntSet *remote_pending; - - /* Backwards compatible behavior: - * add the peer to remote pending without waiting for the actual request - * to be sent */ - remote_pending = tp_intset_new_containing (handle); - tp_group_mixin_change_members (iface, - "", - NULL, /* add */ - NULL, /* remove */ - NULL, /* local pending */ - remote_pending, /* remote pending */ - mixin->self_handle, /* actor */ - TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - tp_intset_destroy (remote_pending); - - /* update flags: no more adding. - * Removal and rescinding are still allowed. */ - tp_group_mixin_change_flags (iface, 0, - TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - return TRUE; - } - - if (priv->session && - handle == mixin->self_handle && - tp_handle_set_is_member (mixin->local_pending, handle)) - { - /* case b: an incoming invite */ - DEBUG("accepting an incoming invite"); - g_return_val_if_fail (priv->session != NULL, FALSE); - - rakia_media_session_accept (priv->session); - - return TRUE; - } - - MESSAGE ("unsupported member change requested for a media channel"); - - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "handle %u cannot be added in the current state", handle); - return FALSE; -} - -static gint -rakia_status_from_tp_reason (TpChannelGroupChangeReason reason) -{ - switch (reason) - { - case TP_CHANNEL_GROUP_CHANGE_REASON_NONE: - return 603; /* Decline */ - case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: - case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: - return 480; /* Temporarily Unavailable */ - case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: - return 486; /* Busy Here */ - case TP_CHANNEL_GROUP_CHANGE_REASON_PERMISSION_DENIED: - case TP_CHANNEL_GROUP_CHANGE_REASON_BANNED: - return 403; /* Forbidden */ - case TP_CHANNEL_GROUP_CHANGE_REASON_INVALID_CONTACT: - return 404; /* Not Found */ - default: - return 500; /* Server Internal Error */ - } -} - -static gboolean -rakia_media_channel_remove_with_reason (GObject *obj, - TpHandle handle, - const gchar *message, - guint reason, - GError **error) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (obj); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - TpIntSet *set = NULL; - TpHandle self_handle; - gboolean rejected; - - self_handle = mixin->self_handle; - - if (priv->initiator != self_handle && handle != self_handle) - { - g_set_error (error, TP_ERRORS, TP_ERROR_PERMISSION_DENIED, - "handle %u cannot be removed because you are not the initiator of the" - " channel", handle); - - return FALSE; - } - - if (priv->session == NULL) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "handle %u cannot be removed in the current state", handle); - - return FALSE; - } - - rejected = (handle == self_handle - && tp_handle_set_is_member (mixin->local_pending, handle)); - - /* We have excluded all the problem cases. - * Now we always want to remove both members on behalf of the local user */ - set = tp_intset_new (); - tp_intset_add (set, self_handle); - tp_intset_add (set, rakia_media_session_get_peer (priv->session)); - tp_group_mixin_change_members (obj, "", - NULL, /* add */ - set, /* remove */ - NULL, - NULL, - self_handle, 0); - tp_intset_destroy (set); - - if (rejected) - { - /* The user has rejected the call */ - - gint status; - - status = rakia_status_from_tp_reason (reason); - - /* XXX: raise NotAvailable if it's the wrong state? */ - rakia_sip_session_respond (priv->sipsession, status, message); - - /* This session is effectively ended, prevent the nua_i_state handler - * from useless work */ - rakia_sip_session_change_state (priv->sipsession, - RAKIA_SIP_SESSION_STATE_ENDED); - } - else - { - /* Want to terminate the call in whatever other situation; - * rescinding is handled by sending CANCEL */ - rakia_sip_session_terminate (priv->sipsession); - } - - return TRUE; -} - -static void -rakia_media_channel_get_call_states (TpSvcChannelInterfaceCallState *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - tp_svc_channel_interface_call_state_return_from_get_call_states ( - context, - priv->call_states); -} - -static void -rakia_media_channel_get_hold_state (TpSvcChannelInterfaceHold *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - TpLocalHoldState hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - TpLocalHoldStateReason hold_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - - if (priv->session == NULL) - { - GError e = {TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "The media session is not available"}; - dbus_g_method_return_error (context, &e); - } - - g_object_get (priv->session, - "hold-state", &hold_state, - "hold-state-reason", &hold_reason, - NULL); - - tp_svc_channel_interface_hold_return_from_get_hold_state (context, - hold_state, - hold_reason); -} - -static void -rakia_media_channel_request_hold (TpSvcChannelInterfaceHold *iface, - gboolean hold, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->immutable_streams) - { - GError e = {TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Session modification disabled"}; - dbus_g_method_return_error (context, &e); - return; - } - else if (priv->session != NULL) - { - rakia_media_session_request_hold (priv->session, hold); - } - else - { - GError e = {TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "The media session is not available"}; - dbus_g_method_return_error (context, &e); - return; - } - - tp_svc_channel_interface_hold_return_from_request_hold (context); -} - -static void -dtmf_player_started_tone_cb (TpDTMFPlayer *dtmf_player, - guint event, - gpointer user_data) -{ - RakiaMediaChannel *self = user_data; - RakiaMediaChannelPrivate *priv = self->priv; - - if (priv->session != NULL) - rakia_media_session_start_telephony_event (priv->session, event); -} - -static void -dtmf_player_stopped_tone_cb (TpDTMFPlayer *dtmf_player, - gpointer user_data) -{ - RakiaMediaChannel *self = user_data; - RakiaMediaChannelPrivate *priv = self->priv; - - if (priv->session != NULL) - rakia_media_session_stop_telephony_event (priv->session); -} - -static void -dtmf_player_finished_cb (TpDTMFPlayer *dtmf_player, - gboolean cancelled, - gpointer user_data) -{ - RakiaMediaChannel *self = user_data; - - tp_svc_channel_interface_dtmf_emit_stopped_tones (self, cancelled); -} - -static void -dtmf_player_tones_deferred_cb (TpDTMFPlayer *dtmf_player, - gchar *tones, - gpointer user_data) -{ - RakiaMediaChannel *self = user_data; - RakiaMediaChannelPrivate *priv = self->priv; - - g_free (priv->deferred_tones); - priv->deferred_tones = g_strdup (tones); - - tp_svc_channel_interface_dtmf_emit_tones_deferred (self, tones); -} - -static void -priv_ensure_dtmf_player (RakiaMediaChannel *self) -{ - RakiaMediaChannelPrivate *priv = self->priv; - if (priv->dtmf_player != NULL) - return; - - priv->dtmf_player = tp_dtmf_player_new (); - - g_signal_connect (priv->dtmf_player, "started-tone", - G_CALLBACK (dtmf_player_started_tone_cb), self); - g_signal_connect (priv->dtmf_player, "stopped-tone", - G_CALLBACK (dtmf_player_stopped_tone_cb), self); - g_signal_connect (priv->dtmf_player, "finished", - G_CALLBACK (dtmf_player_finished_cb), self); - g_signal_connect (priv->dtmf_player, "tones-deferred", - G_CALLBACK (dtmf_player_tones_deferred_cb), self); -} - -static gboolean -rakia_media_channel_send_dtmf_tones (RakiaMediaChannel *self, - const gchar *tones, - guint tone_duration, - GError **error) -{ - RakiaMediaChannelPrivate *priv = self->priv; - - /* Perform sanity checks on the session */ - if (priv->session == NULL) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "the media session is not available, has the channel been closed?"); - return FALSE; - } - if (!rakia_media_session_has_media (priv->session, - TP_MEDIA_STREAM_TYPE_AUDIO)) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "no audio streams are available"); - return FALSE; - } - - priv_ensure_dtmf_player (self); - - if (!tp_dtmf_player_play (priv->dtmf_player, tones, tone_duration, - RAKIA_DTMF_GAP_DURATION, RAKIA_DTMF_PAUSE_DURATION, error)) - return FALSE; - - g_free (priv->deferred_tones); - priv->deferred_tones = NULL; - - tp_svc_channel_interface_dtmf_emit_sending_tones (self, tones); - - return TRUE; -} - -static void -rakia_media_channel_start_tone (TpSvcChannelInterfaceDTMF *iface, - guint stream_id, - guchar event, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - GError *error = NULL; - gchar tone[2]; - - DEBUG("enter"); - - if (event >= NUM_TP_DTMF_EVENTS) - { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "event %u is not a known DTMF event", event); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - tone[0] = tp_dtmf_event_to_char (event); - tone[1] = '\0'; - - if (!rakia_media_channel_send_dtmf_tones (self, tone, G_MAXUINT, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - tp_svc_channel_interface_dtmf_return_from_start_tone (context); -} - -static void -rakia_media_channel_stop_tone (TpSvcChannelInterfaceDTMF *iface, - guint stream_id, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = RAKIA_MEDIA_CHANNEL (iface); - RakiaMediaChannelPrivate *priv; - - DEBUG("enter"); - - priv = RAKIA_MEDIA_CHANNEL_GET_PRIVATE (self); - - if (priv->dtmf_player != NULL) - tp_dtmf_player_cancel (priv->dtmf_player); - - tp_svc_channel_interface_dtmf_return_from_stop_tone (context); -} - -static void -rakia_media_channel_multiple_tones (TpSvcChannelInterfaceDTMF *iface, - const gchar *tones, - DBusGMethodInvocation *context) -{ - RakiaMediaChannel *self = (RakiaMediaChannel *) iface; - GError *error = NULL; - - if (!rakia_media_channel_send_dtmf_tones (self, tones, - RAKIA_DTMF_TONE_DURATION, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - tp_svc_channel_interface_dtmf_return_from_multiple_tones (context); -} - -static void -priv_session_dtmf_ready_cb (RakiaMediaSession *session, - RakiaMediaChannel *channel) -{ - RakiaMediaChannelPrivate *priv = channel->priv; - if (!tp_str_empty (priv->initial_tones)) - rakia_media_channel_send_dtmf_tones (channel, priv->initial_tones, - RAKIA_DTMF_TONE_DURATION, NULL); -} - -static void -event_target_init(gpointer g_iface, gpointer iface_data) -{ -} - -static void -channel_iface_init(gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *)g_iface; - - tp_svc_channel_implement_close ( - klass, rakia_media_channel_dbus_close); -#define IMPLEMENT(x) tp_svc_channel_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT(get_channel_type); - IMPLEMENT(get_handle); - IMPLEMENT(get_interfaces); -#undef IMPLEMENT -} - -static void -streamed_media_iface_init(gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelTypeStreamedMediaClass *klass = (TpSvcChannelTypeStreamedMediaClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_streamed_media_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT(list_streams); - IMPLEMENT(remove_streams); - IMPLEMENT(request_stream_direction); - IMPLEMENT(request_streams); -#undef IMPLEMENT -} - -static void -media_signalling_iface_init(gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceMediaSignallingClass *klass = (TpSvcChannelInterfaceMediaSignallingClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_media_signalling_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT(get_session_handlers); -#undef IMPLEMENT -} - -static void -dtmf_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceDTMFClass *klass = (TpSvcChannelInterfaceDTMFClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_dtmf_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT(start_tone); - IMPLEMENT(stop_tone); - IMPLEMENT(multiple_tones); -#undef IMPLEMENT -} - -static void -call_state_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelInterfaceCallStateClass *klass = g_iface; -#define IMPLEMENT(x) tp_svc_channel_interface_call_state_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT (get_call_states); -#undef IMPLEMENT -} - -static void -hold_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelInterfaceHoldClass *klass = g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_hold_implement_##x (\ - klass, rakia_media_channel_##x) - IMPLEMENT (get_hold_state); - IMPLEMENT (request_hold); -#undef IMPLEMENT -} diff --git a/rakia/media-channel.h b/rakia/media-channel.h deleted file mode 100644 index cbd42ec..0000000 --- a/rakia/media-channel.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * sip-media-channel.h - Header for RakiaMediaChannel - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005-2009 Nokia Corporation - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __RAKIA_MEDIA_CHANNEL_H__ -#define __RAKIA_MEDIA_CHANNEL_H__ - -#include <glib-object.h> -#include <sofia-sip/sdp.h> -#include <telepathy-glib/dbus-properties-mixin.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/handle.h> -#include <telepathy-glib/properties-mixin.h> - -#include <rakia/sofia-decls.h> - - -G_BEGIN_DECLS - -typedef struct _RakiaMediaChannel RakiaMediaChannel; -typedef struct _RakiaMediaChannelClass RakiaMediaChannelClass; -typedef struct _RakiaMediaChannelPrivate RakiaMediaChannelPrivate; - -struct _RakiaMediaChannelClass { - GObjectClass parent_class; - TpGroupMixinClass group_class; - TpPropertiesMixinClass properties_class; - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _RakiaMediaChannel { - GObject parent; - TpGroupMixin group; - TpPropertiesMixin properties; - RakiaMediaChannelPrivate *priv; -}; - -GType rakia_media_channel_get_type(void); - -/* TYPE MACROS */ -#define RAKIA_TYPE_MEDIA_CHANNEL \ - (rakia_media_channel_get_type()) -#define RAKIA_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), RAKIA_TYPE_MEDIA_CHANNEL, RakiaMediaChannel)) -#define RAKIA_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), RAKIA_TYPE_MEDIA_CHANNEL, RakiaMediaChannelClass)) -#define RAKIA_IS_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), RAKIA_TYPE_MEDIA_CHANNEL)) -#define RAKIA_IS_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), RAKIA_TYPE_MEDIA_CHANNEL)) -#define RAKIA_MEDIA_CHANNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), RAKIA_TYPE_MEDIA_CHANNEL, RakiaMediaChannelClass)) - -/*********************************************************************** - * Additional declarations (not based on generated templates) - ***********************************************************************/ - -void rakia_media_channel_close (RakiaMediaChannel *self); - -gboolean _rakia_media_channel_add_member (GObject *iface, - TpHandle handle, - const gchar *message, - GError **error); - -void rakia_media_channel_create_initial_streams (RakiaMediaChannel *self); - -void rakia_media_channel_attach_to_nua_handle (RakiaMediaChannel *self, - nua_handle_t *nh); - -guint -rakia_media_channel_change_call_state (RakiaMediaChannel *self, - TpHandle peer, - guint flags_add, - guint flags_remove); - -G_END_DECLS - -#endif /* #ifndef __RAKIA_MEDIA_CHANNEL_H__*/ diff --git a/rakia/media-session.c b/rakia/media-session.c deleted file mode 100644 index 445dd15..0000000 --- a/rakia/media-session.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* - * sip-media-session.c - Source for RakiaMediaSession - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005-2010 Nokia Corporation - * @author Kai Vehmanen <first.surname@nokia.com> - * @author Mikhail Zabaluev <mikhail.zabaluev@nokia.com> - * - * Based on telepathy-gabble implementation (gabble-media-session). - * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk> - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include "rakia/media-session.h" - -#include <dbus/dbus-glib.h> -#include <stdlib.h> -#include <time.h> -#include <string.h> - -#include <sofia-sip/sip_status.h> - -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-media-interfaces.h> - -#include "config.h" - -#include <rakia/base-connection.h> - -#include "rakia/media-channel.h" -#include "rakia/media-stream.h" -#include "rakia/sip-session.h" - -#include "signals-marshal.h" - -#define DEBUG_FLAG RAKIA_DEBUG_MEDIA -#include "rakia/debug.h" - -/* The timeout for outstanding re-INVITE transactions in seconds. - * Chosen to match the allowed cancellation timeout for proxies - * described in RFC 3261 Section 13.3.1.1 */ -#define RAKIA_REINVITE_TIMEOUT 180 - -static void session_handler_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE(RakiaMediaSession, - rakia_media_session, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_SESSION_HANDLER, - session_handler_iface_init) - ) - -/* signal enum */ -enum -{ - SIG_DTMF_READY, - SIG_LAST_SIGNAL -}; - -/* properties */ -enum -{ - PROP_MEDIA_CHANNEL = 1, - PROP_DBUS_DAEMON, - PROP_OBJECT_PATH, - PROP_SIP_SESSION, - PROP_PEER, - PROP_HOLD_STATE, - PROP_HOLD_STATE_REASON, - PROP_LOCAL_IP_ADDRESS, - PROP_STUN_SERVERS, - LAST_PROPERTY -}; - -static guint signals[SIG_LAST_SIGNAL] = {0}; - -#ifdef ENABLE_DEBUG - -#define SESSION_DEBUG(session, format, ...) \ - rakia_log (DEBUG_FLAG, G_LOG_LEVEL_DEBUG, "session: " format, \ - ##__VA_ARGS__) - -#define SESSION_MESSAGE(session, format, ...) \ - rakia_log (DEBUG_FLAG, G_LOG_LEVEL_MESSAGE, "session: " format, \ - ##__VA_ARGS__) - -#else /* !ENABLE_DEBUG */ - -#define SESSION_DEBUG(session, format, ...) G_STMT_START { } G_STMT_END -#define SESSION_MESSAGE(session, format, ...) G_STMT_START { } G_STMT_END - -#endif /* ENABLE_DEBUG */ - -/* private structure */ -struct _RakiaMediaSessionPrivate -{ - TpDBusDaemon *dbus_daemon; - RakiaMediaChannel *channel; /* see gobj. prop. 'media-channel' */ - gchar *object_path; /* see gobj. prop. 'object-path' */ - RakiaSipSession *sipsession; - TpHandle peer; /* see gobj. prop. 'peer' */ - gchar *local_ip_address; /* see gobj. prop. 'local-ip-address' */ - TpLocalHoldState hold_state; /* local hold state aggregated from stream directions */ - TpLocalHoldStateReason hold_reason; /* last used hold state change reason */ - - gint local_non_ready; /* number of streams with local information update pending */ - guint remote_stream_count; /* number of streams last seen in a remote offer */ - GPtrArray *streams; - gboolean remote_initiated; /*< session is remotely intiated */ - - gboolean se_ready; /*< connection established with stream-engine */ - gboolean audio_connected; /*< an audio stream has reached connected state */ - gboolean dispose_has_run; -}; - -#define RAKIA_MEDIA_SESSION_GET_PRIVATE(session) ((session)->priv) - -static void rakia_media_session_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); -static void rakia_media_session_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); - -static RakiaMediaStream * -rakia_media_session_get_stream (RakiaMediaSession *self, - guint stream_id, - GError **error); - -static void rakia_media_session_init (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - RAKIA_TYPE_MEDIA_SESSION, RakiaMediaSessionPrivate); - - self->priv = priv; - - priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - priv->hold_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - - /* allocate any data required by the object here */ - priv->streams = g_ptr_array_new (); -} - -static GObject * -rakia_media_session_constructor (GType type, guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - RakiaMediaSessionPrivate *priv; - - obj = G_OBJECT_CLASS (rakia_media_session_parent_class)-> - constructor (type, n_props, props); - priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (RAKIA_MEDIA_SESSION (obj)); - - g_assert (TP_IS_DBUS_DAEMON (priv->dbus_daemon)); - tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); - - return obj; -} - -static void rakia_media_session_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - RakiaMediaSession *session = RAKIA_MEDIA_SESSION (object); - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - - switch (property_id) - { - case PROP_DBUS_DAEMON: - g_value_set_object (value, priv->dbus_daemon); - break; - case PROP_MEDIA_CHANNEL: - g_value_set_object (value, priv->channel); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_SIP_SESSION: - g_value_set_object (value, priv->sipsession); - break; - case PROP_PEER: - g_value_set_uint (value, priv->peer); - break; - case PROP_HOLD_STATE: - g_value_set_uint (value, priv->hold_state); - break; - case PROP_HOLD_STATE_REASON: - g_value_set_uint (value, priv->hold_reason); - break; - case PROP_LOCAL_IP_ADDRESS: - g_value_set_string (value, priv->local_ip_address); - break; - - case PROP_STUN_SERVERS: - { - /* TODO: should be able to get all entries from the DNS lookup(s). - * At the moment, rawudp ignores all servers except the first one. */ - GPtrArray *servers; - gchar *stun_server = NULL; - guint stun_port = RAKIA_DEFAULT_STUN_PORT; - - g_return_if_fail (priv->channel != NULL); - - g_object_get (priv->channel, - "stun-server", &stun_server, - "stun-port", &stun_port, - NULL); - - servers = g_ptr_array_new (); - - if (stun_server != NULL) - { - GValue addr = { 0 }; - const GType addr_type = TP_STRUCT_TYPE_SOCKET_ADDRESS_IP; - - g_value_init (&addr, addr_type); - g_value_take_boxed (&addr, - dbus_g_type_specialized_construct (addr_type)); - - dbus_g_type_struct_set (&addr, - 0, stun_server, - 1, (guint16) stun_port, - G_MAXUINT); - - g_ptr_array_add (servers, g_value_get_boxed (&addr)); - - g_free (stun_server); - } - - g_value_take_boxed (value, servers); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void rakia_media_session_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - RakiaMediaSession *session = RAKIA_MEDIA_SESSION (object); - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - - switch (property_id) - { - case PROP_DBUS_DAEMON: - g_assert (priv->dbus_daemon == NULL); /* construct-only */ - priv->dbus_daemon = g_value_dup_object (value); - break; - case PROP_MEDIA_CHANNEL: - priv->channel = RAKIA_MEDIA_CHANNEL (g_value_get_object (value)); - break; - case PROP_OBJECT_PATH: - g_assert (priv->object_path == NULL); - priv->object_path = g_value_dup_string (value); - break; - case PROP_SIP_SESSION: - priv->sipsession = g_value_dup_object (value); - break; - case PROP_PEER: - priv->peer = g_value_get_uint (value); - break; - case PROP_LOCAL_IP_ADDRESS: - g_assert (priv->local_ip_address == NULL); - priv->local_ip_address = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void rakia_media_session_dispose (GObject *object); -static void rakia_media_session_finalize (GObject *object); - -static void -rakia_media_session_class_init (RakiaMediaSessionClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - g_type_class_add_private (klass, sizeof (RakiaMediaSessionPrivate)); - - object_class->constructor = rakia_media_session_constructor; - - object_class->get_property = rakia_media_session_get_property; - object_class->set_property = rakia_media_session_set_property; - - object_class->dispose = rakia_media_session_dispose; - object_class->finalize = rakia_media_session_finalize; - - param_spec = g_param_spec_object ("dbus-daemon", "TpDBusDaemon", - "Connection to D-Bus.", TP_TYPE_DBUS_DAEMON, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DBUS_DAEMON, param_spec); - - param_spec = g_param_spec_object ("media-channel", "RakiaMediaChannel object", - "SIP media channel object that owns this media session object" - " (not reference counted).", - RAKIA_TYPE_MEDIA_CHANNEL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_CHANNEL, param_spec); - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_object ("sip-session", "RakiaSipSession object", - "SIP session object that is used for this SIP media channel object.", - RAKIA_TYPE_SIP_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SIP_SESSION, param_spec); - - param_spec = g_param_spec_uint ("peer", "Session peer", - "The TpHandle representing the contact with whom this session communicates.", - 0, G_MAXUINT32, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER, param_spec); - - param_spec = g_param_spec_uint ("hold-state", "Local hold state", - "The current Local_Hold_State value as reported by the Hold interface", - TP_LOCAL_HOLD_STATE_UNHELD, TP_LOCAL_HOLD_STATE_PENDING_UNHOLD, - TP_LOCAL_HOLD_STATE_UNHELD, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_HOLD_STATE, param_spec); - - param_spec = g_param_spec_uint ("hold-state-reason", - "Local hold state change reason", - "The last Local_Hold_State_Reason value as reported by the Hold interface", - TP_LOCAL_HOLD_STATE_REASON_NONE, - TP_LOCAL_HOLD_STATE_REASON_RESOURCE_NOT_AVAILABLE, - TP_LOCAL_HOLD_STATE_REASON_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_HOLD_STATE_REASON, param_spec); - - param_spec = g_param_spec_string ("local-ip-address", "Local IP address", - "The local IP address preferred for media streams", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCAL_IP_ADDRESS, param_spec); - - param_spec = g_param_spec_boxed ("stun-servers", "STUN servers", - "Array of IP address-port pairs for available STUN servers", - TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVERS, param_spec); - - signals[SIG_DTMF_READY] = - g_signal_new ("dtmf-ready", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -rakia_media_session_dispose (GObject *object) -{ - RakiaMediaSession *self = RAKIA_MEDIA_SESSION (object); - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - - if (priv->dispose_has_run) - return; - - DEBUG("enter"); - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->dbus_daemon); - - tp_clear_object (&priv->sipsession); - - if (G_OBJECT_CLASS (rakia_media_session_parent_class)->dispose) - G_OBJECT_CLASS (rakia_media_session_parent_class)->dispose (object); - - DEBUG("exit"); -} - -static void -rakia_media_session_finalize (GObject *object) -{ - RakiaMediaSession *self = RAKIA_MEDIA_SESSION (object); - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - guint i; - - /* free any data held directly by the object here */ - - for (i = 0; i < priv->streams->len; i++) { - RakiaMediaStream *stream = g_ptr_array_index (priv->streams, i); - if (stream != NULL) - { - WARNING ("stream %u (%p) left over, reaping", i, stream); - g_object_unref (stream); - } - } - g_ptr_array_free(priv->streams, TRUE); - - g_free (priv->local_ip_address); - g_free (priv->object_path); - - G_OBJECT_CLASS (rakia_media_session_parent_class)->finalize (object); - - DEBUG("exit"); -} - - - -/** - * rakia_media_session_error - * - * Implements DBus method Error - * on interface org.freedesktop.Telepathy.Media.SessionHandler - */ -static void -rakia_media_session_error (TpSvcMediaSessionHandler *iface, - guint errno, - const gchar *message, - DBusGMethodInvocation *context) -{ - RakiaMediaSession *self = RAKIA_MEDIA_SESSION (iface); - RakiaMediaSessionPrivate *priv = self->priv; - - SESSION_DEBUG (obj, "Media.SessionHandler::Error called (%s), terminating session", message); - - rakia_sip_session_terminate (priv->sipsession); - - tp_svc_media_session_handler_return_from_error (context); -} - -static void priv_emit_new_stream (RakiaMediaSession *self, - RakiaMediaStream *stream) -{ - gchar *object_path; - guint id; - guint media_type; - guint direction; - - g_object_get (stream, - "object-path", &object_path, - "id", &id, - "media-type", &media_type, - "direction", &direction, - NULL); - - /* note: all of the streams are bidirectional from farsight's point of view, it's - * just in the signalling they change */ - - tp_svc_media_session_handler_emit_new_stream_handler ( - (TpSvcMediaSessionHandler *)self, object_path, id, media_type, - direction); - - g_free (object_path); -} - - -/** - * rakia_media_session_ready - * - * Implements DBus method Ready - * on interface org.freedesktop.Telepathy.Media.SessionHandler - */ -static void -rakia_media_session_ready (TpSvcMediaSessionHandler *iface, - DBusGMethodInvocation *context) -{ - RakiaMediaSession *self = RAKIA_MEDIA_SESSION (iface); - RakiaMediaSessionPrivate *priv = self->priv; - guint i; - - SESSION_DEBUG (self, "Media.SessionHandler.Ready called"); - - if (!priv->se_ready) - { - priv->se_ready = TRUE; - - for (i = 0; i < priv->streams->len; i++) - { - RakiaMediaStream *stream = g_ptr_array_index (priv->streams, i); - if (stream) - priv_emit_new_stream (self, stream); - } - } - - tp_svc_media_session_handler_return_from_ready (context); -} - -/*********************************************************************** - * Helper functions follow (not based on generated templates) - ***********************************************************************/ - -TpHandle -rakia_media_session_get_peer (RakiaMediaSession *session) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - return priv->peer; -} - -static gboolean -rakia_media_session_supports_media_type (guint media_type) -{ - switch (media_type) - { - case TP_MEDIA_STREAM_TYPE_AUDIO: - case TP_MEDIA_STREAM_TYPE_VIDEO: - return TRUE; - } - return FALSE; -} - -static void -priv_apply_streams_pending_direction (RakiaMediaSession *session, - guint pending_send_mask) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - RakiaMediaStream *stream; - guint i; - - /* If there has been a local change pending a re-INVITE, - * suspend remote approval until the next transaction */ - if (rakia_sip_session_pending_offer (priv->sipsession)) - pending_send_mask &= ~(guint)TP_MEDIA_STREAM_PENDING_REMOTE_SEND; - - /* Apply the pending direction changes */ - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream != NULL) - rakia_media_stream_apply_pending_direction (stream, pending_send_mask); - } -} - - -void -priv_add_stream_list_entry (GPtrArray *list, - RakiaMediaStream *stream, - RakiaMediaSession *session) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - GValue entry = { 0 }; - GType stream_type; - guint id; - TpMediaStreamType type = TP_MEDIA_STREAM_TYPE_AUDIO; - TpMediaStreamState connection_state = TP_MEDIA_STREAM_STATE_CONNECTED; - TpMediaStreamDirection direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; - guint pending_send_flags = 0; - - g_assert(stream != NULL); - - g_object_get (stream, - "id", &id, - "media-type", &type, - "state", &connection_state, - "direction", &direction, - "pending-send-flags", &pending_send_flags, - NULL); - - stream_type = TP_STRUCT_TYPE_MEDIA_STREAM_INFO; - - g_value_init (&entry, stream_type); - g_value_take_boxed (&entry, - dbus_g_type_specialized_construct (stream_type)); - - dbus_g_type_struct_set (&entry, - 0, id, - 1, priv->peer, - 2, type, - 3, connection_state, - 4, direction, - 5, pending_send_flags, - G_MAXUINT); - - g_ptr_array_add (list, g_value_get_boxed (&entry)); -} - -gboolean rakia_media_session_request_streams (RakiaMediaSession *session, - const GArray *media_types, - GPtrArray *ret, - GError **error) -{ - guint i; - - DEBUG ("enter"); - - /* Validate the media types before creating any streams */ - for (i = 0; i < media_types->len; i++) { - guint media_type = g_array_index (media_types, guint, i); - if (!rakia_media_session_supports_media_type (media_type)) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "media type #%u is not supported", i); - return FALSE; - } - } - - for (i = 0; i < media_types->len; i++) { - guint media_type = g_array_index (media_types, guint, i); - RakiaMediaStream *stream; - - stream = rakia_media_session_add_stream (session, - media_type, - TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TRUE); - - if (stream == NULL) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "creation of stream %u failed", i); - /* XXX: should we close the streams already created as part of - * this request, despite having emitted signals about them? */ - return FALSE; - } - - priv_add_stream_list_entry (ret, stream, session); - } - - return TRUE; -} - -gboolean -rakia_media_session_remove_streams (RakiaMediaSession *self, - const GArray *stream_ids, - GError **error) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - RakiaSipMedia *media; - guint stream_id; - guint i; - - DEBUG ("enter"); - - for (i = 0; i < stream_ids->len; i++) - { - stream_id = g_array_index (stream_ids, guint, i); - stream = rakia_media_session_get_stream (self, stream_id, error); - if (stream == NULL) - return FALSE; - media = rakia_media_stream_get_media (stream); - rakia_media_stream_close (stream); - rakia_sip_session_remove_media (priv->sipsession, media); - } - - rakia_sip_session_media_changed (priv->sipsession); - - return TRUE; -} - -void rakia_media_session_list_streams (RakiaMediaSession *session, - GPtrArray *ret) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - RakiaMediaStream *stream; - guint i; - - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream) - priv_add_stream_list_entry (ret, stream, session); - } -} - - -static gboolean -rakia_media_session_is_local_hold_ongoing (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - return (priv->hold_state == TP_LOCAL_HOLD_STATE_HELD - || priv->hold_state == TP_LOCAL_HOLD_STATE_PENDING_HOLD); -} - -gboolean -rakia_media_session_request_stream_direction (RakiaMediaSession *self, - guint stream_id, - guint direction, - GError **error) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - RakiaSipSessionState state; - - stream = rakia_media_session_get_stream (self, stream_id, error); - if (stream == NULL) - { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "stream %u does not exist", stream_id); - return FALSE; - } - - state = rakia_sip_session_get_state (priv->sipsession); - - SESSION_DEBUG (self, "direction %u requested for stream %u", - direction, stream_id); - - if (state == RAKIA_SIP_SESSION_STATE_INVITE_RECEIVED - || state == RAKIA_SIP_SESSION_STATE_REINVITE_RECEIVED) - { - /* While processing a session offer, we can only mask out direction - * requested by the remote peer */ - direction &= rakia_sip_media_get_requested_direction ( - rakia_media_stream_get_media (stream)); - } - - if (rakia_media_session_is_local_hold_ongoing (self)) - direction = RAKIA_DIRECTION_NONE; - - rakia_sip_media_set_requested_direction ( - rakia_media_stream_get_media (stream), direction); - - return TRUE; -} - - -void -rakia_media_session_accept (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - - if (rakia_sip_session_is_accepted (priv->sipsession)) - return; - - SESSION_DEBUG (self, "accepting the session"); - - rakia_sip_session_accept (priv->sipsession); - - /* Apply the pending send flags */ - priv_apply_streams_pending_direction (self, - TP_MEDIA_STREAM_PENDING_LOCAL_SEND | - TP_MEDIA_STREAM_PENDING_REMOTE_SEND); - - /* Can play the DTMF dialstring if an audio stream is connected */ - if (priv->audio_connected) - g_signal_emit (self, signals[SIG_DTMF_READY], 0); -} - - -static RakiaMediaStream * -rakia_media_session_get_stream (RakiaMediaSession *self, - guint stream_id, - GError **error) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - - g_assert (priv->streams != NULL); - - if (stream_id >= priv->streams->len) - { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "stream ID %u is invalid", stream_id); - return NULL; - } - - stream = g_ptr_array_index (priv->streams, stream_id); - - if (stream == NULL) - { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "stream %u does not exist", stream_id); - return NULL; - } - - return stream; -} - -TpLocalHoldState -rakia_media_session_get_hold_state (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - return priv->hold_state; -} - -static void -priv_initiate_hold (RakiaMediaSession *self, - gboolean hold, - TpLocalHoldStateReason reason) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - gboolean stream_hold_requested = FALSE; - RakiaMediaStream *stream; - guint i; - - DEBUG("enter"); - - if (hold) - { - if (priv->hold_state == TP_LOCAL_HOLD_STATE_HELD - || priv->hold_state == TP_LOCAL_HOLD_STATE_PENDING_HOLD) - { - MESSAGE ("redundant hold request"); - return; - } - } - else - { - if (priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD - || priv->hold_state == TP_LOCAL_HOLD_STATE_PENDING_UNHOLD) - { - MESSAGE ("redundant unhold request"); - return; - } - } - - /* Emit the hold notification for every stream that needs it */ - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream != NULL - && rakia_media_stream_request_hold_state (stream, hold)) - stream_hold_requested = TRUE; - } - - if (stream_hold_requested) - { - priv->hold_state = hold? TP_LOCAL_HOLD_STATE_PENDING_HOLD - : TP_LOCAL_HOLD_STATE_PENDING_UNHOLD; - } - else - { - /* There were no streams to flip, short cut to the final state */ - priv->hold_state = hold? TP_LOCAL_HOLD_STATE_HELD - : TP_LOCAL_HOLD_STATE_UNHELD; - } - priv->hold_reason = reason; - - tp_svc_channel_interface_hold_emit_hold_state_changed (priv->channel, - priv->hold_state, reason); -} - -static void -priv_finalize_hold (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - TpLocalHoldState final_hold_state; - guint i; - gboolean held = FALSE; - RakiaDirection dir; - - DEBUG("enter"); - - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - held = TRUE; - break; - case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: - held = FALSE; - break; - default: - /* Streams changed state without request, signal this to the client. - * All streams should have the same hold state at this point, - * so just query one of them for the current hold state */ - stream = NULL; - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream != NULL) - break; - } - g_return_if_fail (stream != NULL); - - g_object_get (stream, "hold-state", &held, NULL); - } - - if (held) - { - final_hold_state = TP_LOCAL_HOLD_STATE_HELD; - dir = RAKIA_DIRECTION_NONE; - } - else - { - final_hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - dir = RAKIA_DIRECTION_BIDIRECTIONAL; - } - - priv->hold_state = final_hold_state; - tp_svc_channel_interface_hold_emit_hold_state_changed (priv->channel, - final_hold_state, priv->hold_reason); - - /* Set stream directions accordingly to the achieved hold state */ - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream != NULL) - { - rakia_sip_media_set_requested_direction ( - rakia_media_stream_get_media (stream), dir); - } - } -} - -void -rakia_media_session_request_hold (RakiaMediaSession *self, - gboolean hold) -{ - priv_initiate_hold (self, - hold, - TP_LOCAL_HOLD_STATE_REASON_REQUESTED); -} - -gboolean -rakia_media_session_has_media (RakiaMediaSession *self, - TpMediaStreamType type) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - guint i; - - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream == NULL) - continue; - if (rakia_media_stream_get_media_type (stream) == type) - return TRUE; - } - - return FALSE; -} - -void -rakia_media_session_start_telephony_event (RakiaMediaSession *self, - guchar event) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - guint i; - - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream == NULL) - continue; - if (rakia_media_stream_get_media_type (stream) - != TP_MEDIA_STREAM_TYPE_AUDIO) - continue; - - SESSION_DEBUG (self, "starting telephony event %u on stream %u", - (guint) event, i); - - rakia_media_stream_start_telephony_event (stream, event); - } -} - -void -rakia_media_session_stop_telephony_event (RakiaMediaSession *self) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream; - guint i; - - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index(priv->streams, i); - if (stream == NULL) - continue; - if (rakia_media_stream_get_media_type (stream) - != TP_MEDIA_STREAM_TYPE_AUDIO) - continue; - - SESSION_DEBUG (self, "stopping the telephony event on stream %u", i); - - rakia_media_stream_stop_telephony_event (stream); - } -} - -gint -rakia_media_session_rate_native_transport (RakiaMediaSession *session, - const GValue *transport) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - gint result = 0; - gchar *address = NULL; - guint proto = TP_MEDIA_STREAM_BASE_PROTO_UDP; - - dbus_g_type_struct_get (transport, - 1, &address, - 3, &proto, - G_MAXUINT); - - g_assert (address != NULL); - - if (proto != TP_MEDIA_STREAM_BASE_PROTO_UDP) - result = -1; - /* XXX: this will not work properly when IPv6 support comes */ - else if (priv->local_ip_address != NULL - && strcmp (address, priv->local_ip_address) == 0) - result = 1; - - g_free (address); - - return result; -} - -static void -priv_stream_close_cb (RakiaMediaStream *stream, - RakiaMediaSession *session) -{ - RakiaMediaSessionPrivate *priv; - RakiaSipMedia *media; - guint id; - - DEBUG("enter"); - - priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - - id = rakia_media_stream_get_id (stream); - g_return_if_fail (g_ptr_array_index(priv->streams, id) == stream); - - media = rakia_media_stream_get_media (stream); - rakia_sip_session_remove_media (priv->sipsession, media); - - g_object_unref (stream); - - g_ptr_array_index(priv->streams, id) = NULL; - - tp_svc_channel_type_streamed_media_emit_stream_removed (priv->channel, id); -} - -static void -priv_stream_state_changed_cb (RakiaMediaStream *stream, - guint state, - RakiaMediaSession *session) -{ - RakiaMediaSessionPrivate *priv = session->priv; - - tp_svc_channel_type_streamed_media_emit_stream_state_changed( - priv->channel, - rakia_media_stream_get_id (stream), state); - - /* Check if DTMF can now be played */ - if (!priv->audio_connected - && state == TP_MEDIA_STREAM_STATE_CONNECTED - && rakia_media_stream_get_media_type (stream) - == TP_MEDIA_STREAM_TYPE_AUDIO) - { - priv->audio_connected = TRUE; - - if (rakia_sip_session_is_accepted (priv->sipsession)) - g_signal_emit (session, signals[SIG_DTMF_READY], 0); - } -} - -static void -priv_stream_direction_changed_cb (RakiaMediaStream *stream, - guint direction, - guint pending_send_flags, - RakiaMediaChannel *channel) -{ - g_assert (RAKIA_IS_MEDIA_CHANNEL (channel)); - tp_svc_channel_type_streamed_media_emit_stream_direction_changed ( - channel, - rakia_media_stream_get_id (stream), direction, pending_send_flags); -} - -static void -priv_stream_hold_state_cb (RakiaMediaStream *stream, - GParamSpec *pspec, - RakiaMediaSession *session) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (session); - gboolean hold; - guint i; - - /* Determine the hold state all streams shall come to */ - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - hold = TRUE; - break; - case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: - hold = FALSE; - break; - default: - SESSION_MESSAGE (session, "unexpected hold state change from a stream"); - - /* Try to follow the changes and report the resulting hold state */ - g_object_get (stream, "hold-state", &hold, NULL); - priv->hold_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - } - - /* Check if all streams have reached the desired hold state */ - for (i = 0; i < priv->streams->len; i++) - { - stream = g_ptr_array_index (priv->streams, i); - if (stream != NULL) - { - gboolean stream_held = FALSE; - g_object_get (stream, "hold-state", &stream_held, NULL); - if ((!stream_held) != (!hold)) - { - SESSION_DEBUG (session, "hold/unhold not complete yet"); - return; - } - } - } - - priv_finalize_hold (session); -} - -static void -priv_stream_unhold_failure_cb (RakiaMediaStream *stream, - RakiaMediaSession *session) -{ - priv_initiate_hold (session, - TRUE, - TP_LOCAL_HOLD_STATE_REASON_RESOURCE_NOT_AVAILABLE); -} - -RakiaMediaStream* -rakia_media_session_add_stream (RakiaMediaSession *self, - guint media_type, - TpMediaStreamDirection direction, - gboolean created_locally) -{ - RakiaMediaSessionPrivate *priv = RAKIA_MEDIA_SESSION_GET_PRIVATE (self); - RakiaMediaStream *stream = NULL; - - DEBUG ("enter"); - - if (rakia_media_session_supports_media_type (media_type)) { - guint stream_id; - gchar *object_path; - guint pending_send_flags; - RakiaSipMedia *media; - - stream_id = priv->streams->len; - object_path = g_strdup_printf ("%s/MediaStream%u", - priv->object_path, - stream_id); - pending_send_flags = created_locally - ? TP_MEDIA_STREAM_PENDING_REMOTE_SEND - : TP_MEDIA_STREAM_PENDING_LOCAL_SEND; - - if (!created_locally) - direction &= ~TP_MEDIA_STREAM_DIRECTION_SEND; - - if (rakia_media_session_is_local_hold_ongoing (self)) - direction &= ~TP_MEDIA_STREAM_DIRECTION_RECEIVE; - - media = rakia_sip_session_add_media (priv->sipsession, - media_type, direction, created_locally); - - stream = g_object_new (RAKIA_TYPE_MEDIA_STREAM, - "dbus-daemon", priv->dbus_daemon, - "media-session", self, - "sip-media", media, - "media-type", media_type, - "object-path", object_path, - "id", stream_id, - "direction", direction, - "pending-send-flags", pending_send_flags, - "created-locally", created_locally, - NULL); - - g_free (object_path); - - g_signal_connect (stream, "close", - G_CALLBACK (priv_stream_close_cb), - self); - g_signal_connect (stream, "state-changed", - G_CALLBACK (priv_stream_state_changed_cb), - self); - g_signal_connect (stream, "direction-changed", - G_CALLBACK (priv_stream_direction_changed_cb), - priv->channel); - g_signal_connect (stream, "notify::hold-state", - G_CALLBACK (priv_stream_hold_state_cb), - self); - g_signal_connect (stream, "unhold-failure", - G_CALLBACK (priv_stream_unhold_failure_cb), - self); - - g_assert (priv->local_non_ready >= 0); - ++priv->local_non_ready; - - if (priv->se_ready) - priv_emit_new_stream (self, stream); - - tp_svc_channel_type_streamed_media_emit_stream_added (priv->channel, - stream_id, - priv->peer, - media_type); - if (direction != TP_MEDIA_STREAM_DIRECTION_RECEIVE - || pending_send_flags != TP_MEDIA_STREAM_PENDING_LOCAL_SEND) - { - tp_svc_channel_type_streamed_media_emit_stream_direction_changed ( - priv->channel, - stream_id, - direction, - pending_send_flags); - } - } - - /* note: we add an entry even for unsupported media types */ - g_ptr_array_add (priv->streams, stream); - - DEBUG ("exit"); - - return stream; -} - -static void -session_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaSessionHandlerClass *klass = (TpSvcMediaSessionHandlerClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_media_session_handler_implement_##x (\ - klass, (tp_svc_media_session_handler_##x##_impl) rakia_media_session_##x) - IMPLEMENT(error); - IMPLEMENT(ready); -#undef IMPLEMENT -} - - -gboolean -rakia_media_session_is_accepted (RakiaMediaSession *self) -{ - return rakia_sip_session_is_accepted (self->priv->sipsession); -} diff --git a/rakia/media-session.h b/rakia/media-session.h deleted file mode 100644 index 0a0c795..0000000 --- a/rakia/media-session.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * sip-media-session.h - Header for RakiaMediaSession - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005-2010 Nokia Corporation - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __RAKIA_MEDIA_SESSION_H__ -#define __RAKIA_MEDIA_SESSION_H__ - -#include <rakia/media-stream.h> - -#include <glib-object.h> -#include <telepathy-glib/handle.h> -#include <sofia-sip/sdp.h> - -G_BEGIN_DECLS - -typedef struct _RakiaMediaSession RakiaMediaSession; -typedef struct _RakiaMediaSessionClass RakiaMediaSessionClass; -typedef struct _RakiaMediaSessionPrivate RakiaMediaSessionPrivate; - -struct _RakiaMediaSessionClass { - GObjectClass parent_class; -}; - -struct _RakiaMediaSession { - GObject parent; - RakiaMediaSessionPrivate *priv; -}; - -GType rakia_media_session_get_type(void); - -/* TYPE MACROS */ -#define RAKIA_TYPE_MEDIA_SESSION \ - (rakia_media_session_get_type()) -#define RAKIA_MEDIA_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), RAKIA_TYPE_MEDIA_SESSION, RakiaMediaSession)) -#define RAKIA_MEDIA_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), RAKIA_TYPE_MEDIA_SESSION, RakiaMediaSessionClass)) -#define RAKIA_IS_MEDIA_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), RAKIA_TYPE_MEDIA_SESSION)) -#define RAKIA_IS_MEDIA_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), RAKIA_TYPE_MEDIA_SESSION)) -#define RAKIA_MEDIA_SESSION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), RAKIA_TYPE_MEDIA_SESSION, RakiaMediaSessionClass)) - -/*********************************************************************** - * Additional declarations (not based on generated templates) - ***********************************************************************/ - -TpHandle rakia_media_session_get_peer (RakiaMediaSession *session); -RakiaMediaStream* rakia_media_session_add_stream (RakiaMediaSession *self, - guint media_type, - TpMediaStreamDirection direction, - gboolean created_locally); -gboolean rakia_media_session_request_streams (RakiaMediaSession *session, - const GArray *media_types, - GPtrArray *ret, - GError **error); -gboolean rakia_media_session_remove_streams (RakiaMediaSession *session, - const GArray *stream_ids, - GError **error); -void rakia_media_session_list_streams (RakiaMediaSession *session, - GPtrArray *ret); -gboolean rakia_media_session_request_stream_direction (RakiaMediaSession *session, - guint stream_id, - guint direction, - GError **error); -void rakia_media_session_accept (RakiaMediaSession *self); -gboolean rakia_media_session_is_accepted (RakiaMediaSession *self); - -TpLocalHoldState rakia_media_session_get_hold_state (RakiaMediaSession *session); -void rakia_media_session_request_hold (RakiaMediaSession *session, - gboolean hold); - -gboolean rakia_media_session_has_media (RakiaMediaSession *self, - TpMediaStreamType type); - -void rakia_media_session_start_telephony_event (RakiaMediaSession *self, - guchar event); -void rakia_media_session_stop_telephony_event (RakiaMediaSession *self); - -gint rakia_media_session_rate_native_transport (RakiaMediaSession *session, - const GValue *transport); - -gchar * rakia_sdp_get_string_attribute (const sdp_attribute_t *attrs, - const char *name); - -G_END_DECLS - -#endif /* #ifndef __RAKIA_MEDIA_SESSION_H__*/ diff --git a/rakia/media-stream.c b/rakia/media-stream.c deleted file mode 100644 index 3b62353..0000000 --- a/rakia/media-stream.c +++ /dev/null @@ -1,1532 +0,0 @@ -/* - * sip-media-stream.c - Source for RakiaMediaStream - * Copyright (C) 2006 Collabora Ltd. - * Copyright (C) 2006-2010 Nokia Corporation - * @author Kai Vehmanen <first.surname@nokia.com> - * @author Mikhail Zabaluev <mikhail.zabaluev@nokia.com> - * - * Based on telepathy-gabble implementation (gabble-media-stream). - * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk> - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "rakia/media-stream.h" - -#include <dbus/dbus-glib.h> -#include <stdlib.h> -#include <string.h> - -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-generic.h> -#include <telepathy-glib/svc-media-interfaces.h> -#include <telepathy-glib/util.h> - -#include "config.h" - -#include <rakia/codec-param-formats.h> - - -#include "rakia/media-session.h" -#include "rakia/sip-session.h" - -#include <sofia-sip/msg_parser.h> - -#include "signals-marshal.h" - -#define DEBUG_FLAG RAKIA_DEBUG_MEDIA -#include "rakia/debug.h" - - -#define same_boolean(old, new) ((!(old)) == (!(new))) - - -#ifdef ENABLE_DEBUG - -#define STREAM_DEBUG(stream, format, ...) \ - rakia_log (DEBUG_FLAG, G_LOG_LEVEL_DEBUG, "stream %u: " format, \ - (stream)->priv->id,##__VA_ARGS__) - -#define STREAM_MESSAGE(stream, format, ...) \ - rakia_log (DEBUG_FLAG, G_LOG_LEVEL_MESSAGE, "stream %u: " format, \ - (stream)->priv->id,##__VA_ARGS__) - -#else - -#define STREAM_DEBUG(stream, format, ...) G_STMT_START { } G_STMT_END -#define STREAM_MESSAGE(stream, format, ...) G_STMT_START { } G_STMT_END - -#endif - - -static void stream_handler_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE(RakiaMediaStream, - rakia_media_stream, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_STREAM_HANDLER, - stream_handler_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - ) - -/* signal enum */ -enum -{ - SIG_READY, - SIG_SUPPORTED_CODECS, - SIG_STATE_CHANGED, - SIG_DIRECTION_CHANGED, - SIG_LOCAL_MEDIA_UPDATED, - SIG_UNHOLD_FAILURE, - - SIG_LAST_SIGNAL -}; - -static guint signals[SIG_LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_MEDIA_SESSION = 1, - PROP_DBUS_DAEMON, - PROP_OBJECT_PATH, - PROP_ID, - PROP_MEDIA_TYPE, - PROP_SIP_MEDIA, - PROP_STATE, - PROP_DIRECTION, - PROP_PENDING_SEND_FLAGS, - PROP_HOLD_STATE, - PROP_CREATED_LOCALLY, - PROP_NAT_TRAVERSAL, - PROP_STUN_SERVERS, - PROP_RELAY_INFO, - LAST_PROPERTY -}; - -static GPtrArray *rakia_media_stream_relay_info_empty = NULL; - -/* private structure */ -struct _RakiaMediaStreamPrivate -{ - TpDBusDaemon *dbus_daemon; - RakiaMediaSession *session; /* see gobj. prop. 'media-session' */ - gchar *object_path; /* see gobj. prop. 'object-path' */ - RakiaSipMedia *media; - guint id; /* see gobj. prop. 'id' */ - guint media_type; /* see gobj. prop. 'media-type' */ - guint state; /* see gobj. prop. 'state' */ - guint direction; /* see gobj. prop. 'direction' */ - guint pending_send_flags; /* see gobj. prop. 'pending-send-flags' */ - gboolean hold_state; /* see gobj. prop. 'hold-state' */ - gboolean created_locally; /* see gobj. prop. 'created-locally' */ - - guint remote_candidate_counter; - gchar *remote_candidate_id; - - gchar *native_candidate_id; - - gboolean ready_received; /* our ready method has been called */ - gboolean playing; /* stream set to playing */ - gboolean sending; /* stream set to sending */ - gboolean pending_remote_receive; /* TRUE if remote is to agree to receive media */ - gboolean native_cands_prepared; /* all candidates discovered */ - gboolean native_codecs_prepared; /* all codecs discovered */ - gboolean push_remote_cands_pending; /* SetRemoteCandidates emission is pending */ - gboolean push_remote_codecs_pending; /* SetRemoteCodecs emission is pending */ - gboolean codec_intersect_pending; /* codec intersection is pending */ - gboolean requested_hold_state; /* hold state last requested from the stream handler */ - gboolean dispose_has_run; -}; - -#define RAKIA_MEDIA_STREAM_GET_PRIVATE(stream) ((stream)->priv) - -static void push_remote_codecs (RakiaMediaStream *stream); -static void push_remote_candidates (RakiaMediaStream *stream); -static void priv_update_sending (RakiaMediaStream *stream, - TpMediaStreamDirection direction); -static void priv_emit_local_ready (RakiaMediaStream *stream); - -/*********************************************************************** - * Set: Gobject interface - ***********************************************************************/ - -static void -rakia_media_stream_init (RakiaMediaStream *self) -{ - RakiaMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), - RAKIA_TYPE_MEDIA_STREAM, RakiaMediaStreamPrivate); - - self->priv = priv; -} - -static void -rakia_media_stream_constructed (GObject *obj) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE ( - RAKIA_MEDIA_STREAM (obj)); - GObjectClass *parent_object_class = - G_OBJECT_CLASS (rakia_media_stream_parent_class); - - /* call base class method */ - if (parent_object_class->constructed != NULL) - parent_object_class->constructed (obj); - - /* XXX: overloading the remote pending send flag to check - * if this is a locally offered stream. The code creating such streams - * always sets the flag, because the remote end is supposed to decide - * whether it wants to send. - * This may look weird during a local hold. However, the pending flag - * will be harmlessly cleared once the offer-answer is complete. */ - if ((priv->direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0 - && (priv->pending_send_flags & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0) - { - /* Block sending until the stream is remotely accepted */ - priv->pending_remote_receive = TRUE; - } - - g_signal_connect_object (priv->media, "remote-candidates-updated", - G_CALLBACK (push_remote_candidates), obj, G_CONNECT_SWAPPED); - g_signal_connect_object (priv->media, "remote-codecs-updated", - G_CALLBACK (push_remote_codecs), obj, G_CONNECT_SWAPPED); - - /* go for the bus */ - g_assert (TP_IS_DBUS_DAEMON (priv->dbus_daemon)); - tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); -} - -static void -rakia_media_stream_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - RakiaMediaStream *stream = RAKIA_MEDIA_STREAM (object); - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - switch (property_id) - { - case PROP_DBUS_DAEMON: - g_value_set_object (value, priv->dbus_daemon); - break; - case PROP_MEDIA_SESSION: - g_value_set_object (value, priv->session); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_ID: - g_value_set_uint (value, priv->id); - break; - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_SIP_MEDIA: - g_value_set_object (value, priv->media); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_DIRECTION: - g_value_set_uint (value, priv->direction); - break; - case PROP_PENDING_SEND_FLAGS: - g_value_set_uint (value, priv->pending_send_flags); - break; - case PROP_HOLD_STATE: - g_value_set_boolean (value, priv->hold_state); - break; - case PROP_CREATED_LOCALLY: - g_value_set_boolean (value, priv->created_locally); - break; - case PROP_NAT_TRAVERSAL: - g_value_set_static_string (value, "none"); - break; - case PROP_STUN_SERVERS: - g_return_if_fail (priv->session != NULL); - g_object_get_property (G_OBJECT (priv->session), "stun-servers", value); - break; - case PROP_RELAY_INFO: - g_value_set_static_boxed (value, rakia_media_stream_relay_info_empty); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -rakia_media_stream_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - RakiaMediaStream *stream = RAKIA_MEDIA_STREAM (object); - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - switch (property_id) - { - case PROP_DBUS_DAEMON: - g_assert (priv->dbus_daemon == NULL); /* construct-only */ - priv->dbus_daemon = g_value_dup_object (value); - break; - case PROP_MEDIA_SESSION: - priv->session = g_value_get_object (value); - break; - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_ID: - priv->id = g_value_get_uint (value); - break; - case PROP_MEDIA_TYPE: - priv->media_type = g_value_get_uint (value); - break; - case PROP_SIP_MEDIA: - priv->media = g_value_dup_object (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - case PROP_DIRECTION: - priv->direction = g_value_get_uint (value); - break; - case PROP_PENDING_SEND_FLAGS: - priv->pending_send_flags = g_value_get_uint (value); - break; - case PROP_HOLD_STATE: - priv->hold_state = g_value_get_boolean (value); - break; - case PROP_CREATED_LOCALLY: - priv->created_locally = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void rakia_media_stream_dispose (GObject *object); -static void rakia_media_stream_finalize (GObject *object); - -static void -rakia_media_stream_class_init (RakiaMediaStreamClass *klass) -{ - static TpDBusPropertiesMixinPropImpl stream_handler_props[] = { - { "CreatedLocally", "created-locally", NULL }, - { "NATTraversal", "nat-traversal", NULL }, - { "STUNServers", "stun-servers", NULL }, - { "RelayInfo", "relay-info", NULL }, - { NULL } - }; - - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_MEDIA_STREAM_HANDLER, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - stream_handler_props, - }, - { NULL } - }; - - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GType stream_type = G_OBJECT_CLASS_TYPE (klass); - GParamSpec *param_spec; - - g_type_class_add_private (klass, sizeof (RakiaMediaStreamPrivate)); - - object_class->constructed = rakia_media_stream_constructed; - - object_class->get_property = rakia_media_stream_get_property; - object_class->set_property = rakia_media_stream_set_property; - - object_class->dispose = rakia_media_stream_dispose; - object_class->finalize = rakia_media_stream_finalize; - - param_spec = g_param_spec_object ("dbus-daemon", "TpDBusDaemon", - "Connection to D-Bus.", TP_TYPE_DBUS_DAEMON, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DBUS_DAEMON, param_spec); - - param_spec = g_param_spec_object ("media-session", "RakiaMediaSession object", - "SIP media session object that owns this media stream object.", - RAKIA_TYPE_MEDIA_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_SESSION, param_spec); - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_uint ("id", "Stream ID", - "A stream number for the stream used in the D-Bus API.", - 0, G_MAXUINT, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_ID, param_spec); - - param_spec = g_param_spec_uint ("media-type", "Stream media type", - "A constant indicating which media type the stream carries.", - TP_MEDIA_STREAM_TYPE_AUDIO, TP_MEDIA_STREAM_TYPE_VIDEO, - TP_MEDIA_STREAM_TYPE_AUDIO, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - - param_spec = g_param_spec_object ("sip-media", "RakiaSipMedia object", - "SIP media session object that owns this media stream object.", - RAKIA_TYPE_MEDIA_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_SESSION, param_spec); - - - param_spec = g_param_spec_uint ("state", "Connection state", - "Connection state of the media stream", - TP_MEDIA_STREAM_STATE_DISCONNECTED, TP_MEDIA_STREAM_STATE_CONNECTED, - TP_MEDIA_STREAM_STATE_DISCONNECTED, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* We don't change the following two as individual properties - * after construction, use rakia_media_stream_set_direction() */ - - param_spec = g_param_spec_uint ("direction", "Stream direction", - "A value indicating the current direction of the stream", - TP_MEDIA_STREAM_DIRECTION_NONE, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DIRECTION, param_spec); - - param_spec = g_param_spec_uint ("pending-send-flags", "Pending send flags", - "Flags indicating the current pending send state of the stream", - 0, - TP_MEDIA_STREAM_PENDING_LOCAL_SEND | TP_MEDIA_STREAM_PENDING_REMOTE_SEND, - 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_PENDING_SEND_FLAGS, - param_spec); - - param_spec = g_param_spec_boolean ("hold-state", "Hold state", - "Hold state of the media stream as reported by the stream engine", - FALSE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, - PROP_HOLD_STATE, - param_spec); - - param_spec = g_param_spec_boolean ("created-locally", "Created locally?", - "True if this stream was created by the local user", FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATED_LOCALLY, - param_spec); - - param_spec = g_param_spec_string ("nat-traversal", "NAT traversal", - "NAT traversal mechanism for this stream", NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, - param_spec); - - param_spec = g_param_spec_boxed ("stun-servers", "STUN servers", - "Array of IP address-port pairs for available STUN servers", - TP_ARRAY_TYPE_SOCKET_ADDRESS_IP_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVERS, param_spec); - - param_spec = g_param_spec_boxed ("relay-info", "Relay info", - "Array of mappings containing relay server information", - TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_RELAY_INFO, param_spec); - - rakia_media_stream_relay_info_empty = g_ptr_array_new (); - - /* signals not exported by DBus interface */ - signals[SIG_READY] = - g_signal_new ("ready", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[SIG_SUPPORTED_CODECS] = - g_signal_new ("supported-codecs", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - signals[SIG_STATE_CHANGED] = - g_signal_new ("state-changed", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - signals[SIG_DIRECTION_CHANGED] = - g_signal_new ("direction-changed", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - _rakia_marshal_VOID__UINT_UINT, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); - - signals[SIG_LOCAL_MEDIA_UPDATED] = - g_signal_new ("local-media-updated", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[SIG_UNHOLD_FAILURE] = - g_signal_new ("unhold-failure", - stream_type, - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - klass->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (RakiaMediaStreamClass, dbus_props_class)); -} - -void -rakia_media_stream_dispose (GObject *object) -{ - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (object); - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->media); - tp_clear_object (&priv->dbus_daemon); - - if (G_OBJECT_CLASS (rakia_media_stream_parent_class)->dispose) - G_OBJECT_CLASS (rakia_media_stream_parent_class)->dispose (object); - - DEBUG ("exit"); -} - -void -rakia_media_stream_finalize (GObject *object) -{ - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (object); - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - - /* free any data held directly by the object here */ - g_free (priv->object_path); - - - g_free (priv->native_candidate_id); - g_free (priv->remote_candidate_id); - - G_OBJECT_CLASS (rakia_media_stream_parent_class)->finalize (object); - - DEBUG ("exit"); -} - -/*********************************************************************** - * Set: Media.StreamHandler interface implementation (same for 0.12/0.13???) - ***********************************************************************/ - -/** - * rakia_media_stream_error - * - * Implements DBus method Error - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_error (TpSvcMediaStreamHandler *iface, - guint errno, - const gchar *message, - DBusGMethodInvocation *context) -{ - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (iface); - - STREAM_DEBUG (self, "StreamHandler.Error called: %u %s", errno, message); - - rakia_media_stream_close (self); - - tp_svc_media_stream_handler_return_from_error (context); -} - -/** - * rakia_media_stream_native_candidates_prepared - * - * Implements DBus method NativeCandidatesPrepared - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_native_candidates_prepared (TpSvcMediaStreamHandler *iface, - DBusGMethodInvocation *context) -{ - /* purpose: "Informs the connection manager that all possible native candisates - * have been discovered for the moment." - */ - - RakiaMediaStream *obj = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv = obj->priv; - - STREAM_DEBUG(obj, "Media.StreamHandler.NativeCandidatesPrepared called"); - - priv->native_cands_prepared = TRUE; - - rakia_sip_media_local_candidates_prepared (priv->media); - - if (priv->native_codecs_prepared) - priv_emit_local_ready (obj); - - tp_svc_media_stream_handler_return_from_native_candidates_prepared (context); -} - - -/** - * rakia_media_stream_new_active_candidate_pair - * - * Implements DBus method NewActiveCandidatePair - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_new_active_candidate_pair (TpSvcMediaStreamHandler *iface, - const gchar *native_candidate_id, - const gchar *remote_candidate_id, - DBusGMethodInvocation *context) -{ - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv = self->priv; - - STREAM_DEBUG (self, "stream engine reported new active candidate pair %s-%s", - native_candidate_id, remote_candidate_id); - - if (priv->remote_candidate_id == NULL - || strcmp (priv->remote_candidate_id, remote_candidate_id)) - { - GError *err; - err = g_error_new (TP_ERRORS, - TP_ERROR_INVALID_ARGUMENT, - "Remote candidate ID does not match the locally " - "stored data"); - dbus_g_method_return_error (context, err); - g_error_free (err); - return; - } - - tp_svc_media_stream_handler_return_from_new_active_candidate_pair (context); -} - - -/** - * rakia_media_stream_new_native_candidate - * - * Implements DBus method NewNativeCandidate - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, - const gchar *candidate_id, - const GPtrArray *transports, - DBusGMethodInvocation *context) -{ - RakiaMediaStream *obj = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv; - GValue transport = { 0, }; - guint i; - - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (obj); - - g_return_if_fail (transports->len >= 1); - - - /* Rate the preferability of the address */ - g_value_init (&transport, TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT); - - for (i = 0; i < transports->len; i++) - { - RakiaSipCandidate *sipcandidate; - guint tr_component; - guint tr_proto = G_MAXUINT; - gchar *tr_ip; - guint tr_port; - gdouble tr_preference; - - g_value_set_static_boxed (&transport, - g_ptr_array_index (transports, i)); - - /* Find the RTP component */ - dbus_g_type_struct_get (&transport, - 0, &tr_component, - 1, &tr_ip, - 2, &tr_port, - 3, &tr_proto, - 6, &tr_preference, - G_MAXUINT); - - if (tr_proto != TP_MEDIA_STREAM_BASE_PROTO_UDP) - continue; - - sipcandidate = rakia_sip_candidate_new (tr_component, - tr_ip, tr_port, candidate_id, (guint) tr_preference * 65536); - - g_free (tr_ip); - - rakia_sip_media_take_local_candidate (priv->media, sipcandidate); - } - - - STREAM_DEBUG(obj, "put native candidate '%s' into cache", candidate_id); - - tp_svc_media_stream_handler_return_from_new_native_candidate (context); -} - -static void -priv_set_local_codecs (RakiaMediaStream *self, - const GPtrArray *codecs) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - GPtrArray *sipcodecs = g_ptr_array_new_with_free_func ( - (GDestroyNotify)rakia_sip_codec_free); - GValue codec = { 0, }; - gchar *co_name = NULL; - guint co_id; - guint co_type; - guint co_clockrate; - guint co_channels; - GHashTable *co_params = NULL; - guint i; - STREAM_DEBUG(self, "putting list of %d locally supported codecs into cache", - codecs->len); - - g_value_init (&codec, TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC); - - for (i = 0; i < codecs->len; i++) - { - RakiaSipCodec *sipcodec; - GHashTableIter iter; - gpointer key, value; - - g_value_set_static_boxed (&codec, g_ptr_array_index (codecs, i)); - - dbus_g_type_struct_get (&codec, - 0, &co_id, - 1, &co_name, - 2, &co_type, - 3, &co_clockrate, - 4, &co_channels, - 5, &co_params, - G_MAXUINT); - - sipcodec = rakia_sip_codec_new (co_id, co_name, co_clockrate, - co_channels); - - g_hash_table_iter_init (&iter, co_params); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - rakia_sip_codec_add_param (sipcodec, key, value); - } - - g_ptr_array_add (sipcodecs, sipcodec); - - g_free (co_name); - co_name = NULL; - g_hash_table_unref (co_params); - co_params = NULL; - } - - rakia_sip_media_take_local_codecs (priv->media, sipcodecs); - - priv->native_codecs_prepared = TRUE; - if (priv->native_cands_prepared) - priv_emit_local_ready (self); -} - -static void -rakia_media_stream_codecs_updated (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - - if (!priv->native_codecs_prepared) - { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "CodecsUpdated may not be called before codecs have been provided " - "with SetLocalCodecs or Ready" }; - - STREAM_DEBUG (self, - "CodecsUpdated called before SetLocalCodecs or Ready"); - - dbus_g_method_return_error (context, &e); - } - else - { - STREAM_DEBUG (self, "putting list of %d locally supported " - "codecs from CodecsUpdated into cache", codecs->len); - priv_set_local_codecs (self, codecs); - - if (priv->native_cands_prepared) - g_signal_emit (self, signals[SIG_LOCAL_MEDIA_UPDATED], 0); - - tp_svc_media_stream_handler_return_from_codecs_updated (context); - } -} - -/** - * rakia_media_stream_ready - * - * Implements DBus method Ready - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_ready (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - /* purpose: "Inform the connection manager that a client is ready to handle - * this StreamHandler. Also provide it with info about all supported - * codecs." - * - * - note, with SIP we don't send the invite just yet (we need - * candidates first - */ - - RakiaMediaStream *obj = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv = obj->priv; - - STREAM_DEBUG (obj, "Media.StreamHandler.Ready called"); - - if (priv->ready_received) - { - STREAM_MESSAGE (obj, "Ready called more than once"); - tp_svc_media_stream_handler_return_from_ready (context); - return; - } - - priv->ready_received = TRUE; - - if (codecs->len != 0) - priv_set_local_codecs (obj, codecs); - - /* Push the initial sending/playing state */ - tp_svc_media_stream_handler_emit_set_stream_playing ( - iface, priv->playing); - tp_svc_media_stream_handler_emit_set_stream_sending ( - iface, priv->sending); - - if (priv->push_remote_cands_pending) - { - priv->push_remote_cands_pending = FALSE; - push_remote_candidates (obj); - } - if (priv->push_remote_codecs_pending) - { - priv->push_remote_codecs_pending = FALSE; - push_remote_codecs (obj); - } - - - rakia_media_stream_set_playing (obj, TRUE); - - tp_svc_media_stream_handler_return_from_ready (context); -} - -static void -rakia_media_stream_set_local_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - priv_set_local_codecs (RAKIA_MEDIA_STREAM (iface), codecs); - tp_svc_media_stream_handler_return_from_set_local_codecs (context); -} - -/** - * rakia_media_stream_stream_state - * - * Implements DBus method StreamState - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_stream_state (TpSvcMediaStreamHandler *iface, - guint state, - DBusGMethodInvocation *context) -{ - /* purpose: "Informs the connection manager of the stream's current state - * State is as specified in *ChannelTypeStreamedMedia::GetStreams." - * - * - set the stream state for session - */ - - RakiaMediaStream *obj = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv; - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (obj); - - if (priv->state != state) - { - STREAM_DEBUG (obj, "stream state change %u -> %u", priv->state, state); - priv->state = state; - g_signal_emit (obj, signals[SIG_STATE_CHANGED], 0, state); - } - - tp_svc_media_stream_handler_return_from_stream_state (context); -} - -/** - * rakia_media_stream_supported_codecs - * - * Implements DBus method SupportedCodecs - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -rakia_media_stream_supported_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - /* purpose: "Inform the connection manager of the supported codecs for this session. - * This is called after the connection manager has emitted SetRemoteCodecs - * to notify what codecs are supported by the peer, and will thus be an - * intersection of all locally supported codecs (passed to Ready) - * and those supported by the peer." - * - * - emit SupportedCodecs - */ - - RakiaMediaStream *self = RAKIA_MEDIA_STREAM (iface); - RakiaMediaStreamPrivate *priv; - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - - STREAM_DEBUG (self, - "got codec intersection containing %u codecs from stream-engine", - codecs->len); - - /* Save the local codecs, but avoid triggering a new - * session update at this point. If the stream engine have changed any codec - * parameters, it is supposed to follow up with CodecsUpdated. */ - priv_set_local_codecs (self, codecs); - - if (priv->codec_intersect_pending) - { - if (priv->push_remote_codecs_pending) - { - /* The remote codec list has been updated since the intersection - * has started, plunge into a new intersection immediately */ - priv->push_remote_codecs_pending = FALSE; - push_remote_codecs (self); - } - else - { - priv->codec_intersect_pending = FALSE; - g_signal_emit (self, signals[SIG_SUPPORTED_CODECS], 0, codecs->len); - } - } - else - WARNING("SupportedCodecs called when no intersection is ongoing"); - - tp_svc_media_stream_handler_return_from_supported_codecs (context); -} - -static void -rakia_media_stream_hold_state (TpSvcMediaStreamHandler *self, - gboolean held, - DBusGMethodInvocation *context) -{ - g_object_set (self, "hold-state", held, NULL); - tp_svc_media_stream_handler_return_from_hold_state (context); -} - -static void -rakia_media_stream_unhold_failure (TpSvcMediaStreamHandler *self, - DBusGMethodInvocation *context) -{ - /* Not doing anything to hold_state or requested_hold_state, - * because the session is going to put all streams on hold after getting - * the signal below */ - - g_signal_emit (self, signals[SIG_UNHOLD_FAILURE], 0); - tp_svc_media_stream_handler_return_from_unhold_failure (context); -} - -/*********************************************************************** - * Helper functions follow (not based on generated templates) - ***********************************************************************/ - -guint -rakia_media_stream_get_id (RakiaMediaStream *self) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - return priv->id; -} - -guint -rakia_media_stream_get_media_type (RakiaMediaStream *self) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - return priv->media_type; -} - -void -rakia_media_stream_close (RakiaMediaStream *self) -{ - tp_svc_media_stream_handler_emit_close (self); -} - -/* - * Returns stream direction as requested by the latest local or remote - * direction change. - */ -static TpMediaStreamDirection -priv_get_requested_direction (RakiaMediaStreamPrivate *priv) -{ - TpMediaStreamDirection direction; - - direction = priv->direction; - if ((priv->pending_send_flags & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0) - direction |= TP_MEDIA_STREAM_DIRECTION_SEND; - return direction; -} - -/** - * Converts a sofia-sip media type enum to Telepathy media type. - * See <sofia-sip/sdp.h> and <telepathy-constants.h>. - * - * @return G_MAXUINT if the media type cannot be mapped - */ -guint -rakia_tp_media_type (sdp_media_e sip_mtype) -{ - switch (sip_mtype) - { - case sdp_media_audio: return TP_MEDIA_STREAM_TYPE_AUDIO; - case sdp_media_video: return TP_MEDIA_STREAM_TYPE_VIDEO; - default: return G_MAXUINT; - } -} - - -/** - * Sets the media state to playing or non-playing. When not playing, - * received RTP packets may not be played locally. - */ -void rakia_media_stream_set_playing (RakiaMediaStream *stream, gboolean playing) -{ - RakiaMediaStreamPrivate *priv; - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - if (same_boolean (priv->playing, playing)) - return; - - STREAM_DEBUG (stream, "set playing to %s", playing? "TRUE" : "FALSE"); - - priv->playing = playing; - - if (priv->ready_received) - tp_svc_media_stream_handler_emit_set_stream_playing ( - (TpSvcMediaStreamHandler *)stream, playing); -} - -/** - * Sets the media state to sending or non-sending. When not sending, - * captured media are not sent over the network. - */ -void -rakia_media_stream_set_sending (RakiaMediaStream *stream, gboolean sending) -{ - RakiaMediaStreamPrivate *priv; - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - if (same_boolean(priv->sending, sending)) - return; - - STREAM_DEBUG (stream, "set sending to %s", sending? "TRUE" : "FALSE"); - - priv->sending = sending; - - if (priv->ready_received) - tp_svc_media_stream_handler_emit_set_stream_sending ( - (TpSvcMediaStreamHandler *)stream, sending); -} - -static void -priv_update_sending (RakiaMediaStream *stream, - TpMediaStreamDirection direction) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - gboolean sending = TRUE; - - /* XXX: the pending send flag check is probably an overkill - * considering that effective sending direction and pending send should be - * mutually exclusive */ - if ((direction & TP_MEDIA_STREAM_DIRECTION_SEND) == 0 - || priv->pending_remote_receive - || (priv->pending_send_flags & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0 - || !rakia_media_session_is_accepted (priv->session)) - { - sending = FALSE; - } - - rakia_media_stream_set_sending (stream, sending); -} - -void -rakia_media_stream_set_direction (RakiaMediaStream *stream, - TpMediaStreamDirection direction, - guint pending_send_mask) -{ - RakiaMediaStreamPrivate *priv; - guint pending_send_flags; - TpMediaStreamDirection old_sdp_direction; - - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - pending_send_flags = priv->pending_send_flags & pending_send_mask; - - if ((direction & TP_MEDIA_STREAM_DIRECTION_SEND) == 0) - { - /* We won't be sending, clear the pending local send flag */ - pending_send_flags &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND; - } - else if ((direction & TP_MEDIA_STREAM_DIRECTION_SEND & ~priv->direction) != 0) - { - /* We are requested to start sending, but... */ - if ((pending_send_mask - & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0) - { - /* ... but we need to confirm this with the client. - * Clear the sending bit and set the pending send flag. */ - direction &= ~(guint)TP_MEDIA_STREAM_DIRECTION_SEND; - pending_send_flags |= TP_MEDIA_STREAM_PENDING_LOCAL_SEND; - } - if ((pending_send_mask - & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0 - && (priv->pending_send_flags - & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) == 0) - { - g_assert ((priv_get_requested_direction (priv) & TP_MEDIA_STREAM_DIRECTION_SEND) == 0); - - /* ... but the caller wants to agree with the remote - * end first. Block the stream handler from sending for now. */ - priv->pending_remote_receive = TRUE; - } - } - - if ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE) == 0) - { - /* We are not going to receive, clear the pending remote send flag */ - pending_send_flags &= ~TP_MEDIA_STREAM_PENDING_REMOTE_SEND; - } - else if ((direction & TP_MEDIA_STREAM_DIRECTION_RECEIVE & ~priv->direction) != 0 - && (pending_send_mask - & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0) - { - /* We're requested to start receiving, but the remote end did not - * confirm if it will send. Set the pending send flag. */ - pending_send_flags |= TP_MEDIA_STREAM_PENDING_REMOTE_SEND; - } - - if (priv->direction == direction - && priv->pending_send_flags == pending_send_flags) - return; - - old_sdp_direction = priv_get_requested_direction (priv); - - priv->direction = direction; - priv->pending_send_flags = pending_send_flags; - - STREAM_DEBUG (stream, "set direction %u, pending send flags %u", priv->direction, priv->pending_send_flags); - - g_signal_emit (stream, signals[SIG_DIRECTION_CHANGED], 0, - priv->direction, priv->pending_send_flags); - - priv_update_sending (stream, priv->direction); - - if (priv->native_cands_prepared - && priv->native_codecs_prepared - && priv_get_requested_direction (priv) - != old_sdp_direction) - g_signal_emit (stream, signals[SIG_LOCAL_MEDIA_UPDATED], 0); -} - -/* - * Clears the pending send flag(s) present in @pending_send_mask. - * If #TP_MEDIA_STREAM_PENDING_LOCAL_SEND is thus cleared, - * enable the sending bit in the stream direction. - * If @pending_send_mask has #TP_MEDIA_STREAM_PENDING_REMOTE_SEND flag set, - * also start sending if agreed by the stream direction. - */ -void -rakia_media_stream_apply_pending_direction (RakiaMediaStream *stream, - guint pending_send_mask) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - guint flags; - - - /* Don't apply pending send for new streams that haven't been negotiated */ - //if (priv->remote_media == NULL) - // return; - - /* Remember the flags that got changes and then clear the set */ - flags = (priv->pending_send_flags & pending_send_mask); - priv->pending_send_flags &= ~pending_send_mask; - - if (flags != 0) - { - if ((flags & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0) - priv->direction |= TP_MEDIA_STREAM_DIRECTION_SEND; - - STREAM_DEBUG (stream, "set direction %u, pending send flags %u", priv->direction, priv->pending_send_flags); - - g_signal_emit (stream, signals[SIG_DIRECTION_CHANGED], 0, - priv->direction, priv->pending_send_flags); - } - - if ((pending_send_mask & TP_MEDIA_STREAM_PENDING_REMOTE_SEND) != 0) - { - priv->pending_remote_receive = FALSE; - STREAM_DEBUG (stream, "remote end ready to receive"); - } - - /* Always check to enable sending because the session could become accepted */ - priv_update_sending (stream, priv->direction); -} - -TpMediaStreamDirection -rakia_media_stream_get_requested_direction (RakiaMediaStream *self) -{ - return priv_get_requested_direction (RAKIA_MEDIA_STREAM_GET_PRIVATE (self)); -} - -/** - * Returns true if the stream has a valid SDP description and - * connection has been established with the stream engine. - */ -gboolean rakia_media_stream_is_local_ready (RakiaMediaStream *self) -{ - RakiaMediaStreamPrivate *priv = self->priv; - return (priv->ready_received && priv->native_cands_prepared - && priv->native_codecs_prepared); -} - -gboolean -rakia_media_stream_is_codec_intersect_pending (RakiaMediaStream *self) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - return priv->codec_intersect_pending; -} - -void -rakia_media_stream_start_telephony_event (RakiaMediaStream *self, guchar event) -{ - tp_svc_media_stream_handler_emit_start_telephony_event ( - (TpSvcMediaStreamHandler *)self, event); -} - -void -rakia_media_stream_stop_telephony_event (RakiaMediaStream *self) -{ - tp_svc_media_stream_handler_emit_stop_telephony_event ( - (TpSvcMediaStreamHandler *)self); -} - -gboolean -rakia_media_stream_request_hold_state (RakiaMediaStream *self, gboolean hold) -{ - RakiaMediaStreamPrivate *priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (self); - - if ((!priv->requested_hold_state) != (!hold)) - { - priv->requested_hold_state = hold; - tp_svc_media_stream_handler_emit_set_stream_held (self, hold); - return TRUE; - } - return FALSE; -} - -static void -priv_emit_local_ready (RakiaMediaStream *self) -{ - /* Trigger any session updates that are due in the current session state */ - g_signal_emit (self, signals[SIG_LOCAL_MEDIA_UPDATED], 0); - g_signal_emit (self, signals[SIG_READY], 0); -} - -/** - * Notify StreamEngine of remote codecs. - * - * @pre Ready signal must be receiveid (priv->ready_received) - */ -static void push_remote_codecs (RakiaMediaStream *stream) -{ - RakiaMediaStreamPrivate *priv; - GPtrArray *codecs; - GType codecs_type; - GType codec_type; - GPtrArray *sipcodecs; - guint i, j; - - DEBUG ("enter"); - - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - sipcodecs = rakia_sip_media_get_remote_codecs (priv->media); - if (sipcodecs == NULL) - { - STREAM_DEBUG (stream, "remote media description is not received yet"); - return; - } - - if (!priv->ready_received) - { - STREAM_DEBUG (stream, "the stream engine is not ready, SetRemoteCodecs is pending"); - priv->push_remote_codecs_pending = TRUE; - return; - } - - codec_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC; - codecs_type = TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CODEC_LIST; - - codecs = dbus_g_type_specialized_construct (codecs_type); - - for (i = 0; i < sipcodecs->len; i++) - { - GValue codec = { 0, }; - GHashTable *opt_params; - RakiaSipCodec *sipcodec = g_ptr_array_index (sipcodecs, i); - - g_value_init (&codec, codec_type); - g_value_take_boxed (&codec, - dbus_g_type_specialized_construct (codec_type)); - - opt_params = g_hash_table_new (g_str_hash, g_str_equal); - if (sipcodec->params) - { - for (j = 0; j < sipcodec->params->len; j++) - { - RakiaSipCodecParam *param = - g_ptr_array_index (sipcodec->params, j); - - g_hash_table_insert (opt_params, param->name, param->value); - } - } - - dbus_g_type_struct_set (&codec, - /* payload type: */ - 0, sipcodec->id, - /* encoding name: */ - 1, sipcodec->encoding_name, - /* media type */ - 2, (guint)priv->media_type, - /* clock-rate */ - 3, sipcodec->clock_rate, - /* number of supported channels: */ - 4, sipcodec->channels, - /* optional params: */ - 5, opt_params, - G_MAXUINT); - - g_hash_table_unref (opt_params); - - g_ptr_array_add (codecs, g_value_get_boxed (&codec)); - } - - - STREAM_DEBUG(stream, "emitting %d remote codecs to the handler", - codecs->len); - - tp_svc_media_stream_handler_emit_set_remote_codecs ( - (TpSvcMediaStreamHandler *)stream, codecs); - - g_boxed_free (codecs_type, codecs); -} - -static void push_remote_candidates (RakiaMediaStream *stream) -{ - RakiaMediaStreamPrivate *priv; - GValue candidate = { 0 }; - GValue transport = { 0 }; - GValue transport_rtcp = { 0 }; - GPtrArray *candidates; - GPtrArray *transports; - GType candidate_type; - GType candidates_type; - GType transport_type; - GType transports_type; - gchar *candidate_id; - GPtrArray *remote_candidates; - RakiaSipCandidate *rtp_cand = NULL; - RakiaSipCandidate *rtcp_cand = NULL; - guint i; - - DEBUG("enter"); - - priv = RAKIA_MEDIA_STREAM_GET_PRIVATE (stream); - - remote_candidates = rakia_sip_media_get_remote_candidates (priv->media); - - if (remote_candidates == NULL) - { - STREAM_DEBUG (stream, "remote media description is not received yet"); - return; - } - - if (!priv->ready_received) - { - STREAM_DEBUG (stream, "the stream engine is not ready, SetRemoteCandidateList is pending"); - priv->push_remote_cands_pending = TRUE; - return; - } - - for (i = 0; i < remote_candidates->len; i++) - { - RakiaSipCandidate *tmpc = g_ptr_array_index (remote_candidates, i); - - if (tmpc->component == 1) - { - rtp_cand = tmpc; - } - else if (tmpc->component == 2) - { - rtcp_cand = tmpc; - } - } - - if (rtp_cand == NULL) - { - STREAM_DEBUG (stream, "no rtp candidate"); - priv->push_remote_cands_pending = TRUE; - return; - } - - transports_type = TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT_LIST; - transports = dbus_g_type_specialized_construct (transports_type); - - transport_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT; - g_value_init (&transport, transport_type); - g_value_take_boxed (&transport, - dbus_g_type_specialized_construct (transport_type)); - dbus_g_type_struct_set (&transport, - 0, 1, /* component number */ - 1, rtp_cand->ip, - 2, rtp_cand->port, - 3, TP_MEDIA_STREAM_BASE_PROTO_UDP, - 4, "RTP", - 5, "AVP", - /* 6, 0.0f, */ - 7, TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL, - /* 8, "", */ - /* 9, "", */ - G_MAXUINT); - - STREAM_DEBUG (stream, "remote RTP address=<%s>, port=<%u>", rtp_cand->ip, - rtp_cand->port); - g_ptr_array_add (transports, g_value_get_boxed (&transport)); - - if (rtcp_cand) - { - g_value_init (&transport_rtcp, transport_type); - g_value_take_boxed (&transport_rtcp, - dbus_g_type_specialized_construct (transport_type)); - dbus_g_type_struct_set (&transport_rtcp, - 0, 2, /* component number */ - 1, rtcp_cand->ip, - 2, rtcp_cand->port, - 3, TP_MEDIA_STREAM_BASE_PROTO_UDP, - 4, "RTP", - 5, "AVP", - /* 6, 0.0f, */ - 7, TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL, - /* 8, "", */ - /* 9, "", */ - G_MAXUINT); - - STREAM_DEBUG (stream, "remote RTCP address=<%s>, port=<%u>", - rtcp_cand->ip, rtcp_cand->port); - g_ptr_array_add (transports, g_value_get_boxed (&transport_rtcp)); - } - - g_free (priv->remote_candidate_id); - candidate_id = g_strdup_printf ("L%u", ++priv->remote_candidate_counter); - priv->remote_candidate_id = candidate_id; - - candidate_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE; - g_value_init (&candidate, candidate_type); - g_value_take_boxed (&candidate, - dbus_g_type_specialized_construct (candidate_type)); - dbus_g_type_struct_set (&candidate, - 0, candidate_id, - 1, transports, - G_MAXUINT); - - candidates_type = TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE_LIST; - candidates = dbus_g_type_specialized_construct (candidates_type); - g_ptr_array_add (candidates, g_value_get_boxed (&candidate)); - - STREAM_DEBUG (stream, "emitting SetRemoteCandidateList with %s", candidate_id); - - tp_svc_media_stream_handler_emit_set_remote_candidate_list ( - (TpSvcMediaStreamHandler *)stream, candidates); - - g_boxed_free (candidates_type, candidates); - g_boxed_free (transports_type, transports); -} - - -static void -stream_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaStreamHandlerClass *klass = (TpSvcMediaStreamHandlerClass *)g_iface; - -#define IMPLEMENT(x) tp_svc_media_stream_handler_implement_##x (\ - klass, (tp_svc_media_stream_handler_##x##_impl) rakia_media_stream_##x) - IMPLEMENT(error); - IMPLEMENT(native_candidates_prepared); - IMPLEMENT(new_active_candidate_pair); - IMPLEMENT(new_native_candidate); - IMPLEMENT(ready); - IMPLEMENT(set_local_codecs); - IMPLEMENT(codecs_updated); - IMPLEMENT(stream_state); - IMPLEMENT(supported_codecs); - IMPLEMENT(hold_state); - IMPLEMENT(unhold_failure); -#undef IMPLEMENT -} - -RakiaSipMedia * -rakia_media_stream_get_media (RakiaMediaStream *stream) -{ - RakiaMediaStreamPrivate *priv = stream->priv; - - return priv->media; -} diff --git a/rakia/media-stream.h b/rakia/media-stream.h deleted file mode 100644 index 1785d39..0000000 --- a/rakia/media-stream.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * sip-media-stream.h - Header for RakiaMediaStream - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005-2010 Nokia Corporation - * - * This work 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 work 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 work; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __RAKIA_MEDIA_STREAM_H__ -#define __RAKIA_MEDIA_STREAM_H__ - -#include <glib-object.h> -#include <telepathy-glib/dbus-properties-mixin.h> -#include <telepathy-glib/enums.h> -#include <sofia-sip/sdp.h> - -#include "rakia/sip-media.h" - -G_BEGIN_DECLS - -typedef struct _RakiaMediaStream RakiaMediaStream; -typedef struct _RakiaMediaStreamClass RakiaMediaStreamClass; -typedef struct _RakiaMediaStreamPrivate RakiaMediaStreamPrivate; - -struct _RakiaMediaStreamClass { - GObjectClass parent_class; - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _RakiaMediaStream { - GObject parent; - RakiaMediaStreamPrivate *priv; -}; - -GType rakia_media_stream_get_type(void); - -/* TYPE MACROS */ -#define RAKIA_TYPE_MEDIA_STREAM \ - (rakia_media_stream_get_type()) -#define RAKIA_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), RAKIA_TYPE_MEDIA_STREAM, RakiaMediaStream)) -#define RAKIA_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), RAKIA_TYPE_MEDIA_STREAM, RakiaMediaStreamClass)) -#define RAKIA_IS_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), RAKIA_TYPE_MEDIA_STREAM)) -#define RAKIA_IS_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), RAKIA_TYPE_MEDIA_STREAM)) -#define RAKIA_MEDIA_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), RAKIA_TYPE_MEDIA_STREAM, RakiaMediaStreamClass)) - -/*********************************************************************** - * Additional declarations (not based on generated templates) - ***********************************************************************/ - -void rakia_media_stream_close (RakiaMediaStream *self); -guint rakia_media_stream_get_id (RakiaMediaStream *self); -guint rakia_media_stream_get_media_type (RakiaMediaStream *self); - -void rakia_media_stream_set_playing (RakiaMediaStream *self, gboolean playing); -void rakia_media_stream_set_sending (RakiaMediaStream *self, gboolean sending); -void rakia_media_stream_set_direction (RakiaMediaStream *stream, - TpMediaStreamDirection direction, - guint pending_send_mask); -void rakia_media_stream_apply_pending_direction (RakiaMediaStream *stream, - guint pending_send_mask); -TpMediaStreamDirection rakia_media_stream_get_requested_direction (RakiaMediaStream *self); -gboolean rakia_media_stream_is_local_ready (RakiaMediaStream *self); -gboolean rakia_media_stream_is_codec_intersect_pending (RakiaMediaStream *self); -void rakia_media_stream_start_telephony_event (RakiaMediaStream *self, guchar event); -void rakia_media_stream_stop_telephony_event (RakiaMediaStream *self); -gboolean rakia_media_stream_request_hold_state (RakiaMediaStream *self, - gboolean hold); - -guint rakia_tp_media_type (sdp_media_e sip_mtype); - - -RakiaSipMedia *rakia_media_stream_get_media (RakiaMediaStream *stream); - -G_END_DECLS - -#endif /* #ifndef __RAKIA_MEDIA_STREAM_H__*/ |