changeset 26386:7e24c04ab5c9

merge of '932de261b2c091dd834f54518d4c9df53b9ad7ac' and 'ef1c8c06e832e807799e7e2785305b34f7a257b2'
author Mike Ruprecht <maiku@soc.pidgin.im>
date Thu, 19 Mar 2009 10:46:41 +0000
parents 95794e9acf71 (diff) 3824cd706fa3 (current diff)
children 189ac8d13103
files libpurple/protocols/jabber/jingle/session.c
diffstat 11 files changed, 273 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/media.c	Thu Mar 19 10:46:41 2009 +0000
@@ -126,6 +126,7 @@
 enum {
 	ERROR,
 	ACCEPTED,
+	CANDIDATES_PREPARED,
 	CODECS_CHANGED,
 	NEW_CANDIDATE,
 	READY_NEW,
@@ -234,6 +235,11 @@
 					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 					 purple_smarshal_VOID__STRING_STRING,
 					 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+	purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass),
+					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					 purple_smarshal_VOID__STRING_STRING,
+					 G_TYPE_NONE, 2, G_TYPE_STRING,
+					 G_TYPE_STRING);
 	purple_media_signals[CODECS_CHANGED] = g_signal_new("codecs-changed", G_TYPE_FROM_CLASS(klass),
 					 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
 					 g_cclosure_marshal_VOID__STRING,
@@ -260,7 +266,7 @@
 purple_media_init (PurpleMedia *media)
 {
 	media->priv = PURPLE_MEDIA_GET_PRIVATE(media);
-	memset(media->priv, 0, sizeof(media->priv));
+	memset(media->priv, 0, sizeof(*media->priv));
 }
 
 static void
@@ -355,7 +361,7 @@
 		priv->manager = NULL;
 	}
 
-	G_OBJECT_CLASS(parent_class)->finalize(media);
+	G_OBJECT_CLASS(parent_class)->dispose(media);
 }
 
 static void
@@ -1724,6 +1730,10 @@
 	stream_data = purple_media_get_stream(session->media, session->id, name);
 	stream_data->candidates_prepared = TRUE;
 
+	g_signal_emit(session->media,
+			purple_media_signals[CANDIDATES_PREPARED],
+			0, session->id, name);
+
 	purple_media_emit_ready(session->media, session, name);
 	g_free(name);
 }
--- a/libpurple/protocols/jabber/jingle/content.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/content.c	Thu Mar 19 10:46:41 2009 +0000
@@ -152,7 +152,7 @@
 jingle_content_init (JingleContent *content)
 {
 	content->priv = JINGLE_CONTENT_GET_PRIVATE(content);
-	memset(content->priv, 0, sizeof(content->priv));
+	memset(content->priv, 0, sizeof(*content->priv));
 }
 
 static void
@@ -205,13 +205,11 @@
 			if (content->priv->transport)
 				g_object_unref(content->priv->transport);
 			content->priv->transport = g_value_get_object(value);
-			g_object_ref(content->priv->transport);
 			break;
 		case PROP_PENDING_TRANSPORT:
 			if (content->priv->pending_transport)
 				g_object_unref(content->priv->pending_transport);
 			content->priv->pending_transport = g_value_get_object(value);
-			g_object_ref(content->priv->pending_transport);
 			break;
 		default:	
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -435,6 +433,7 @@
 			transport = jingle_content_get_transport(content);
 
 		jingle_transport_to_xml(transport, node, action);
+		g_object_unref(transport);
 	}
 
 	return node;
--- a/libpurple/protocols/jabber/jingle/iceudp.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/iceudp.c	Thu Mar 19 10:46:41 2009 +0000
@@ -68,6 +68,8 @@
 	new_candidate->username = g_strdup(candidate->username);
 	new_candidate->password = g_strdup(candidate->password);
 
+	new_candidate->rem_known = candidate->rem_known;
+
 	return new_candidate;
 }
 
@@ -119,6 +121,8 @@
 
 	candidate->username = g_strdup(username);
 	candidate->password = g_strdup(password);
+
+	candidate->rem_known = FALSE;
 	return candidate;
 }
 
