changeset 23830:b5a00ddb7077

Jingle sessions now keep track of their transaction state to a degree.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Sat, 07 Jun 2008 03:14:52 +0000
parents 54adcf17d271
children 6268758d029a
files libpurple/media.c libpurple/media.h libpurple/protocols/jabber/jingle.c
diffstat 3 files changed, 105 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Fri Jun 06 22:20:33 2008 +0000
+++ b/libpurple/media.c	Sat Jun 07 03:14:52 2008 +0000
@@ -754,9 +754,9 @@
 }
 
 static void
-purple_media_new_local_candidate(FsStream *stream,
-				  FsCandidate *local_candidate,
-				  PurpleMediaSession *session)
+purple_media_new_local_candidate_cb(FsStream *stream,
+				    FsCandidate *local_candidate,
+				    PurpleMediaSession *session)
 {
 	gchar *name;
 	FsParticipant *participant;
@@ -774,7 +774,7 @@
 }
 
 static void
-purple_media_candidates_prepared(FsStream *stream, PurpleMediaSession *session)
+purple_media_candidates_prepared_cb(FsStream *stream, PurpleMediaSession *session)
 {
 	gchar *name;
 	FsParticipant *participant;
@@ -788,10 +788,10 @@
 /* callback called when a pair of transport candidates (local and remote)
  * has been established */
 static void
-purple_media_candidate_pair_established(FsStream *stream,
-					 FsCandidate *native_candidate,
-					 FsCandidate *remote_candidate,
-					 PurpleMediaSession *session)
+purple_media_candidate_pair_established_cb(FsStream *stream,
+					   FsCandidate *native_candidate,
+					   FsCandidate *remote_candidate,
+					   PurpleMediaSession *session)
 {
 	session->local_candidate = fs_candidate_copy(native_candidate);
 	session->remote_candidate = fs_candidate_copy(remote_candidate);
@@ -803,8 +803,8 @@
 }
 
 static void
-purple_media_src_pad_added(FsStream *stream, GstPad *srcpad,
-			    FsCodec *codec, PurpleMediaSession *session)
+purple_media_src_pad_added_cb(FsStream *stream, GstPad *srcpad,
+			      FsCodec *codec, PurpleMediaSession *session)
 {
 	GstElement *pipeline = purple_media_get_pipeline(session->media);
 	GstPad *sinkpad = gst_element_get_static_pad(session->sink, "ghostsink");
@@ -893,18 +893,18 @@
 		purple_media_insert_stream(session, who, stream);
 		/* callback for new local candidate (new local candidate retreived) */
 		g_signal_connect(G_OBJECT(stream),
-				 "new-local-candidate", G_CALLBACK(purple_media_new_local_candidate), session);
+				 "new-local-candidate", G_CALLBACK(purple_media_new_local_candidate_cb), session);
 		/* callback for source pad added (new stream source ready) */
 		g_signal_connect(G_OBJECT(stream),
-				 "src-pad-added", G_CALLBACK(purple_media_src_pad_added), session);
+				 "src-pad-added", G_CALLBACK(purple_media_src_pad_added_cb), session);
 		/* callback for local candidates prepared (local candidates ready to send) */
 		g_signal_connect(G_OBJECT(stream), 
 				 "local-candidates-prepared", 
-				 G_CALLBACK(purple_media_candidates_prepared), session);
+				 G_CALLBACK(purple_media_candidates_prepared_cb), session);
 		/* callback for new active candidate pair (established connection) */
 		g_signal_connect(G_OBJECT(stream),
 				 "new-active-candidate-pair", 
-				 G_CALLBACK(purple_media_candidate_pair_established), session);
+				 G_CALLBACK(purple_media_candidate_pair_established_cb), session);
 	} else if (*direction != type_direction) {	
 		/* change direction */
 		g_object_set(stream, "direction", type_direction, NULL);
@@ -1012,4 +1012,19 @@
 	fs_stream_set_remote_codecs(stream, codecs, NULL);
 }
 
