[Telepathy-commits] [telepathy-gabble/master] Actually commited half of the content-* related changes, thanks git
Senko Rasic
senko at phyrexia.lan
Tue Dec 2 04:34:00 PST 2008
---
src/jingle-content.c | 77 +++++++--
src/jingle-content.h | 2 +
src/jingle-session.c | 439 +++++++++++++++++++++++++-------------------------
src/jingle-session.h | 10 +-
4 files changed, 290 insertions(+), 238 deletions(-)
diff --git a/src/jingle-content.c b/src/jingle-content.c
index 3cf9154..4b0fce0 100644
--- a/src/jingle-content.c
+++ b/src/jingle-content.c
@@ -70,7 +70,7 @@ struct _GabbleJingleContentPrivate
gboolean created_by_us;
JingleContentState state;
JingleContentSenders senders;
- gboolean ready;
+ // gboolean ready;
gchar *content_ns;
gchar *transport_ns;
@@ -178,11 +178,14 @@ gabble_jingle_content_get_property (GObject *object,
break;
case PROP_READY:
g_assert_not_reached ();
- g_value_set_boolean (value, priv->ready);
+ // g_value_set_boolean (value, priv->ready);
break;
case PROP_CONTENT_NS:
g_value_set_string (value, priv->content_ns);
break;
+ case PROP_TRANSPORT_NS:
+ g_value_set_string (value, priv->transport_ns);
+ break;
case PROP_DISPOSITION:
g_value_set_string (value, priv->disposition);
break;
@@ -227,6 +230,8 @@ gabble_jingle_content_set_property (GObject *object,
g_assert (transport_type != 0);
+ DEBUG ("using transport: %s", priv->transport_ns);
+
priv->transport = g_object_new (transport_type,
"content", self, "transport-ns", priv->transport_ns, NULL);
@@ -249,6 +254,7 @@ gabble_jingle_content_set_property (GObject *object,
break;
case PROP_READY:
g_assert_not_reached ();
+#if 0
DEBUG ("setting content ready from %u to %u",
priv->ready, g_value_get_boolean (value));
@@ -259,7 +265,7 @@ gabble_jingle_content_set_property (GObject *object,
}
priv->ready = g_value_get_boolean (value);
-
+#endif
break;
case PROP_DISPOSITION:
g_assert (priv->disposition == NULL);
@@ -323,7 +329,6 @@ gabble_jingle_content_class_init (GabbleJingleContentClass *cls)
param_spec = g_param_spec_string ("transport-ns", "Transport namespace",
"Namespace identifying the transport type.",
NULL,
- G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB);
@@ -347,6 +352,9 @@ gabble_jingle_content_class_init (GabbleJingleContentClass *cls)
G_PARAM_STATIC_BLURB);
g_object_class_install_property (object_class, PROP_STATE, param_spec);
+/* Note: we now have media_ready and transport_ready internal flags for this
+ */
+#if 0
param_spec = g_param_spec_boolean ("ready", "Ready?",
"A boolean signifying whether media for "
"this content is ready to be signalled.",
@@ -355,6 +363,7 @@ gabble_jingle_content_class_init (GabbleJingleContentClass *cls)
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_BLURB);
g_object_class_install_property (object_class, PROP_READY, param_spec);
+#endif
param_spec = g_param_spec_string ("disposition", "Content disposition",
"Distinguishes between 'session' and other "
@@ -424,8 +433,7 @@ send_gtalk4_transport_accept (gpointer user_data)
tnode = lm_message_node_add_child (sess_node, "transport", NULL);
lm_message_node_set_attribute (tnode, "xmlns", priv->transport_ns);
- _gabble_connection_send (c->conn, msg, NULL);
- lm_message_unref (msg);
+ gabble_jingle_session_send (c->session, msg, NULL);
return FALSE;
}
@@ -606,7 +614,6 @@ gabble_jingle_content_parse_accept (GabbleJingleContent *c,
if (*error)
return;
- // FIXME: this overlaps with _update_senders, maybe merge?
g_object_notify ((GObject *) c, "senders");
// If all went well, it means the content is finally ackd
@@ -747,8 +754,7 @@ send_content_add_or_accept (GabbleJingleContent *self)
msg = gabble_jingle_session_new_message (self->session,
action, &sess_node);
gabble_jingle_content_produce_node (self, sess_node, TRUE);
- _gabble_connection_send (self->conn, msg, NULL);
- lm_message_unref (msg);
+ gabble_jingle_session_send (self->session, msg, NULL);
priv->state = new_state;
g_object_notify (G_OBJECT (self), "state");
@@ -758,25 +764,33 @@ static void
_maybe_ready (GabbleJingleContent *self)
{
GabbleJingleContentPrivate *priv = GABBLE_JINGLE_CONTENT_GET_PRIVATE (self);
+ JingleSessionState state;
if (!gabble_jingle_content_is_ready (self))
return;
DEBUG ("called, and is ready");
- if (!tp_strdiff (priv->disposition, "session"))
+ /* If content disposition is session and session
+ * is not yet acknowledged/active, we signall
+ * the readiness to the session and let it take
+ * care of it. Otherwise, we can deal with it
+ * ourselves. */
+
+ g_object_get (self->session, "state", &state, NULL);
+
+ DEBUG ("session state == %d", state);
+
+ if (!tp_strdiff (priv->disposition, "session") &&
+ (state < JS_STATE_PENDING_ACCEPT_SENT))
{
- DEBUG ("disposition == 'session' signalling");
+ DEBUG ("disposition == 'session' and session not active, signalling");
/* Notify the session that we're ready for
* session-initiate/session-accept */
g_signal_emit (self, signals[READY], 0);
}
else
{
- JingleSessionState state;
-
- g_object_get (self->session, "state", &state, NULL);
-
if (state >= JS_STATE_PENDING_INITIATE_SENT)
{
DEBUG ("disposition != 'session', sending add/accept");
@@ -785,7 +799,8 @@ _maybe_ready (GabbleJingleContent *self)
{
/* non session-disposition content ready without session
* being initiated at all? */
- g_assert_not_reached ();
+ DEBUG ("session not initiated yet, ignoring non-session ready content");
+ return;
}
}
@@ -834,8 +849,7 @@ gabble_jingle_content_accept (GabbleJingleContent *c)
JINGLE_ACTION_CONTENT_ACCEPT, &sess_node);
gabble_jingle_content_produce_node (c, sess_node, TRUE);
- _gabble_connection_send (c->conn, msg, NULL);
- lm_message_unref (msg);
+ gabble_jingle_session_send (c->session, msg, NULL);
g_object_set (c, "state", JINGLE_CONTENT_STATE_ACKNOWLEDGED, NULL);
}
@@ -848,4 +862,31 @@ gabble_jingle_content_get_remote_candidates (GabbleJingleContent *c)
return gabble_jingle_transport_iface_get_remote_candidates (priv->transport);
}
+gboolean
+gabble_jingle_content_change_direction (GabbleJingleContent *c,
+ JingleContentSenders senders)
+{
+ GabbleJingleContentPrivate *priv = GABBLE_JINGLE_CONTENT_GET_PRIVATE (c);
+ LmMessage *msg;
+ LmMessageNode *sess_node;
+ JingleDialect dialect;
+
+ g_object_get (c->session, "dialect", &dialect, NULL);
+
+ if (dialect <= JINGLE_DIALECT_GTALK4)
+ {
+ DEBUG ("ignoring direction change request for GTalk stream");
+ return FALSE;
+ }
+
+ priv->senders = senders;
+
+ msg = gabble_jingle_session_new_message (c->session,
+ JINGLE_ACTION_CONTENT_MODIFY, &sess_node);
+ gabble_jingle_content_produce_node (c, sess_node, FALSE);
+ gabble_jingle_session_send (c->session, msg, NULL);
+
+ /* FIXME: actually check whether remote end accepts our content-modify */
+ return TRUE;
+}
diff --git a/src/jingle-content.h b/src/jingle-content.h
index 436eaba..f4b7cbc 100644
--- a/src/jingle-content.h
+++ b/src/jingle-content.h
@@ -110,6 +110,8 @@ void gabble_jingle_content_set_transport_state (GabbleJingleContent *content,
JingleTransportState state);
void gabble_jingle_content_accept (GabbleJingleContent *c);
GList *gabble_jingle_content_get_remote_candidates (GabbleJingleContent *c);
+gboolean gabble_jingle_content_change_direction (GabbleJingleContent *c,
+ JingleContentSenders senders);
#endif /* __JINGLE_CONTENT_H__ */
diff --git a/src/jingle-session.c b/src/jingle-session.c
index 809e8e9..7c629a9 100644
--- a/src/jingle-session.c
+++ b/src/jingle-session.c
@@ -74,16 +74,14 @@ struct _GabbleJingleSessionPrivate
* Table owns references to these objects. */
GHashTable *contents;
- /* Table of initial content objects keyed by name.
- * Any object in this table has to appear in contents
- * also. This table just borrows the references. */
- GHashTable *initial_contents;
JingleDialect dialect;
JingleState state;
gchar *sid;
gboolean locally_accepted;
+ guint timer_id;
+
gboolean dispose_has_run;
};
@@ -98,6 +96,7 @@ static const gchar *action_table[] = {
"content-modify",
"content-remove",
"content-replace",
+ "content-reject",
"session-accept",
"session-info",
"session-initiate",
@@ -107,12 +106,14 @@ static const gchar *action_table[] = {
NULL
};
+#define DEFAULT_SESSION_TIMEOUT 6000
+
typedef struct {
JingleState state;
JingleAction *actions;
} JingleStateActions;
-static JingleAction allowed_actions[6][8] = {
+static JingleAction allowed_actions[6][10] = {
/* JS_STATE_PENDING_CREATED */
{ JINGLE_ACTION_SESSION_INITIATE, JINGLE_ACTION_UNKNOWN },
/* JS_STATE_PENDING_INITIATE_SENT */
@@ -121,7 +122,7 @@ static JingleAction allowed_actions[6][8] = {
JINGLE_ACTION_TRANSPORT_INFO, JINGLE_ACTION_UNKNOWN },
/* JS_STATE_PENDING_INITIATED */
{ JINGLE_ACTION_SESSION_ACCEPT, JINGLE_ACTION_SESSION_TERMINATE,
- JINGLE_ACTION_TRANSPORT_INFO,
+ JINGLE_ACTION_TRANSPORT_INFO, JINGLE_ACTION_CONTENT_REJECT,
JINGLE_ACTION_CONTENT_MODIFY, JINGLE_ACTION_CONTENT_ACCEPT,
JINGLE_ACTION_CONTENT_REMOVE, JINGLE_ACTION_UNKNOWN },
/* JS_STATE_PENDING_ACCEPT_SENT */
@@ -129,6 +130,7 @@ static JingleAction allowed_actions[6][8] = {
/* JS_STATE_ACTIVE */
{ JINGLE_ACTION_CONTENT_MODIFY, JINGLE_ACTION_CONTENT_ADD,
JINGLE_ACTION_CONTENT_REMOVE, JINGLE_ACTION_CONTENT_REPLACE,
+ JINGLE_ACTION_CONTENT_ACCEPT, JINGLE_ACTION_CONTENT_REJECT,
JINGLE_ACTION_SESSION_INFO, JINGLE_ACTION_TRANSPORT_INFO,
JINGLE_ACTION_SESSION_TERMINATE, JINGLE_ACTION_UNKNOWN },
/* JS_STATE_ENDED */
@@ -145,11 +147,10 @@ gabble_jingle_session_init (GabbleJingleSession *obj)
priv->contents = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
- priv->initial_contents = g_hash_table_new_full (g_str_hash,
- g_str_equal, g_free, NULL);
priv->state = JS_STATE_PENDING_CREATED;
priv->locally_accepted = FALSE;
+ priv->timer_id = 0;
priv->dispose_has_run = FALSE;
}
@@ -167,8 +168,9 @@ gabble_jingle_session_dispose (GObject *object)
DEBUG ("dispose called");
priv->dispose_has_run = TRUE;
- g_hash_table_destroy (priv->initial_contents);
- priv->initial_contents = NULL;
+ g_assert ((priv->state == JS_STATE_PENDING_CREATED) ||
+ (priv->state == JS_STATE_ENDED));
+ g_assert (priv->timer_id == 0);
g_hash_table_destroy (priv->contents);
priv->contents = NULL;
@@ -641,15 +643,6 @@ _each_content_accept (GabbleJingleSession *sess, GabbleJingleContent *c,
}
static void
-_mark_each_initial_content (gpointer key, gpointer data, gpointer user_data)
-{
- GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data);
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
-
- g_hash_table_insert (priv->initial_contents, key, data);
-}
-
-static void
on_session_initiate (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
@@ -676,11 +669,9 @@ on_session_initiate (GabbleJingleSession *sess, LmMessageNode *node,
if (*error == NULL)
{
- DEBUG ("marking all newly defined contents as initial contents");
-
- /* mark all newly defined contents as initial contents */
- g_hash_table_foreach (priv->contents,
- _mark_each_initial_content, sess);
+ /* FIXME: contents defined here should always have "session" content
+ * disposition; resolve this as soon as the proper procedure is defined
+ * in XEP-0166. */
set_state (sess, JS_STATE_PENDING_INITIATED);
}
@@ -704,7 +695,14 @@ static void
on_content_remove (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
+ GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
+
_foreach_content (sess, node, _each_content_remove, error);
+
+ if (g_hash_table_size (priv->contents) == 0)
+ {
+ gabble_jingle_session_terminate (sess);
+ }
}
static void
@@ -715,11 +713,20 @@ on_content_replace (GabbleJingleSession *sess, LmMessageNode *node,
}
static void
+on_content_reject (GabbleJingleSession *sess, LmMessageNode *node,
+ GError **error)
+{
+ /* FIXME: reject is different from remove - remove is for
+ * acknowledged contents, reject is for pending; but the result
+ * is the same. */
+ _foreach_content (sess, node, _each_content_remove, error);
+}
+
+static void
on_content_accept (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- // FIXME
- // _foreach_content (sess, node, _each_content_replace, error);
+ _foreach_content (sess, node, _each_content_accept, error);
}
static void
@@ -754,7 +761,6 @@ on_session_terminate (GabbleJingleSession *sess, LmMessageNode *node,
{
DEBUG ("remote end terminates the session");
set_state (sess, JS_STATE_ENDED);
- g_signal_emit (sess, signals[TERMINATED], 0, FALSE);
}
static void
@@ -819,6 +825,7 @@ static HandlerFunc handlers[] = {
on_content_modify,
on_content_remove,
on_content_replace,
+ on_content_reject,
on_session_accept, /* jingle_on_session_accept */
NULL, /* jingle_on_session_info */
on_session_initiate,
@@ -1065,25 +1072,25 @@ gabble_jingle_session_new_message (GabbleJingleSession *sess,
iq_node = lm_message_get_node (msg);
- switch (priv->dialect) {
- case JINGLE_DIALECT_V026:
- el = "jingle";
- ns = NS_JINGLE026;
- break;
- case JINGLE_DIALECT_V015:
- el = "jingle";
- ns = NS_JINGLE015;
- break;
- case JINGLE_DIALECT_GTALK3:
- case JINGLE_DIALECT_GTALK4:
- el = "session";
- ns = NS_GOOGLE_SESSION;
- gtalk_mode = TRUE;
- break;
- case JINGLE_DIALECT_ERROR:
- g_assert_not_reached ();
-
- }
+ switch (priv->dialect)
+ {
+ case JINGLE_DIALECT_V015:
+ el = "jingle";
+ ns = NS_JINGLE015;
+ break;
+ case JINGLE_DIALECT_GTALK3:
+ case JINGLE_DIALECT_GTALK4:
+ el = "session";
+ ns = NS_GOOGLE_SESSION;
+ gtalk_mode = TRUE;
+ break;
+ case JINGLE_DIALECT_ERROR:
+ g_assert_not_reached ();
+ default:
+ el = "jingle";
+ ns = NS_JINGLE026;
+ break;
+ }
session_node = lm_message_node_add_child (iq_node, el, NULL);
lm_message_node_set_attributes (session_node,
@@ -1094,42 +1101,52 @@ gabble_jingle_session_new_message (GabbleJingleSession *sess,
produce_action (action, priv->dialect),
NULL);
- *sess_node = session_node;
+ if (sess_node != NULL)
+ *sess_node = session_node;
return msg;
}
+typedef void (*ContentMapperFunc) (GabbleJingleSession *sess,
+ GabbleJingleContent *c, gpointer user_data);
+
static void
-_check_content_for_acceptance (gpointer key, gpointer data, gpointer user_data)
+_map_initial_contents (GabbleJingleSession *sess, ContentMapperFunc mapper,
+ gpointer user_data)
{
- GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (data);
- gboolean *is_ready = (gboolean *) user_data;
+ GList *li;
+ GList *contents = gabble_jingle_session_get_contents (sess);
+
+ for (li = contents; li; li = li->next)
+ {
+ const gchar *disposition;
+ GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (li->data);
- /* TODO: content knows whether we are the creator (different
- * rules for readiness for initiate/accept) */
- *is_ready = gabble_jingle_content_is_ready (c);
+ g_object_get (c, "disposition", &disposition, NULL);
+
+ if (!tp_strdiff (disposition, "session"))
+ {
+ mapper (sess, c, user_data);
+ }
+ }
+
+ g_list_free (contents);
}
static void
-_check_content_for_initiation (gpointer key, gpointer data, gpointer user_data)
+_check_content_ready (GabbleJingleSession *sess,
+ GabbleJingleContent *c, gpointer user_data)
{
- GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (data);
- gboolean *is_ready = (gboolean *) user_data;
-
- *is_ready = gabble_jingle_content_is_ready (c);
- DEBUG ("content %p reported readiness: %u", c, *is_ready);
-
+ * ((gboolean *) user_data) = gabble_jingle_content_is_ready (c);
}
static void
-_try_session_accept_fill (gpointer key, gpointer data, gpointer user_data)
+_fill_content (GabbleJingleSession *sess,
+ GabbleJingleContent *c, gpointer user_data)
{
- GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (data);
LmMessageNode *sess_node = user_data;
JingleContentState state;
- /* We can safely add every content, because we're only
- * considering the initial ones anyways. */
gabble_jingle_content_produce_node (c, sess_node, TRUE);
g_object_get (c, "state", &state, NULL);
@@ -1145,90 +1162,135 @@ _try_session_accept_fill (gpointer key, gpointer data, gpointer user_data)
else
{
DEBUG ("weird, content %p is in stata %u", c, state);
+ g_assert_not_reached ();
}
}
-static void
-try_session_accept (GabbleJingleSession *sess)
+static LmHandlerResult
+_process_reply (GabbleConnection *conn,
+ LmMessage *sent, LmMessage *reply, GObject *obj, gpointer user_data)
{
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
- LmMessage *msg;
- LmMessageNode *sess_node;
- gboolean content_ready = TRUE;
+ GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (obj);
+ JingleReplyHandler handler = user_data;
- g_assert (g_hash_table_size (priv->initial_contents) > 0);
+ if (lm_message_get_sub_type (reply) == LM_MESSAGE_SUB_TYPE_RESULT)
+ {
+ handler (sess, TRUE, reply);
+ }
+ else
+ {
+ handler (sess, FALSE, reply);
+ }
+
+ return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
- if (priv->state != JS_STATE_PENDING_INITIATED)
+void
+gabble_jingle_session_send (GabbleJingleSession *sess, LmMessage *msg,
+ JingleReplyHandler cb)
+{
+ GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
+
+ if (cb != NULL)
{
- DEBUG ("session is in state %u, won't try to accept", priv->state);
- return;
+ DEBUG ("sending with reply %p", cb);
+ _gabble_connection_send_with_reply (priv->conn, msg,
+ _process_reply, G_OBJECT (sess), cb, NULL);
+ }
+ else
+ {
+ _gabble_connection_send (priv->conn, msg, NULL);
}
- if (!priv->locally_accepted)
- return;
+ lm_message_unref (msg);
+}
- g_hash_table_foreach (priv->initial_contents, _check_content_for_acceptance, &content_ready);
+static void
+_on_initiate_reply (GabbleJingleSession *sess, gboolean success,
+ LmMessage *reply)
+{
+ if (success)
+ set_state (sess, JS_STATE_PENDING_INITIATED);
+ else
+ set_state (sess, JS_STATE_ENDED);
+}
- if (!content_ready)
- return;
+static void
+_on_accept_reply (GabbleJingleSession *sess, gboolean success,
+ LmMessage *reply)
+{
+ /* FIXME: clear session timeout timer here */
- msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_SESSION_ACCEPT,
- &sess_node);
+ if (success)
+ set_state (sess, JS_STATE_ACTIVE);
+ else
+ set_state (sess, JS_STATE_ENDED);
+}
- g_hash_table_foreach (priv->initial_contents, _try_session_accept_fill, sess_node);
+static gboolean
+timeout_session (gpointer data)
+{
+ GabbleJingleSession *session = data;
- _gabble_connection_send (priv->conn, msg, NULL);
+ DEBUG ("session timed out");
- lm_message_unref (msg);
+ /* FIXME: distinguish between different cases; we somehow need to
+ * signal this to media channel - parameter to TERMINATED perhaps?*/
- set_state (sess, JS_STATE_ACTIVE);
+ gabble_jingle_session_terminate (session);
+ return FALSE;
}
static void
-try_session_initiate (GabbleJingleSession *sess)
+try_session_initiate_or_accept (GabbleJingleSession *sess)
{
GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
LmMessage *msg;
LmMessageNode *sess_node;
- gboolean content_ready = TRUE;
+ gboolean contents_ready = TRUE;
+ JingleAction action;
+ JingleSessionState new_state;
+ JingleReplyHandler handler;
+ /* If there are no contents yet, we shouldn't have been called at all. */
g_assert (g_hash_table_size (priv->contents) > 0);
- if (priv->state != JS_STATE_PENDING_CREATED)
+ if (priv->local_initiator)
{
- DEBUG ("session is in state %u, won't try to initiate", priv->state);
- return;
- }
-
- g_hash_table_foreach (priv->contents, _check_content_for_initiation, &content_ready);
-
- if (!content_ready)
- return;
-
- msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_SESSION_INITIATE,
- &sess_node);
-
- g_hash_table_foreach (priv->contents, _try_session_accept_fill, sess_node);
+ if (priv->state != JS_STATE_PENDING_CREATED)
+ {
+ DEBUG ("session is in state %u, won't try to initiate", priv->state);
+ return;
+ }
- _gabble_connection_send (priv->conn, msg, NULL);
+ action = JINGLE_ACTION_SESSION_INITIATE;
+ new_state = JS_STATE_PENDING_INITIATE_SENT;
+ handler = _on_initiate_reply;
- lm_message_unref (msg);
+ /* FIXME: set session timeout timer here */
+ }
+ else
+ {
+ if (priv->state != JS_STATE_PENDING_INITIATED)
+ {
+ DEBUG ("session is in state %u, won't try to accept", priv->state);
+ return;
+ }
- set_state (sess, JS_STATE_PENDING_INITIATE_SENT);
-}
+ action = JINGLE_ACTION_SESSION_ACCEPT;
+ new_state = JS_STATE_PENDING_ACCEPT_SENT;
+ handler = _on_accept_reply;
+ }
-static void
-content_accept (GabbleJingleSession *sess, GabbleJingleContent *c)
-{
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
+ _map_initial_contents (sess, _check_content_ready, &contents_ready);
- if (priv->state < JS_STATE_PENDING_INITIATE_SENT)
- {
- DEBUG ("session is in state %u, won't try to accept content", priv->state);
+ if (!contents_ready)
return;
- }
- gabble_jingle_content_accept (c);
+ msg = gabble_jingle_session_new_message (sess, action, &sess_node);
+ _map_initial_contents (sess, _fill_content, sess_node);
+ gabble_jingle_session_send (sess, msg, handler);
+ set_state (sess, new_state);
}
static void
@@ -1236,9 +1298,28 @@ set_state (GabbleJingleSession *sess, JingleState state)
{
GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
+ DEBUG ("Setting state of JingleSession: %p (priv = %p) from %u to %u", sess, priv, priv->state, state);
+
priv->state = state;
- DEBUG ("Setting state of JingleSession: %p (priv = %p), state = %u", sess, priv, priv->state);
g_object_notify (G_OBJECT (sess), "state");
+
+ /* if we or peer just initiated the session, set the session timer */
+ if ((priv->local_initiator && (state == JS_STATE_PENDING_INITIATE_SENT)) ||
+ (!priv->local_initiator && (state == JS_STATE_PENDING_INITIATED)))
+ {
+ g_assert (priv->timer_id == 0);
+ priv->timer_id = g_timeout_add (DEFAULT_SESSION_TIMEOUT,
+ timeout_session, sess);
+ }
+ /* if we're active or ended, we can clear the timer */
+ else if ((state >= JS_STATE_ACTIVE) && (priv->timer_id != 0))
+ {
+ g_source_remove (priv->timer_id);
+ priv->timer_id = 0;
+ }
+
+ if (state == JS_STATE_ENDED)
+ g_signal_emit (sess, signals[TERMINATED], 0, FALSE);
}
void
@@ -1248,22 +1329,15 @@ gabble_jingle_session_accept (GabbleJingleSession *sess)
priv->locally_accepted = TRUE;
- try_session_accept (sess);
+ try_session_initiate_or_accept (sess);
}
void
gabble_jingle_session_terminate (GabbleJingleSession *sess)
{
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
- LmMessage *msg;
- LmMessageNode *sess_node;
-
- msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_SESSION_TERMINATE,
- &sess_node);
-
- _gabble_connection_send (priv->conn, msg, NULL);
-
- lm_message_unref (msg);
+ gabble_jingle_session_send (sess,
+ gabble_jingle_session_new_message (sess, JINGLE_ACTION_SESSION_TERMINATE,
+ NULL), NULL);
/* NOTE: on "terminated", jingle factory and media channel will unref
* it, bringing refcount to 0, so dispose will be called, and it
@@ -1271,31 +1345,35 @@ gabble_jingle_session_terminate (GabbleJingleSession *sess)
DEBUG ("we are terminating this session");
set_state (sess, JS_STATE_ENDED);
- g_signal_emit (sess, signals[TERMINATED], 0, FALSE);
}
void
gabble_jingle_session_remove_content (GabbleJingleSession *sess,
- const gchar *content_name)
+ GabbleJingleContent *c)
{
GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
- GabbleJingleContent *c = g_hash_table_lookup (priv->contents, content_name);
+ const gchar *content_name;
LmMessage *msg;
LmMessageNode *sess_node;
- g_return_if_fail (c != NULL);
+ g_object_get (c, "name", &content_name, NULL);
+
+ DEBUG ("removing content '%s'", content_name);
msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_CONTENT_REMOVE,
&sess_node);
-
- g_assert (msg != NULL);
-
gabble_jingle_content_produce_node (c, sess_node, FALSE);
- /* FIXME: actually send it, mark it as in removal, etc */
+ gabble_jingle_session_send (sess, msg, NULL);
- /* FIXME: emit a 'content-removed' signal */
- /* This should g_object_unref the content */
+ /* FIXME: emit a 'content-removed' signal, mark it as in removal? */
+ /* When we and MediaChannel unref the object, it should get disposed */
g_hash_table_remove (priv->contents, content_name);
+
+ /* If that was the last one, we can terminate the session */
+ if (g_hash_table_size (priv->contents) == 0)
+ {
+ gabble_jingle_session_terminate (sess);
+ }
}
GabbleJingleContent *
@@ -1332,66 +1410,15 @@ gabble_jingle_session_add_content (GabbleJingleSession *sess, JingleMediaType mt
"senders", JINGLE_CONTENT_SENDERS_BOTH,
NULL);
- DEBUG ("here");
-
g_signal_connect (c, "ready",
(GCallback) content_ready_cb, sess);
g_hash_table_insert (priv->contents, g_strdup (name), c);
-
g_signal_emit (sess, signals[NEW_CONTENT], 0, c);
- /* FIXME BUG: for session acceptance, we should only consider
- * contents with disposition != "session". we'll burn that bridge
- * when we come to it. Here we assume all the contents added before
- * an initiation message has been sent are initial contents. */
- if (priv->state == JS_STATE_PENDING_CREATED)
- g_hash_table_insert (priv->initial_contents, name, c);
-
- /* Try to signal content-add if needed. */
- if ((priv->state == JS_STATE_ACTIVE) ||
- ((priv->state >= JS_STATE_PENDING_INITIATE_SENT) &&
- (priv->dialect >= JINGLE_DIALECT_V026)))
- {
- LmMessage *msg;
- LmMessageNode *sess_node;
-
- msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_CONTENT_ADD,
- &sess_node);
- gabble_jingle_content_produce_node (c, sess_node, TRUE);
- _gabble_connection_send (priv->conn, msg, NULL);
- lm_message_unref (msg);
-
- DEBUG ("setting jingle cotnent state to sent");
- g_object_set (c, "state", JINGLE_CONTENT_STATE_SENT, NULL);
- }
-
return c;
}
-void
-gabble_jingle_session_change_direction (GabbleJingleSession *sess,
- const gchar *content_name, JingleContentSenders senders)
-{
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
- GabbleJingleContent *c = g_hash_table_lookup (priv->contents, content_name);
- LmMessage *msg;
- LmMessageNode *sess_node;
-
- g_return_if_fail (c != NULL);
-
- g_object_set (c, "senders", senders, NULL);
-
- msg = gabble_jingle_session_new_message (sess, JINGLE_ACTION_CONTENT_MODIFY,
- &sess_node);
-
- g_assert (msg != NULL);
-
- gabble_jingle_content_produce_node (c, sess_node, FALSE);
-
- /* FIXME: send the message, mark the nodes as pending change, etc */
-}
-
/* Get any content. Either we're in google mode (so we only have one content
* anyways), or we just need any content type to figure out what use case
* we're in (media, ft, etc). */
@@ -1438,40 +1465,18 @@ static void
content_ready_cb (GabbleJingleContent *c, gpointer user_data)
{
GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data);
- GabbleJingleSessionPrivate *priv = GABBLE_JINGLE_SESSION_GET_PRIVATE (sess);
- const gchar *name;
+ const gchar *disposition;
DEBUG ("called");
- g_object_get (c, "name", &name, NULL);
+ /* FIXME: we rely on the fact that JingleContent only signals
+ * "ready" on session contents; this is wrong, session contents
+ * added/accepted *after* session-accept are handled the same
+ * as early media */
+ g_object_get (c, "disposition", &disposition, NULL);
+ g_assert (!tp_strdiff (disposition, "session"));
- if (g_hash_table_lookup (priv->initial_contents, name))
- {
- DEBUG ("it's one of the initial contents");
- /* it's one of the contents from session-initiate */
- if (priv->local_initiator)
- {
- DEBUG ("local initiator, i'm going to try to initiate");
- try_session_initiate (sess);
- }
- else
- {
- DEBUG ("remote initiator, i'm going to try to accept");
- try_session_accept (sess);
- }
- }
- else
- {
- /* FIXME: we're assuming the content wasn't
- * created by us (we should invent content property
- * that says this, instead of assuming anything) */
- if (gabble_jingle_content_is_ready (c))
- {
- /* FIXME: content can figure out it needs to accept itself,
- * it should be handled automatically */
- content_accept (sess, c);
- }
- }
+ try_session_initiate_or_accept (sess);
}
diff --git a/src/jingle-session.h b/src/jingle-session.h
index a54cd1e..9dd11b6 100644
--- a/src/jingle-session.h
+++ b/src/jingle-session.h
@@ -88,9 +88,7 @@ gint _string_to_enum (const gchar **table, const gchar *val);
void gabble_jingle_session_accept (GabbleJingleSession *sess);
void gabble_jingle_session_terminate (GabbleJingleSession *sess);
void gabble_jingle_session_remove_content (GabbleJingleSession *sess,
- const gchar *content_name);
-void gabble_jingle_session_change_direction (GabbleJingleSession *sess,
- const gchar *content_name, JingleContentSenders senders);
+ GabbleJingleContent *c);
GabbleJingleContent *
gabble_jingle_session_add_content (GabbleJingleSession *sess, JingleMediaType mtype,
@@ -99,5 +97,11 @@ gabble_jingle_session_add_content (GabbleJingleSession *sess, JingleMediaType mt
GType gabble_jingle_session_get_content_type (GabbleJingleSession *);
GList *gabble_jingle_session_get_contents (GabbleJingleSession *sess);
+typedef void (*JingleReplyHandler) (GabbleJingleSession *, gboolean success,
+ LmMessage *reply);
+void gabble_jingle_session_send (GabbleJingleSession *sess, LmMessage *msg,
+ JingleReplyHandler cb);
+
+
#endif /* __JINGLE_SESSION_H__ */
--
1.5.6.5
More information about the Telepathy-commits
mailing list