@@ -177,7 +181,8 @@
 jingle_iceudp_init (JingleIceUdp *iceudp)
 {
 	iceudp->priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp);
-	memset(iceudp->priv, 0, sizeof(iceudp->priv));
+	iceudp->priv->local_candidates = NULL;
+	iceudp->priv->remote_candidates = NULL;
 }
 
 static void
@@ -185,6 +190,8 @@
 {
 /*	JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp); */
 	purple_debug_info("jingle","jingle_iceudp_finalize\n");
+
+	G_OBJECT_CLASS(parent_class)->finalize(iceudp);
 }
 
 static void
@@ -321,6 +328,7 @@
 				xmlnode_get_attrib(candidate, "rel-addr"));
 		iceudp_candidate->relport =
 				relport != NULL ? atoi(relport) : 0;
+		iceudp_candidate->rem_known = TRUE;
 		jingle_iceudp_add_remote_candidate(JINGLE_ICEUDP(transport), iceudp_candidate);
 	}
 
@@ -332,31 +340,34 @@
 {
 	xmlnode *node = parent_class->to_xml(transport, content, action);
 
-	if (action == JINGLE_SESSION_INITIATE || action == JINGLE_TRANSPORT_INFO ||
-			action == JINGLE_CONTENT_ADD || action == JINGLE_TRANSPORT_REPLACE) {
-		JingleIceUdpPrivate *icetransport =
-				JINGLE_ICEUDP_GET_PRIVATE(transport);
-		if (icetransport && icetransport->local_candidates) {
-			JingleIceUdpCandidate *candidate =
-					icetransport->local_candidates->data;
-			xmlnode_set_attrib(node, "pwd", candidate->password);
-			xmlnode_set_attrib(node, "ufrag", candidate->username);
-		}
-	}
-
-	if (action == JINGLE_TRANSPORT_INFO || action == JINGLE_SESSION_ACCEPT) {
+	if (action == JINGLE_SESSION_INITIATE ||
+			action == JINGLE_SESSION_ACCEPT ||
+			action == JINGLE_TRANSPORT_INFO ||
+			action == JINGLE_CONTENT_ADD ||
+			action == JINGLE_TRANSPORT_REPLACE) {
 		JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(transport);
 		GList *iter = priv->local_candidates;
+		gboolean used_candidate = FALSE;
 
 		for (; iter; iter = g_list_next(iter)) {
 			JingleIceUdpCandidate *candidate = iter->data;
+			xmlnode *xmltransport;
+			gchar *component, *generation, *network,
+					*port, *priority;
 
-			xmlnode *xmltransport = xmlnode_new_child(node, "candidate");
-			gchar *component = g_strdup_printf("%d", candidate->component);
-			gchar *generation = g_strdup_printf("%d", candidate->generation);
-			gchar *network = g_strdup_printf("%d", candidate->network);
-			gchar *port = g_strdup_printf("%d", candidate->port);
-			gchar *priority = g_strdup_printf("%d", candidate->priority);
+			if (candidate->rem_known == TRUE)
+				continue;
+
+			used_candidate = TRUE;
+			candidate->rem_known = TRUE;
+
+			xmltransport = xmlnode_new_child(node, "candidate");
+			component = g_strdup_printf("%d", candidate->component);
+			generation = g_strdup_printf("%d",
+					candidate->generation);
+			network = g_strdup_printf("%d", candidate->network);
+			port = g_strdup_printf("%d", candidate->port);
+			priority = g_strdup_printf("%d", candidate->priority);
 
 			xmlnode_set_attrib(xmltransport, "component", component);
 			xmlnode_set_attrib(xmltransport, "foundation", candidate->foundation);
@@ -388,6 +399,13 @@
 			g_free(port);
 			g_free(priority);
 		}
+
+		if (used_candidate == TRUE) {
+			JingleIceUdpCandidate *candidate =
+					priv->local_candidates->data;
+			xmlnode_set_attrib(node, "pwd", candidate->password);
+			xmlnode_set_attrib(node, "ufrag", candidate->username);
+		}
 	}
 
 	return node;
--- a/libpurple/protocols/jabber/jingle/iceudp.h	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/iceudp.h	Thu Mar 19 10:46:41 2009 +0000
@@ -78,6 +78,9 @@
 
 	gchar *username;
 	gchar *password;
+
+	gboolean rem_known;	/* TRUE if the remote side knows
+				 * about this candidate */
 };
 
 #ifdef __cplusplus
--- a/libpurple/protocols/jabber/jingle/jingle.h	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.h	Thu Mar 19 10:46:41 2009 +0000
@@ -42,7 +42,7 @@
 #define JINGLE_DTMF "urn:xmpp:jingle:dtmf:0"
 #define JINGLE_TRANSPORT_S5B "urn:xmpp:jingle:transports:s5b:0"
 #define JINGLE_TRANSPORT_IBB "urn:xmpp:jingle:transports:ibb:0"
-#define JINGLE_TRANSPORT_ICEUDP "urn:xmpp:jingle:transports:ice-udp:0"
+#define JINGLE_TRANSPORT_ICEUDP "urn:xmpp:jingle:transports:ice-udp:1"
 #define JINGLE_TRANSPORT_RAWUDP "urn:xmpp:jingle:transports:raw-udp:1"
 
 typedef enum {
--- a/libpurple/protocols/jabber/jingle/rawudp.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rawudp.c	Thu Mar 19 10:46:41 2009 +0000
@@ -59,6 +59,8 @@
 	new_candidate->id = g_strdup(candidate->id);
 	new_candidate->ip = g_strdup(candidate->ip);
 	new_candidate->port = candidate->port;
+
+	new_candidate->rem_known = candidate->rem_known;
 	return new_candidate;
 }
 
@@ -91,6 +93,8 @@
 	candidate->id = g_strdup(id);
 	candidate->ip = g_strdup(ip);
 	candidate->port = port;
+
+	candidate->rem_known = FALSE;
 	return candidate;
 }
 