+gboolean
+purple_media_candidates_prepared(PurpleMedia *media, const gchar *name)
+{
+	GList *sessions = purple_media_get_session_names(media);
+
+	for (; sessions; sessions = sessions->next) {
+		const gchar *session = sessions->data;
+		if (!purple_media_get_local_candidate(media, session, name) ||
+				!purple_media_get_remote_candidate(media, session, name))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
 #endif  /* USE_VV */
--- a/libpurple/media.h	Fri Jun 06 22:20:33 2008 +0000
+++ b/libpurple/media.h	Sat Jun 07 03:14:52 2008 +0000
@@ -133,6 +133,8 @@
 FsCandidate *purple_media_get_remote_candidate(PurpleMedia *media, const gchar *sess_id, const gchar *name);
 void purple_media_set_remote_codecs(PurpleMedia *media, const gchar *sess_id, const gchar *name, GList *codecs);
 
+gboolean purple_media_candidates_prepared(PurpleMedia *media, const gchar *name);
+
 G_END_DECLS
 
 #endif  /* USE_VV */
--- a/libpurple/protocols/jabber/jingle.c	Fri Jun 06 22:20:33 2008 +0000
+++ b/libpurple/protocols/jabber/jingle.c	Sat Jun 07 03:14:52 2008 +0000
@@ -36,6 +36,13 @@
 #define JINGLE_RTP_INFO "urn:xmpp:tmp:jingle:apps:rtp:info"
 #define TRANSPORT_ICEUDP "urn:xmpp:tmp:jingle:transports:ice-udp"
 
+typedef enum {
+	PENDING,
+	GOT_ACK,
+	ACCEPTED,
+	ACTIVE
+} JingleSessionState;
+
 typedef struct {
 	char *id;
 	JabberStream *js;
@@ -43,7 +50,7 @@
 	char *remote_jid;
 	char *initiator;
 	gboolean is_initiator;
-	gboolean session_started;
+	JingleSessionState state;
 	GHashTable *contents;	/* JingleSessionContent table */
 } JingleSession;
 
@@ -207,7 +214,7 @@
 					  sess->id);
 	g_hash_table_insert(js->sessions, sess->id, sess);
 
-	sess->session_started = FALSE;
+	sess->state = PENDING;
 
 	return sess;
 }
@@ -393,6 +400,20 @@
 	sess->remote_jid = strdup(remote_jid);
 }
 
+static JingleSessionState
+jabber_jingle_session_get_state(JingleSession *sess)
+{
+	return sess->state;
+}
+
+static void
+jabber_jingle_session_set_state(JingleSession *sess,
+				JingleSessionState state)
+{
+	sess->state = state;
+}
+				
+
 static const char *
 jabber_jingle_session_get_initiator(const JingleSession *sess)
 {
@@ -647,10 +668,10 @@
 #endif
 
 static JabberIq *
-jabber_jingle_session_create_session_accept(const JingleSession *session,
-					    FsCandidate *local,
-					    FsCandidate *remote)
+jabber_jingle_session_create_session_accept(const JingleSession *session)
 {
+	PurpleMedia *media = jabber_jingle_session_get_media(session);
+	const gchar *remote_jid = jabber_jingle_session_get_remote_jid(session);
 	JabberIq *request = jabber_jingle_session_create_iq(session);
 	xmlnode *jingle =
 		jabber_jingle_session_add_jingle(session, request,
@@ -659,13 +680,19 @@
 
 	for (; contents; contents = contents->next) {
 		JingleSessionContent *jsc = contents->data;
+		const gchar *session_name = jabber_jingle_session_content_get_name(jsc);
 		xmlnode *content = jabber_jingle_session_add_content(jsc, jingle);
 		xmlnode *description = jabber_jingle_session_add_description(jsc, content);
 		xmlnode *transport = jabber_jingle_session_add_transport(jsc, content);
 		if (jabber_jingle_session_content_is_type(jsc, JINGLE_RTP))
 			jabber_jingle_session_add_payload_types(jsc, description);
-		if (jabber_jingle_session_content_is_transport_type(jsc, TRANSPORT_ICEUDP))
-			jabber_jingle_session_add_candidate_iceudp(transport, local, remote);
+		if (jabber_jingle_session_content_is_transport_type(jsc, TRANSPORT_ICEUDP)) {
+			jabber_jingle_session_add_candidate_iceudp(transport, 
+					purple_media_get_local_candidate(media, session_name,
+									 remote_jid),
+					purple_media_get_remote_candidate(media, session_name,
+									  remote_jid));
+		}
 	}
 
 	return request;
@@ -760,12 +787,13 @@
 	/* create transport-info packages */
 	PurpleMedia *media = jabber_jingle_session_get_media(session);
 	GList *contents = jabber_jingle_session_get_contents(session);
+	const gchar *remote_jid = jabber_jingle_session_get_remote_jid(session);
 	for (; contents; contents = contents->next) {
 		JingleSessionContent *jsc = contents->data;
 		GList *candidates = purple_media_get_local_candidates(
 				media,
 				jabber_jingle_session_content_get_name(jsc),
-				jabber_jingle_session_get_remote_jid(session));
+				remote_jid);
 		purple_debug_info("jingle",
 				  "jabber_session_candidates_prepared: %d candidates\n",
 				  g_list_length(candidates));
@@ -776,23 +804,20 @@
 			jabber_iq_send(result);
 		}
 		fs_candidate_list_destroy(candidates);
+
 		purple_debug_info("jingle", "codec intersection: %i\n",
 				g_list_length(purple_media_get_negotiated_codecs(media,
 				jabber_jingle_session_content_get_name(jsc))));
-		jabber_iq_send(jabber_jingle_session_create_session_accept(session, 
-				purple_media_get_local_candidate(media,
-					jabber_jingle_session_content_get_name(jsc),
-					jabber_jingle_session_get_remote_jid(session)),
-				purple_media_get_remote_candidate(media,
-					jabber_jingle_session_content_get_name(jsc),
-					jabber_jingle_session_get_remote_jid(session))));
 	}
 
+	if (purple_media_candidates_prepared(media, remote_jid)) {
+		jabber_iq_send(jabber_jingle_session_create_session_accept(session));
 
-	purple_debug_info("jingle", "Sent session accept, starting stream\n");
-	gst_element_set_state(purple_media_get_pipeline(session->media), GST_STATE_PLAYING);
-
-	session->session_started = TRUE;
+		purple_debug_info("jingle", "Sent session accept, starting stream\n");
+		gst_element_set_state(purple_media_get_pipeline(session->media), GST_STATE_PLAYING);
+		jabber_jingle_session_set_state(session, ACTIVE);
+	} else
+		jabber_jingle_session_set_state(session, ACCEPTED);
 }
 
 static void
