[Telepathy-commits] [telepathy-glib/master] ExampleCallableMediaChannel: implement the outgoing-call state machine (the Group interface)
Simon McVittie
simon.mcvittie at collabora.co.uk
Fri Mar 13 06:32:56 PDT 2009
---
examples/cm/callable/media-channel.c | 89 +++++++++++++++++++++++++++++++--
1 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/examples/cm/callable/media-channel.c b/examples/cm/callable/media-channel.c
index 7179c28..9b44b87 100644
--- a/examples/cm/callable/media-channel.c
+++ b/examples/cm/callable/media-channel.c
@@ -83,6 +83,13 @@ enum
N_SIGNALS
};
+typedef enum {
+ PROGRESS_NONE,
+ PROGRESS_CALLING,
+ PROGRESS_ACTIVE,
+ PROGRESS_ENDED
+} ExampleCallableCallProgress;
+
static guint signals[N_SIGNALS] = { 0 };
struct _ExampleCallableMediaChannelPrivate
@@ -91,6 +98,7 @@ struct _ExampleCallableMediaChannelPrivate
gchar *object_path;
TpHandle handle;
TpHandle initiator;
+ ExampleCallableCallProgress progress;
guint next_stream_id;
@@ -98,7 +106,6 @@ struct _ExampleCallableMediaChannelPrivate
/* These are really booleans, but gboolean is signed. Thanks, GLib */
unsigned locally_requested:1;
- unsigned closed:1;
unsigned disposed:1;
};
@@ -158,12 +165,14 @@ constructed (GObject *object)
/* Nobody is locally pending. The remote peer will turn up in
* remote-pending state when we actually contact them, which is done
* in RequestStreams */
+ self->priv->progress = PROGRESS_NONE;
local_pending = NULL;
}
else
{
/* This is an incoming call, so the self-handle is locally
* pending, to indicate that we need to answer. */
+ self->priv->progress = PROGRESS_CALLING;
local_pending = tp_intset_new_containing (self->priv->conn->self_handle);
}
@@ -268,7 +277,7 @@ get_property (GObject *object,
break;
case PROP_CHANNEL_DESTROYED:
- g_value_set_boolean (value, self->priv->closed);
+ g_value_set_boolean (value, (self->priv->progress == PROGRESS_ENDED));
break;
case PROP_CHANNEL_PROPERTIES:
@@ -342,11 +351,11 @@ static void
example_callable_media_channel_close (ExampleCallableMediaChannel *self,
TpChannelGroupChangeReason reason)
{
- if (!self->priv->closed)
+ if (self->priv->progress != PROGRESS_ENDED)
{
const gchar *send_reason;
- self->priv->closed = TRUE;
+ self->priv->progress = PROGRESS_ENDED;
/* In a real protocol these would be some sort of real protocol construct,
* like an XMPP error stanza or a SIP error code */
@@ -364,7 +373,7 @@ example_callable_media_channel_close (ExampleCallableMediaChannel *self,
send_reason = "<call-terminated/>";
}
- g_message ("Sending to server: Terminating call: %s", send_reason);
+ g_message ("SIGNALLING: send: Terminating call: %s", send_reason);
g_signal_emit (self, signals[SIGNAL_CALL_TERMINATED], 0);
tp_svc_channel_emit_closed (self);
}
@@ -426,7 +435,7 @@ add_member (GObject *object,
/* We're in local-pending, move to members to accept. */
TpIntSet *set = tp_intset_new_containing (member);
- g_message ("Sending to server: Accepting incoming call from %s",
+ g_message ("SIGNALLING: send: Accepting incoming call from %s",
tp_handle_inspect (contact_repo, self->priv->handle));
tp_group_mixin_change_members (object, "",
@@ -777,6 +786,38 @@ stream_direction_changed_cb (ExampleCallableMediaStream *stream,
direction, pending);
}
+static gboolean
+simulate_contact_answered_cb (gpointer p)
+{
+ ExampleCallableMediaChannel *self = p;
+ TpIntSet *peer_set;
+
+ /* if the call has been cancelled while we were waiting for the
+ * contact to answer, do nothing */
+ if (self->priv->progress == PROGRESS_ENDED)
+ return FALSE;
+
+ /* otherwise, we're waiting for a response from the contact, which now
+ * arrives */
+ g_assert (self->priv->progress == PROGRESS_CALLING);
+
+ g_message ("SIGNALLING: receive: contact answered our call");
+
+ self->priv->progress = PROGRESS_ACTIVE;
+
+ peer_set = tp_intset_new_containing (self->priv->handle);
+ tp_group_mixin_change_members ((GObject *) self, "",
+ peer_set /* added */,
+ NULL /* nobody removed */,
+ NULL /* nobody added to local-pending */,
+ NULL /* nobody added to remote-pending */,
+ self->priv->handle /* actor */,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_intset_destroy (peer_set);
+
+ return FALSE;
+}
+
static void
media_request_streams (TpSvcChannelTypeStreamedMedia *iface,
guint contact_handle,
@@ -801,6 +842,13 @@ media_request_streams (TpSvcChannelTypeStreamedMedia *iface,
goto error;
}
+ if (self->priv->progress == PROGRESS_ENDED)
+ {
+ g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "Call has terminated");
+ goto error;
+ }
+
for (i = 0; i < media_types->len; i++)
{
guint media_type = g_array_index (media_types, guint, i);
@@ -826,6 +874,35 @@ media_request_streams (TpSvcChannelTypeStreamedMedia *iface,
GValueArray *info;
guint id = self->priv->next_stream_id++;
+ if (self->priv->progress < PROGRESS_CALLING)
+ {
+ TpIntSet *peer_set = tp_intset_new_containing (self->priv->handle);
+
+ g_message ("SIGNALLING: send: new streamed media call");
+ self->priv->progress = PROGRESS_CALLING;
+
+ tp_group_mixin_change_members ((GObject *) self, "",
+ NULL /* nobody added */,
+ NULL /* nobody removed */,
+ NULL /* nobody added to local-pending */,
+ peer_set /* added to remote-pending */,
+ self->group.self_handle /* actor */,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+
+ tp_intset_destroy (peer_set);
+
+ /* In this example there is no real contact, so just simulate them
+ * answering after 1000ms */
+ /* FIXME: define a special contact who never answers, and if it's
+ * that contact, don't add this timeout */
+ g_timeout_add_full (G_PRIORITY_DEFAULT, 1000,
+ simulate_contact_answered_cb, g_object_ref (self),
+ g_object_unref);
+ }
+
+ g_message ("SIGNALLING: send: new %s stream",
+ media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video");
+
stream = g_object_new (EXAMPLE_TYPE_CALLABLE_MEDIA_STREAM,
"channel", self,
"id", id,
--
1.5.6.5
More information about the telepathy-commits
mailing list