@@ -149,7 +153,8 @@
 jingle_rawudp_init (JingleRawUdp *rawudp)
 {
 	rawudp->priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp);
-	memset(rawudp->priv, 0, sizeof(rawudp->priv));
+	rawudp->priv->local_candidates = NULL;
+	rawudp->priv->remote_candidates = NULL;
 }
 
 static void
@@ -157,6 +162,8 @@
 {
 /*	JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); */
 	purple_debug_info("jingle","jingle_rawudp_finalize\n");
+
+	G_OBJECT_CLASS(parent_class)->finalize(rawudp);
 }
 
 static void
@@ -277,6 +284,7 @@
 				atoi(xmlnode_get_attrib(candidate, "component")),
 				xmlnode_get_attrib(candidate, "ip"),
 				atoi(xmlnode_get_attrib(candidate, "port")));
+		rawudp_candidate->rem_known = TRUE;
 		jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
 	}
 
@@ -286,6 +294,7 @@
 		rawudp_candidate = g_boxed_copy(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate);
 		rawudp_candidate->component = 2;
 		rawudp_candidate->port = rawudp_candidate->port + 1;
+		rawudp_candidate->rem_known = TRUE;
 		jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
 	}
 
@@ -297,17 +306,25 @@
 {
 	xmlnode *node = parent_class->to_xml(transport, content, action);
 
-	if (action == JINGLE_SESSION_INITIATE || action == JINGLE_TRANSPORT_INFO) {
+	if (action == JINGLE_SESSION_INITIATE ||
+			action == JINGLE_TRANSPORT_INFO ||
+			action == JINGLE_SESSION_ACCEPT) {
 		JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport);
 		GList *iter = priv->local_candidates;
 
 		for (; iter; iter = g_list_next(iter)) {
 			JingleRawUdpCandidate *candidate = iter->data;
+			xmlnode *xmltransport;
+			gchar *generation, *component, *port;
 
-			xmlnode *xmltransport = xmlnode_new_child(node, "candidate");
-			gchar *generation = g_strdup_printf("%d", candidate->generation);
-			gchar *component = g_strdup_printf("%d", candidate->component);
-			gchar *port = g_strdup_printf("%d", candidate->port);
+			if (candidate->rem_known == TRUE)
+				continue;
+			candidate->rem_known = TRUE;
+
+			xmltransport = xmlnode_new_child(node, "candidate");
+			generation = g_strdup_printf("%d", candidate->generation);
+			component = g_strdup_printf("%d", candidate->component);
+			port = g_strdup_printf("%d", candidate->port);
 
 			xmlnode_set_attrib(xmltransport, "generation", generation);
 			xmlnode_set_attrib(xmltransport, "component", component);
--- a/libpurple/protocols/jabber/jingle/rawudp.h	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rawudp.h	Thu Mar 19 10:46:41 2009 +0000
@@ -68,6 +68,9 @@
 	gchar *id;
 	gchar *ip;
 	guint port;
+
+	gboolean rem_known;	/* TRUE if the remote side knows
+				 * about this candidate */
 };
 
 #ifdef __cplusplus
--- a/libpurple/protocols/jabber/jingle/rtp.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Thu Mar 19 10:46:41 2009 +0000
@@ -37,6 +37,7 @@
 struct _JingleRtpPrivate
 {
 	gchar *media_type;
+	gchar *ssrc;
 };
 
 #define JINGLE_RTP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RTP, JingleRtpPrivate))
@@ -63,6 +64,7 @@
 enum {
 	PROP_0,
 	PROP_MEDIA_TYPE,
+	PROP_SSRC,
 };
 
 GType
@@ -108,6 +110,13 @@
 			"The media type (\"audio\" or \"video\") for this rtp session.",
 			NULL,
 			G_PARAM_READWRITE));