@@ -861,51 +886,41 @@
 						      subtype);
 }
 
-/* callback called when new local transport candidate(s) are available on the
-	Farsight stream */
 static void
-jabber_jingle_session_candidates_prepared(PurpleMedia *media, JingleSession *session)
+jabber_jingle_session_new_candidate_cb(PurpleMedia *media,
+				       const gchar *session_id,
+				       const gchar *name,
+				       FsCandidate *candidate,
+				       JingleSession *session)
 {
-#if 0
-	if (!jabber_jingle_session_is_initiator(session)) {
-		/* create transport-info packages */
-		GList *contents = jabber_jingle_session_get_contents(session);
-		for (; contents; contents = contents->next) {
-			JingleSessionContent *jsc = contents->data;
-			GList *candidates = purple_media_get_local_audio_candidates(
-					jabber_jingle_session_get_media(session));
-			purple_debug_info("jingle",
-					  "jabber_session_candidates_prepared: %d candidates\n",
-					  g_list_length(candidates));
-			for (; candidates; candidates = candidates->next) {
-				FsCandidate *candidate = candidates->data;
-				JabberIq *result = jabber_jingle_session_create_transport_info(jsc,
-						candidate);
-				jabber_iq_send(result);
-			}
-			fs_candidate_list_destroy(candidates);
-		}
+	if (jabber_jingle_session_get_state(session) == GOT_ACK ||
+			jabber_jingle_session_get_state(session) == ACTIVE) {
+		JingleSessionContent *jsc = jabber_jingle_session_get_content(session,
+									      session_id);
+		jabber_iq_send(jabber_jingle_session_create_transport_info(jsc,
+				candidate));
 	}
-#endif
 }
 
 /* callback called when a pair of transport candidates (local and remote)
 	has been established */
 static void
-jabber_jingle_session_candidate_pair_established(PurpleMedia *media,
-						 FsCandidate *native_candidate,
-						 FsCandidate *remote_candidate,
-						 JingleSession *session)
+jabber_jingle_session_candidate_pair_established_cb(PurpleMedia *media,
+						    FsCandidate *native_candidate,
+						    FsCandidate *remote_candidate,
+						    JingleSession *session)
 {
-#if 0
-	purple_debug_info("jingle", "jabber_candidate_pair_established called\n");
-	/* if we are the responder, we should send a sesson-accept message */
 	if (!jabber_jingle_session_is_initiator(session) &&
-			!session->session_started) {
-		jabber_iq_send(jabber_jingle_session_create_session_accept(session, 
-				native_candidate, remote_candidate));
+			jabber_jingle_session_get_state(session) == ACCEPTED &&
+			purple_media_candidates_prepared(media,
+				jabber_jingle_session_get_remote_jid(session))) {
+		jabber_iq_send(jabber_jingle_session_create_session_accept(session));
+		
+		purple_debug_info("jingle", "Sent session accept, starting stream\n");
+		gst_element_set_state(purple_media_get_pipeline(session->media),
+				      GST_STATE_PLAYING);
+		jabber_jingle_session_set_state(session, ACTIVE);
 	}
-#endif
 }
 
 static gboolean
@@ -959,10 +974,10 @@
 				 G_CALLBACK(jabber_jingle_session_send_session_reject), session);
 	g_signal_connect_swapped(G_OBJECT(media), "hangup", 
 				 G_CALLBACK(jabber_jingle_session_send_session_terminate), session);
-	g_signal_connect(G_OBJECT(media), "candidates-prepared", 
-				 G_CALLBACK(jabber_jingle_session_candidates_prepared), session);
+	g_signal_connect(G_OBJECT(media), "new-candidate", 
+				 G_CALLBACK(jabber_jingle_session_new_candidate_cb), session);
 	g_signal_connect(G_OBJECT(media), "candidate-pair", 
-				 G_CALLBACK(jabber_jingle_session_candidate_pair_established), session);
+				 G_CALLBACK(jabber_jingle_session_candidate_pair_established_cb), session);
 
 	purple_media_ready(media);
 
@@ -1007,6 +1022,8 @@
 		}
 		fs_candidate_list_destroy(candidates);
 	}
+
+	jabber_jingle_session_set_state(session, GOT_ACK);
 }
 
 PurpleMedia *
@@ -1205,7 +1222,7 @@
 
 	jabber_iq_send(result);
 
-	session->session_started = TRUE;
+	jabber_jingle_session_set_state(session, ACTIVE);
 }
 
 void