+	g_object_class_install_property(gobject_class, PROP_SSRC,
+			g_param_spec_string("ssrc",
+			"ssrc",
+			"The ssrc for this rtp session.",
+			NULL,
+			G_PARAM_READWRITE));
+
 	g_type_class_add_private(klass, sizeof(JingleRtpPrivate));
 }
 
@@ -115,7 +124,7 @@
 jingle_rtp_init (JingleRtp *rtp)
 {
 	rtp->priv = JINGLE_RTP_GET_PRIVATE(rtp);
-	memset(rtp->priv, 0, sizeof(rtp->priv));
+	memset(rtp->priv, 0, sizeof(*rtp->priv));
 }
 
 static void
@@ -125,6 +134,9 @@
 	purple_debug_info("jingle-rtp","jingle_rtp_finalize\n");
 
 	g_free(priv->media_type);
+	g_free(priv->ssrc);
+
+	G_OBJECT_CLASS(parent_class)->finalize(rtp);
 }
 
 static void
@@ -140,6 +152,10 @@
 			g_free(rtp->priv->media_type);
 			rtp->priv->media_type = g_value_dup_string(value);
 			break;
+		case PROP_SSRC:
+			g_free(rtp->priv->ssrc);
+			rtp->priv->ssrc = g_value_dup_string(value);
+			break;
 		default:	
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 			break;
@@ -158,6 +174,9 @@
 		case PROP_MEDIA_TYPE:
 			g_value_set_string(value, rtp->priv->media_type);
 			break;
+		case PROP_SSRC:
+			g_value_set_string(value, rtp->priv->ssrc);
+			break;
 		default:	
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
 			break;
@@ -172,6 +191,14 @@
 	return media_type;
 }
 
+gchar *
+jingle_rtp_get_ssrc(JingleContent *content)
+{
+	gchar *ssrc;
+	g_object_get(content, "ssrc", &ssrc, NULL);
+	return ssrc;
+}
+
 static PurpleMedia *
 jingle_rtp_get_media(JingleSession *session)
 {
@@ -194,6 +221,39 @@
 	return media;
 }
 
+static JingleRawUdpCandidate *
+jingle_rtp_candidate_to_rawudp(JingleSession *session, guint generation,
+		PurpleMediaCandidate *candidate)
+{
+	gchar *id = jabber_get_next_id(jingle_session_get_js(session));
+	JingleRawUdpCandidate *rawudp_candidate =
+			jingle_rawudp_candidate_new(id,
+			generation, candidate->component_id,
+			candidate->ip, candidate->port);
+	g_free(id);
+	return rawudp_candidate;
+}
+
+static JingleIceUdpCandidate *
+jingle_rtp_candidate_to_iceudp(JingleSession *session, guint generation,
+		PurpleMediaCandidate *candidate)
+{
+	gchar *id = jabber_get_next_id(jingle_session_get_js(session));
+	JingleIceUdpCandidate *iceudp_candidate = jingle_iceudp_candidate_new(
+			candidate->component_id, candidate->foundation,
+			generation, id, candidate->ip, 0,
+			candidate->port, candidate->priority, "udp",
+			candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
+			candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
+			candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
+			candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : "",
+			candidate->username, candidate->password);
+	iceudp_candidate->reladdr = g_strdup(candidate->base_ip);
+	iceudp_candidate->relport = candidate->base_port;
+	g_free(id);
+	return iceudp_candidate;
+}
+
 static JingleTransport *
 jingle_rtp_candidates_to_transport(JingleSession *session, GType type, guint generation, GList *candidates)
 {
@@ -202,13 +262,11 @@
 		JingleRawUdpCandidate *rawudp_candidate;
 		for (; candidates; candidates = g_list_next(candidates)) {
 			PurpleMediaCandidate *candidate = candidates->data;
-			gchar *id = jabber_get_next_id(
-					jingle_session_get_js(session));
-			rawudp_candidate = jingle_rawudp_candidate_new(id,
-					generation, candidate->component_id,
-					candidate->ip, candidate->port);
-			jingle_rawudp_add_local_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
-			g_free(id);
+			rawudp_candidate = jingle_rtp_candidate_to_rawudp(
+					session, generation, candidate);
+			jingle_rawudp_add_local_candidate(
+					JINGLE_RAWUDP(transport),
+					rawudp_candidate);
 		}
 		return transport;
 	} else if (type == JINGLE_TYPE_ICEUDP) {
@@ -216,20 +274,11 @@
 		JingleIceUdpCandidate *iceudp_candidate;
 		for (; candidates; candidates = g_list_next(candidates)) {
 			PurpleMediaCandidate *candidate = candidates->data;
-			gchar *id = jabber_get_next_id(
-					jingle_session_get_js(session));
-			iceudp_candidate = jingle_iceudp_candidate_new(candidate->component_id,
-					candidate->foundation, generation, id, candidate->ip,
-					0, candidate->port, candidate->priority, "udp",
-					candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
-					candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
-					candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
-					candidate->type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" : "",
-					candidate->username, candidate->password);
-			iceudp_candidate->reladdr = g_strdup(candidate->base_ip);
-			iceudp_candidate->relport = candidate->base_port;
-			jingle_iceudp_add_local_candidate(JINGLE_ICEUDP(transport), iceudp_candidate);
-			g_free(id);
+			iceudp_candidate = jingle_rtp_candidate_to_iceudp(
+					session, generation, candidate);
+			jingle_iceudp_add_local_candidate(
+					JINGLE_ICEUDP(transport),
+					iceudp_candidate);
 		}
 		return transport;
 	} else {
@@ -294,6 +343,38 @@
 }
 
 static void
+jingle_rtp_candidates_prepared_cb(PurpleMedia *media,
+		gchar *sid, gchar *name, JingleSession *session)
+{
+	JingleContent *content = jingle_session_find_content(
+			session, sid, NULL);
+	JingleTransport *oldtransport, *transport;
+	GList *candidates;
+
+	purple_debug_info("jingle-rtp", "jingle_rtp_candidates_prepared_cb\n");
+
+	if (content == NULL) {
+		purple_debug_error("jingle-rtp",
+				"jingle_rtp_candidates_prepared_cb: "
+				"Can't find session %s\n", sid);
+		return;
+	}
+
+	oldtransport = jingle_content_get_transport(content);
+	candidates = purple_media_get_local_candidates(media, sid, name);
+	transport = JINGLE_TRANSPORT(jingle_rtp_candidates_to_transport(
+			session, JINGLE_IS_RAWUDP(oldtransport) ?
+				JINGLE_TYPE_RAWUDP : JINGLE_TYPE_ICEUDP,
+			0, candidates));
+
+	g_list_free(candidates);
+	g_object_unref(oldtransport);
+
+	jingle_content_set_pending_transport(content, transport);
+	jingle_content_accept_transport(content);
+}
+
+static void
 jingle_rtp_codecs_changed_cb(PurpleMedia *media, gchar *sid,
 		JingleSession *session)
 {
@@ -304,7 +385,34 @@
 static void
 jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, PurpleMediaCandidate *candidate, JingleSession *session)
 {
+	JingleContent *content = jingle_session_find_content(
+			session, sid, NULL);
+	JingleTransport *transport;
+
 	purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n");
+
+	if (content == NULL) {
+		purple_debug_error("jingle-rtp",
+				"jingle_rtp_new_candidate_cb: "
+				"Can't find session %s\n", sid);
+		return;
+	}
+
+	transport = jingle_content_get_transport(content);
+
+	if (JINGLE_IS_ICEUDP(transport))
+		jingle_iceudp_add_local_candidate(JINGLE_ICEUDP(transport),
+				jingle_rtp_candidate_to_iceudp(
+				session, 1, candidate));
+	else if (JINGLE_IS_RAWUDP(transport))
+		jingle_rawudp_add_local_candidate(JINGLE_RAWUDP(transport),
+				jingle_rtp_candidate_to_rawudp(
+				session, 1, candidate));
+
+	g_object_unref(transport);
+
+	jabber_iq_send(jingle_session_to_packet(session,
+			JINGLE_TRANSPORT_INFO));
 }
 
 static void
@@ -318,9 +426,6 @@
 		g_object_unref(session);
 		return;
 	}
-
-	jabber_iq_send(jingle_session_to_packet(session,
-			JINGLE_TRANSPORT_INFO));
 }
 
 static void
@@ -330,36 +435,18 @@
 
 	if (sid == NULL && name == NULL) {
 		if (jingle_session_is_initiator(session) == TRUE) {
-			GList *contents = jingle_session_get_contents(session);
 			JabberIq *iq = jingle_session_to_packet(
 					session, JINGLE_SESSION_INITIATE);
-
-			if (contents->data) {
-				JingleTransport *transport =
-						jingle_content_get_transport(contents->data);
-				if (JINGLE_IS_ICEUDP(transport))
-					jabber_iq_set_callback(iq,
-							jingle_rtp_initiate_ack_cb, session);
-			}
-
+			jabber_iq_set_callback(iq,
+					jingle_rtp_initiate_ack_cb, session);
 			jabber_iq_send(iq);
+			g_signal_connect(G_OBJECT(media), "new-candidate",
+					 G_CALLBACK(jingle_rtp_new_candidate_cb), session);
 		} else {
-			jabber_iq_send(jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO));
 			jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_ACCEPT));
+			g_signal_connect(G_OBJECT(media), "new-candidate",
+					 G_CALLBACK(jingle_rtp_new_candidate_cb), session);
 		}
-	} else if (sid != NULL && name != NULL) {
-		JingleContent *content = jingle_session_find_content(session, sid, "initiator");
-		JingleTransport *oldtransport = jingle_content_get_transport(content);
-		GList *candidates = purple_media_get_local_candidates(media, sid, name);
-		JingleTransport *transport =
-				JINGLE_TRANSPORT(jingle_rtp_candidates_to_transport(
-				session, JINGLE_IS_RAWUDP(oldtransport) ?
-					JINGLE_TYPE_RAWUDP : JINGLE_TYPE_ICEUDP,
-				0, candidates));
-		g_list_free(candidates);
-
-		jingle_content_set_pending_transport(content, transport);
-		jingle_content_accept_transport(content);
 	}
 }
 
@@ -400,10 +487,10 @@
 	/* connect callbacks */
 	g_signal_connect(G_OBJECT(media), "accepted",
 				 G_CALLBACK(jingle_rtp_accepted_cb), session);
+	g_signal_connect(G_OBJECT(media), "candidates-prepared",
+				 G_CALLBACK(jingle_rtp_candidates_prepared_cb), session);
 	g_signal_connect(G_OBJECT(media), "codecs-changed",
 				 G_CALLBACK(jingle_rtp_codecs_changed_cb), session);
-	g_signal_connect(G_OBJECT(media), "new-candidate",
-				 G_CALLBACK(jingle_rtp_new_candidate_cb), session);
 	g_signal_connect(G_OBJECT(media), "ready-new",
 				 G_CALLBACK(jingle_rtp_ready_cb), session);
 	g_signal_connect(G_OBJECT(media), "state-changed",
@@ -448,6 +535,7 @@
 		transmitter = "nice";
 	else
 		transmitter = "notransmitter";
+	g_object_unref(transport);
 
 	is_audio = !strcmp(media_type, "audio");
 
@@ -525,8 +613,11 @@
 	JingleContent *content = parent_class->parse(rtp);
 	xmlnode *description = xmlnode_get_child(rtp, "description");
 	const gchar *media_type = xmlnode_get_attrib(description, "media");
+	const gchar *ssrc = xmlnode_get_attrib(description, "ssrc");
 	purple_debug_info("jingle-rtp", "rtp parse\n");
 	g_object_set(content, "media-type", media_type, NULL);
+	if (ssrc != NULL)
+		g_object_set(content, "ssrc", ssrc, NULL);
 	return content;
 }
 
@@ -571,11 +662,15 @@
 		JingleSession *session = jingle_content_get_session(rtp);
 		PurpleMedia *media = jingle_rtp_get_media(session);
 		gchar *media_type = jingle_rtp_get_media_type(rtp);
+		gchar *ssrc = jingle_rtp_get_ssrc(rtp);
 		gchar *name = jingle_content_get_name(rtp);
 		GList *codecs = purple_media_get_codecs(media, name);
 
 		xmlnode_set_attrib(description, "media", media_type);
 
+		if (ssrc != NULL)
+			xmlnode_set_attrib(description, "ssrc", ssrc);
+
 		g_free(media_type);
 		g_free(name);
 		g_object_unref(session);
@@ -589,23 +684,7 @@
 jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *xmlcontent, JingleActionType action)
 {
 	switch (action) {
-		case JINGLE_SESSION_ACCEPT: {
-			JingleSession *session = jingle_content_get_session(content);
-			xmlnode *description = xmlnode_get_child(xmlcontent, "description");
-			GList *codecs = jingle_rtp_parse_codecs(description);
-
-			purple_media_set_remote_codecs(jingle_rtp_get_media(session),
-					jingle_content_get_name(content),
-					jingle_session_get_remote_jid(session), codecs);
-
-			/* This needs to be for the entire session, not a single content */
-			/* very hacky */
-			if (xmlnode_get_next_twin(xmlcontent) == NULL)
-				purple_media_accept(jingle_rtp_get_media(session));
-
-			g_object_unref(session);
-			break;
-		}
+		case JINGLE_SESSION_ACCEPT:
 		case JINGLE_SESSION_INITIATE: {
 			JingleSession *session = jingle_content_get_session(content);
 			JingleTransport *transport = jingle_transport_parse(
@@ -613,8 +692,13 @@
 			xmlnode *description = xmlnode_get_child(xmlcontent, "description");
 			GList *candidates = jingle_rtp_transport_to_candidates(transport);
 			GList *codecs = jingle_rtp_parse_codecs(description);
+			gchar *name = jingle_content_get_name(content);
+			gchar *remote_jid =
+					jingle_session_get_remote_jid(session);
+			PurpleMedia *media;
 
-			if (jingle_rtp_init_media(content) == FALSE) {
+			if (action == JINGLE_SESSION_INITIATE &&
+					jingle_rtp_init_media(content) == FALSE) {
 				/* XXX: send error */
 				jabber_iq_send(jingle_session_terminate_packet(
 						session, "general-error"));
@@ -622,17 +706,20 @@
 				break;
 			}
 
-			purple_media_set_remote_codecs(jingle_rtp_get_media(session),
-					jingle_content_get_name(content),
-					jingle_session_get_remote_jid(session), codecs);
+			media = jingle_rtp_get_media(session);
+			purple_media_set_remote_codecs(media,
+					name, remote_jid, codecs);
+			purple_media_add_remote_candidates(media,
+					name, remote_jid, candidates);
 
-			if (JINGLE_IS_RAWUDP(transport)) {
-				purple_media_add_remote_candidates(jingle_rtp_get_media(session),
-						jingle_content_get_name(content),
-						jingle_session_get_remote_jid(session),
-						candidates);
-			}
+			/* This needs to be for the entire session, not a single content */
+			/* very hacky */
+			if (action == JINGLE_SESSION_ACCEPT &&
+					xmlnode_get_next_twin(xmlcontent) == NULL)
+				purple_media_accept(media);
 
+			g_free(remote_jid);
+			g_free(name);
 			g_object_unref(session);
 			break;
 		}
@@ -652,11 +739,16 @@
 			JingleTransport *transport = jingle_transport_parse(
 					xmlnode_get_child(xmlcontent, "transport"));
 			GList *candidates = jingle_rtp_transport_to_candidates(transport);
+			gchar *name = jingle_content_get_name(content);
+			gchar *remote_jid =
+					jingle_session_get_remote_jid(session);
 
-			purple_media_add_remote_candidates(jingle_rtp_get_media(session),
-					jingle_content_get_name(content),
-					jingle_session_get_remote_jid(session),
-					candidates);
+			purple_media_add_remote_candidates(
+					jingle_rtp_get_media(session),
+					name, remote_jid, candidates);
+
+			g_free(remote_jid);
+			g_free(name);
 			g_object_unref(session);
 			break;
 		}
--- a/libpurple/protocols/jabber/jingle/rtp.h	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.h	Thu Mar 19 10:46:41 2009 +0000
@@ -73,6 +73,7 @@
 GType jingle_rtp_get_type(void);
 
 gchar *jingle_rtp_get_media_type(JingleContent *content);
+gchar *jingle_rtp_get_ssrc(JingleContent *content);
 
 PurpleMedia *jingle_rtp_initiate_media(JabberStream *js,
 				   const gchar *who,
--- a/libpurple/protocols/jabber/jingle/session.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/session.c	Thu Mar 19 10:46:41 2009 +0000
@@ -154,7 +154,7 @@
 jingle_session_init (JingleSession *session)
 {
 	session->priv = JINGLE_SESSION_GET_PRIVATE(session);
-	memset(session->priv, 0, sizeof(session->priv));
+	memset(session->priv, 0, sizeof(*session->priv));
 }
 
 static void
@@ -500,11 +500,14 @@
 	for (; iter; iter = g_list_next(iter)) {
 		JingleContent *content = iter->data;
 		gchar *cname = jingle_content_get_name(content);
-		gchar *ccreator = jingle_content_get_creator(content);
-		gboolean result = (!strcmp(name, cname) && !strcmp(creator, ccreator));
+		gboolean result = !strcmp(name, cname);
+		g_free(cname);
 
-		g_free(cname);
-		g_free(ccreator);
+		if (creator != NULL) {
+			gchar *ccreator = jingle_content_get_creator(content);
+			result = (result && !strcmp(creator, ccreator));
+			g_free(ccreator);
+		}
 
 		if (result == TRUE)
 			return content;
@@ -519,11 +522,14 @@
 	for (; iter; iter = g_list_next(iter)) {
 		JingleContent *content = iter->data;
 		gchar *cname = jingle_content_get_name(content);
-		gchar *ccreator = jingle_content_get_creator(content);
-		gboolean result = (!strcmp(name, cname) && !strcmp(creator, ccreator));
+		gboolean result = !strcmp(name, cname);
+		g_free(cname);
 
-		g_free(cname);
-		g_free(ccreator);
+		if (creator != NULL) {
+			gchar *ccreator = jingle_content_get_creator(content);
+			result = (result && !strcmp(creator, ccreator));
+			g_free(ccreator);
+		}
 
 		if (result == TRUE)
 			return content;
--- a/libpurple/protocols/jabber/jingle/transport.c	Thu Mar 19 10:46:34 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/transport.c	Thu Mar 19 10:46:41 2009 +0000
@@ -89,7 +89,7 @@
 jingle_transport_init (JingleTransport *transport)
 {
 	transport->priv = JINGLE_TRANSPORT_GET_PRIVATE(transport);
-	memset(transport->priv, 0, sizeof(transport->priv));
+	transport->priv->dummy = NULL;
 }
 
 static void