changeset 26023:7252e3d0c627

Add files I missed committing before and remove a few unnecessary functions.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Mon, 20 Oct 2008 00:11:33 +0000
parents 46387cbfaf85
children 78c3e991782a
files libpurple/protocols/jabber/jingle/rawudp.c libpurple/protocols/jabber/jingle/rawudp.h libpurple/protocols/jabber/jingle/rtp.c libpurple/protocols/jabber/jingle/rtp.h libpurple/protocols/jabber/jingle/session.h libpurple/protocols/jabber/jingle/transport.h
diffstat 6 files changed, 1081 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/jingle/rawudp.c	Mon Oct 20 00:11:33 2008 +0000
@@ -0,0 +1,239 @@
+/**
+ * @file rawudp.c
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "rawudp.h"
+#include "jingle.h"
+#include "debug.h"
+
+#include <string.h>
+
+struct _JingleRawUdpPrivate
+{
+	guint generation;
+	gchar *id;
+	gchar *ip;
+	guint port;
+};
+
+#define JINGLE_RAWUDP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RAWUDP, JingleRawUdpPrivate))
+
+static void jingle_rawudp_class_init (JingleRawUdpClass *klass);
+static void jingle_rawudp_init (JingleRawUdp *rawudp);
+static void jingle_rawudp_finalize (GObject *object);
+static void jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static JingleTransport *jingle_rawudp_parse_internal(xmlnode *rawudp);
+static xmlnode *jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
+
+static JingleTransportClass *parent_class = NULL;
+
+enum {
+	PROP_0,
+	PROP_GENERATION,
+	PROP_ID,
+	PROP_IP,
+	PROP_PORT,
+};
+
+GType
+jingle_rawudp_get_type()
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(JingleRawUdpClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) jingle_rawudp_class_init,
+			NULL,
+			NULL,
+			sizeof(JingleRawUdp),
+			0,
+			(GInstanceInitFunc) jingle_rawudp_init,
+			NULL
+		};
+		type = g_type_register_static(JINGLE_TYPE_TRANSPORT, "JingleRawUdp", &info, 0);
+	}
+	return type;
+}
+
+static void
+jingle_rawudp_class_init (JingleRawUdpClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+
+	gobject_class->finalize = jingle_rawudp_finalize;
+	gobject_class->set_property = jingle_rawudp_set_property;
+	gobject_class->get_property = jingle_rawudp_get_property;
+	klass->parent_class.to_xml = jingle_rawudp_to_xml_internal;
+	klass->parent_class.parse = jingle_rawudp_parse_internal;
+	klass->parent_class.transport_type = JINGLE_TRANSPORT_RAWUDP;
+
+	g_object_class_install_property(gobject_class, PROP_GENERATION,
+			g_param_spec_uint("generation",
+			"Generation",
+			"The generation for this transport.",
+			0,
+			G_MAXUINT,
+			0,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_ID,
+			g_param_spec_string("id",
+			"Id",
+			"The id for this transport.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_IP,
+			g_param_spec_string("ip",
+			"IP Address",
+			"The IP address for this transport.",
+			NULL,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property(gobject_class, PROP_PORT,
+			g_param_spec_uint("port",
+			"Port",
+			"The port for this transport.",
+			0,
+			65535,
+			0,
+			G_PARAM_READWRITE));
+
+	g_type_class_add_private(klass, sizeof(JingleRawUdpPrivate));
+}
+
+static void
+jingle_rawudp_init (JingleRawUdp *rawudp)
+{
+	rawudp->priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp);
+	memset(rawudp->priv, 0, sizeof(rawudp->priv));
+}
+
+static void
+jingle_rawudp_finalize (GObject *rawudp)
+{
+	JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp);
+	purple_debug_info("jingle","jingle_rawudp_finalize\n");
+
+	g_free(priv->id);
+	g_free(priv->ip);
+}
+
+static void
+jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	JingleRawUdp *rawudp;
+	g_return_if_fail(JINGLE_IS_RAWUDP(object));
+
+	rawudp = JINGLE_RAWUDP(object);
+
+	switch (prop_id) {
+		case PROP_GENERATION:
+			rawudp->priv->generation = g_value_get_uint(value);
+			break;
+		case PROP_ID:
+			g_free(rawudp->priv->id);
+			rawudp->priv->id = g_value_dup_string(value);
+			break;
+		case PROP_IP:
+			g_free(rawudp->priv->ip);
+			rawudp->priv->ip = g_value_dup_string(value);
+			break;
+		case PROP_PORT:
+			rawudp->priv->port = g_value_get_uint(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	JingleRawUdp *rawudp;
+	g_return_if_fail(JINGLE_IS_RAWUDP(object));
+	
+	rawudp = JINGLE_RAWUDP(object);
+
+	switch (prop_id) {
+		case PROP_GENERATION:
+			g_value_set_uint(value, rawudp->priv->generation);
+			break;
+		case PROP_ID:
+			g_value_set_string(value, rawudp->priv->id);
+			break;
+		case PROP_IP:
+			g_value_set_string(value, rawudp->priv->ip);
+			break;
+		case PROP_PORT:
+			g_value_set_uint(value, rawudp->priv->port);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+}
+
+JingleRawUdp *
+jingle_rawudp_create(guint generation, const gchar *id, const gchar *ip, guint port)
+{
+	return g_object_new(jingle_rawudp_get_type(),
+			"generation", generation,
+			"id", id,
+			"ip", ip,
+			"port", port, NULL);
+}
+
+static JingleTransport *
+jingle_rawudp_parse_internal(xmlnode *rawudp)
+{
+	JingleTransport *transport = parent_class->parse(rawudp);
+	
+	return transport;
+}
+
+static xmlnode *
+jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action)
+{
+	xmlnode *node = parent_class->to_xml(transport, content, action);
+
+	if (action == JINGLE_SESSION_INITIATE || action == JINGLE_TRANSPORT_INFO) {
+		xmlnode *xmltransport = xmlnode_new_child(node, "candidate");
+		JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport);
+		gchar *generation = g_strdup_printf("%d", priv->generation);
+		gchar *port = g_strdup_printf("%d", priv->port);
+
+		xmlnode_set_attrib(xmltransport, "generation", generation);
+		xmlnode_set_attrib(xmltransport, "id", priv->id);
+		xmlnode_set_attrib(xmltransport, "ip", priv->ip);
+		xmlnode_set_attrib(xmltransport, "port", port);
+
+		g_free(port);
+		g_free(generation);
+	}
+
+	return node;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/jingle/rawudp.h	Mon Oct 20 00:11:33 2008 +0000
@@ -0,0 +1,81 @@
+/**
+ * @file rawudp.h
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef JINGLE_RAWUDP_H
+#define JINGLE_RAWUDP_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "transport.h"
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_RAWUDP            (jingle_rawudp_get_type())
+#define JINGLE_RAWUDP(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_RAWUDP, JingleRawUdp))
+#define JINGLE_RAWUDP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_RAWUDP, JingleRawUdpClass))
+#define JINGLE_IS_RAWUDP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_RAWUDP))
+#define JINGLE_IS_RAWUDP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_RAWUDP))
+#define JINGLE_RAWUDP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_RAWUDP, JingleRawUdpClass))
+
+/** @copydoc _JingleRawUdp */
+typedef struct _JingleRawUdp JingleRawUdp;
+/** @copydoc _JingleRawUdpClass */
+typedef struct _JingleRawUdpClass JingleRawUdpClass;
+/** @copydoc _JingleRawUdpPrivate */
+typedef struct _JingleRawUdpPrivate JingleRawUdpPrivate;
+
+/** The rawudp class */
+struct _JingleRawUdpClass
+{
+	JingleTransportClass parent_class;     /**< The parent class. */
+
+	xmlnode *(*to_xml) (JingleTransport *transport, xmlnode *content, JingleActionType action);
+	JingleTransport *(*parse) (xmlnode *transport);
+};
+
+/** The rawudp class's private data */
+struct _JingleRawUdp
+{
+	JingleTransport parent;                /**< The parent of this object. */
+	JingleRawUdpPrivate *priv;      /**< The private data of this object. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the rawudp class's GType
+ *
+ * @return The rawudp class's GType.
+ */
+GType jingle_rawudp_get_type(void);
+
+JingleRawUdp *jingle_rawudp_create(guint generation, const gchar *id, const gchar *ip, guint port);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
+#endif /* JINGLE_RAWUDP_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Mon Oct 20 00:11:33 2008 +0000
@@ -0,0 +1,670 @@
+/**
+ * @file rtp.c
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "config.h"
+
+#include "jabber.h"
+#include "jingle.h"
+#include "media.h"
+#include "mediamanager.h"
+#include "rawudp.h"
+#include "rtp.h"
+#include "session.h"
+#include "debug.h"
+
+#include <string.h>
+
+struct _JingleRtpPrivate
+{
+	gchar *media_type;
+	gboolean candidates_ready;
+	gboolean codecs_ready;
+};
+
+#define JINGLE_RTP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RTP, JingleRtpPrivate))
+
+static void jingle_rtp_class_init (JingleRtpClass *klass);
+static void jingle_rtp_init (JingleRtp *rtp);
+static void jingle_rtp_finalize (GObject *object);
+static void jingle_rtp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void jingle_rtp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static JingleContent *jingle_rtp_parse_internal(xmlnode *rtp);
+static xmlnode *jingle_rtp_to_xml_internal(JingleContent *rtp, xmlnode *content, JingleActionType action);
+static void jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *jingle, JingleActionType action);
+
+static PurpleMedia *jingle_rtp_get_media(JingleSession *session);
+
+static JingleContentClass *parent_class = NULL;
+#if 0
+enum {
+	LAST_SIGNAL
+};
+static guint jingle_rtp_signals[LAST_SIGNAL] = {0};
+#endif
+
+enum {
+	PROP_0,
+	PROP_MEDIA_TYPE,
+};
+
+GType
+jingle_rtp_get_type()
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(JingleRtpClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) jingle_rtp_class_init,
+			NULL,
+			NULL,
+			sizeof(JingleRtp),
+			0,
+			(GInstanceInitFunc) jingle_rtp_init,
+			NULL
+		};
+		type = g_type_register_static(JINGLE_TYPE_CONTENT, "JingleRtp", &info, 0);
+	}
+	return type;
+}
+
+static void
+jingle_rtp_class_init (JingleRtpClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+
+	gobject_class->finalize = jingle_rtp_finalize;
+	gobject_class->set_property = jingle_rtp_set_property;
+	gobject_class->get_property = jingle_rtp_get_property;
+	klass->parent_class.to_xml = jingle_rtp_to_xml_internal;
+	klass->parent_class.parse = jingle_rtp_parse_internal;
+	klass->parent_class.description_type = JINGLE_APP_RTP;
+	klass->parent_class.handle_action = jingle_rtp_handle_action_internal;
+
+	g_object_class_install_property(gobject_class, PROP_MEDIA_TYPE,
+			g_param_spec_string("media-type",
+			"Media Type",
+			"The media type (\"audio\" or \"video\") for this rtp session.",
+			NULL,
+			G_PARAM_READWRITE));
+	g_type_class_add_private(klass, sizeof(JingleRtpPrivate));
+}
+
+static void
+jingle_rtp_init (JingleRtp *rtp)
+{
+	rtp->priv = JINGLE_RTP_GET_PRIVATE(rtp);
+	memset(rtp->priv, 0, sizeof(rtp->priv));
+}
+
+static void
+jingle_rtp_finalize (GObject *rtp)
+{
+	JingleRtpPrivate *priv = JINGLE_RTP_GET_PRIVATE(rtp);
+	purple_debug_info("jingle-rtp","jingle_rtp_finalize\n");
+
+	g_free(priv->media_type);
+}
+
+static void
+jingle_rtp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	JingleRtp *rtp;
+	g_return_if_fail(JINGLE_IS_RTP(object));
+
+	rtp = JINGLE_RTP(object);
+
+	switch (prop_id) {
+		case PROP_MEDIA_TYPE:
+			g_free(rtp->priv->media_type);
+			rtp->priv->media_type = g_value_dup_string(value);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+jingle_rtp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	JingleRtp *rtp;
+	g_return_if_fail(JINGLE_IS_RTP(object));
+	
+	rtp = JINGLE_RTP(object);
+
+	switch (prop_id) {
+		case PROP_MEDIA_TYPE:
+			g_value_set_string(value, rtp->priv->media_type);
+			break;
+		default:	
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+}
+
+static gboolean
+jingle_rtp_ready_to_initiate(JingleSession *session, PurpleMedia *media)
+{
+	if (jingle_session_is_initiator(session)) {
+		GList *iter = jingle_session_get_contents(session);
+		for (; iter; iter = g_list_next(iter)) {
+			JingleContent *content = iter->data;
+			gchar *name = jingle_content_get_name(content);
+			if (!JINGLE_IS_RTP(content)
+					|| JINGLE_RTP_GET_PRIVATE(content)->codecs_ready == FALSE
+					|| JINGLE_RTP_GET_PRIVATE(content)->candidates_ready == FALSE) {
+				g_free(name);
+				return FALSE;
+			}
+			g_free(name);
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+gchar *
+jingle_rtp_get_media_type(JingleContent *content)
+{
+	gchar *media_type;
+	g_object_get(content, "media-type", &media_type, NULL);
+	return media_type;
+}
+
+static PurpleMedia *
+jingle_rtp_get_media(JingleSession *session)
+{
+	JabberStream *js = jingle_session_get_js(session);
+	gchar *sid = jingle_session_get_sid(session);
+
+	PurpleMedia *media = (PurpleMedia *) (js->medias) ?
+			  g_hash_table_lookup(js->medias, sid) : NULL;
+	g_free(sid);
+
+	return media;
+}
+
+static JingleTransport *
+jingle_rtp_candidate_to_transport(GType type, guint generation, FsCandidate *candidate)
+{
+	if (type == JINGLE_TYPE_RAWUDP) {
+		return JINGLE_TRANSPORT(jingle_rawudp_create(generation,
+				candidate->foundation, candidate->ip, candidate->port));
+#if 0
+	} else if (type == JINGLE_TYPE_ICEUDP) {
+		return NULL;
+#endif
+	} else {
+		return NULL;
+	}
+}
+
+static FsCandidate *
+jingle_rtp_transport_to_candidate(xmlnode *transport)
+{
+	xmlnode *candidate = xmlnode_get_child(transport, "candidate");
+	const gchar *type = xmlnode_get_namespace(transport);
+	if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP)) {
+		return fs_candidate_new("", FS_COMPONENT_RTP,
+				FS_CANDIDATE_TYPE_SRFLX, FS_NETWORK_PROTOCOL_UDP,
+				xmlnode_get_attrib(candidate, "ip"),
+				atoi(xmlnode_get_attrib(candidate, "port")));
+#if 0
+	} else if (type == JINGLE_TRANSPORT_ICEUDP) {
+		return NULL;
+#endif
+	} else {
+		return NULL;
+	}
+}
+
+static void
+jingle_rtp_accept_cb(PurpleMedia *media, JingleSession *session)
+{
+	jabber_iq_send(jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO));
+	jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_ACCEPT));
+}
+
+static void
+jingle_rtp_reject_cb(PurpleMedia *media, JingleSession *session)
+{
+	jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE));
+	g_object_unref(session);
+}
+
+static void
+jingle_rtp_hangup_cb(PurpleMedia *media, JingleSession *session)
+{
+	jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE));
+	g_object_unref(session);
+}
+
+static void
+jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, FsCandidate *candidate, JingleSession *session)
+{
+	purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n");
+
+	if (candidate->component_id == 1) {
+		JingleContent *content = jingle_session_find_content(session, sid, "initiator");
+		JingleTransport *transport =
+				JINGLE_TRANSPORT(jingle_rtp_candidate_to_transport(
+				JINGLE_TYPE_RAWUDP, 0, candidate));
+		jingle_content_set_pending_transport(content, transport);
+		jingle_content_accept_transport(content);
+	}
+}
+
+static void
+jingle_rtp_candidates_prepared_cb(PurpleMedia *media, gchar *sid, gchar *name, JingleSession *session)
+{
+	JingleContent *content = jingle_session_find_content(session, sid, "initiator");
+	JINGLE_RTP_GET_PRIVATE(content)->candidates_ready = TRUE;
+
+	if (jingle_rtp_ready_to_initiate(session, media))
+		jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_INITIATE));
+}
+
+static void
+jingle_rtp_candidate_pair_established_cb(PurpleMedia *media, FsCandidate *local_candidate, FsCandidate *remote_candidate, JingleSession *session)
+{
+
+}
+
+static void
+jingle_rtp_codecs_ready_cb(PurpleMedia *media, gchar *sid, JingleSession *session)
+{
+	JingleContent *content = jingle_session_find_content(session, sid, "initiator");
+
+	if (content == NULL)
+		content = jingle_session_find_content(session, sid, "responder");
+
+	if (JINGLE_RTP_GET_PRIVATE(content)->codecs_ready == FALSE) {
+		JINGLE_RTP_GET_PRIVATE(content)->codecs_ready =
+				purple_media_codecs_ready(media, sid);
+
+		if (jingle_rtp_ready_to_initiate(session, media))
+			jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_INITIATE));
+	}
+}
+
+static PurpleMedia *
+jingle_rtp_create_media(JingleContent *content)
+{
+	JingleSession *session = jingle_content_get_session(content);
+	JabberStream *js = jingle_session_get_js(session);
+	gchar *remote_jid = jingle_session_get_remote_jid(session);
+	gchar *sid = jingle_session_get_sid(session);
+
+	PurpleMedia *media = purple_media_manager_create_media(purple_media_manager_get(), 
+						  js->gc, "fsrtpconference", remote_jid);
+	g_free(remote_jid);
+
+	if (!media) {
+		purple_debug_error("jingle-rtp", "Couldn't create media session\n");
+		return NULL;
+	}
+
+	/* insert it into the hash table */
+	if (!js->medias) {
+		purple_debug_info("jingle-rtp", "Creating hash table for media\n");
+		js->medias = g_hash_table_new(g_str_hash, g_str_equal);
+	}
+	purple_debug_info("jingle-rtp", "inserting media with sid: %s into table\n", sid);
+	g_hash_table_insert(js->medias, sid, media);
+
+	/* connect callbacks */
+	g_signal_connect(G_OBJECT(media), "accepted",
+				 G_CALLBACK(jingle_rtp_accept_cb), session);
+	g_signal_connect(G_OBJECT(media), "reject",
+				 G_CALLBACK(jingle_rtp_reject_cb), session);
+	g_signal_connect(G_OBJECT(media), "hangup",
+				 G_CALLBACK(jingle_rtp_hangup_cb), session);
+	g_signal_connect(G_OBJECT(media), "new-candidate",
+				 G_CALLBACK(jingle_rtp_new_candidate_cb), session);
+	g_signal_connect(G_OBJECT(media), "candidates-prepared",
+				 G_CALLBACK(jingle_rtp_candidates_prepared_cb), session);
+	g_signal_connect(G_OBJECT(media), "candidate-pair",
+				 G_CALLBACK(jingle_rtp_candidate_pair_established_cb), session);
+	g_signal_connect(G_OBJECT(media), "codecs-ready",
+				 G_CALLBACK(jingle_rtp_codecs_ready_cb), session);
+
+	g_object_unref(session);
+	return media;
+}
+
+static gboolean
+jingle_rtp_init_media(JingleContent *content)
+{
+	JingleSession *session = jingle_content_get_session(content);
+	PurpleMedia *media = jingle_rtp_get_media(session);
+	gchar *media_type;
+	gchar *remote_jid;
+	gchar *senders;
+	gchar *name;
+	const gchar *transmitter;
+	FsMediaType type;
+	FsStreamDirection direction;
+	JingleTransport *transport;
+
+	/* maybe this create ought to just be in initiate and handle initiate */
+	if (media == NULL)
+		media = jingle_rtp_create_media(content);
+
+	if (media == NULL)
+		return FALSE;
+
+	name = jingle_content_get_name(content);
+	media_type = jingle_rtp_get_media_type(content);
+	remote_jid = jingle_session_get_remote_jid(session);
+	senders = jingle_content_get_senders(content);
+	transport = jingle_content_get_transport(content);
+
+	if (JINGLE_IS_RAWUDP(transport))
+		transmitter = "rawudp";
+	else
+		transmitter = "notransmitter";
+
+	if (!strcmp(media_type, "audio"))
+		type = FS_MEDIA_TYPE_AUDIO;
+	else
+		type = FS_MEDIA_TYPE_VIDEO;
+
+	if (!strcmp(senders, "both"))
+		direction = FS_DIRECTION_BOTH;
+	else if (!strcmp(senders, "initiator")
+			&& jingle_session_is_initiator(session))
+		direction = FS_DIRECTION_SEND;
+	else
+		direction = FS_DIRECTION_RECV;
+
+	purple_media_add_stream(media, name, remote_jid,
+			purple_media_from_fs(type, direction),
+			transmitter, 0, NULL);
+
+
+	g_free(name);
+	g_free(media_type);
+	g_free(remote_jid);
+	g_free(senders);
+	g_object_unref(session);
+
+	/* needs to be after all the streams have been added */
+	purple_media_ready(media);
+
+	return TRUE;
+}
+
+static GList *
+jingle_rtp_parse_codecs(xmlnode *description)
+{
+	GList *codecs = NULL;
+	xmlnode *codec_element = NULL;
+	const char *encoding_name,*id, *clock_rate;
+	FsCodec *codec;
+	const gchar *media = xmlnode_get_attrib(description, "media");
+	FsMediaType type = !strcmp(media, "video") ? FS_MEDIA_TYPE_VIDEO :
+			!strcmp(media, "audio") ? FS_MEDIA_TYPE_AUDIO : 0;
+
+	for (codec_element = xmlnode_get_child(description, "payload-type") ;
+		 codec_element ;
+		 codec_element = xmlnode_get_next_twin(codec_element)) {
+		xmlnode *param;
+		gchar *codec_str;
+		encoding_name = xmlnode_get_attrib(codec_element, "name");
+
+		id = xmlnode_get_attrib(codec_element, "id");
+		clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
+
+		codec = fs_codec_new(atoi(id), encoding_name, 
+				     type, 
+				     clock_rate ? atoi(clock_rate) : 0);
+
+		for (param = xmlnode_get_child(codec_element, "parameter");
+				param; param = xmlnode_get_next_twin(param)) {
+			fs_codec_add_optional_parameter(codec,
+					xmlnode_get_attrib(param, "name"),
+					xmlnode_get_attrib(param, "value"));
+		}
+
+		codec_str = fs_codec_to_string(codec);
+		purple_debug_info("jingle-rtp", "received codec: %s\n", codec_str);
+		g_free(codec_str);
+
+		codecs = g_list_append(codecs, codec);
+	}
+	return codecs;
+}
+
+static JingleContent *
+jingle_rtp_parse_internal(xmlnode *rtp)
+{
+	JingleContent *content = parent_class->parse(rtp);
+	xmlnode *description = xmlnode_get_child(rtp, "description");
+	const gchar *media_type = xmlnode_get_attrib(description, "media");
+	purple_debug_info("jingle-rtp", "rtp parse\n");
+	g_object_set(content, "media-type", media_type, NULL);
+	return content;
+}
+
+static void
+jingle_rtp_add_payloads(xmlnode *description, GList *codecs)
+{
+	for (; codecs ; codecs = codecs->next) {
+		FsCodec *codec = (FsCodec*)codecs->data;
+		GList *iter = codec->optional_params;
+		char id[8], clockrate[10], channels[10];
+		gchar *codec_str;
+		xmlnode *payload = xmlnode_new_child(description, "payload-type");
+		
+		g_snprintf(id, sizeof(id), "%d", codec->id);
+		g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate);
+		g_snprintf(channels, sizeof(channels), "%d", codec->channels);
+		
+		xmlnode_set_attrib(payload, "name", codec->encoding_name);
+		xmlnode_set_attrib(payload, "id", id);
+		xmlnode_set_attrib(payload, "clockrate", clockrate);
+		xmlnode_set_attrib(payload, "channels", channels);
+
+		for (; iter; iter = g_list_next(iter)) {
+			FsCodecParameter *fsparam = iter->data;
+			xmlnode *param = xmlnode_new_child(payload, "parameter");
+			xmlnode_set_attrib(param, "name", fsparam->name);
+			xmlnode_set_attrib(param, "value", fsparam->value);
+		}
+
+		codec_str = fs_codec_to_string(codec);
+		purple_debug_info("jingle", "adding codec: %s\n", codec_str);
+		g_free(codec_str);
+	}
+}
+
+static xmlnode *
+jingle_rtp_to_xml_internal(JingleContent *rtp, xmlnode *content, JingleActionType action)
+{
+	xmlnode *node = parent_class->to_xml(rtp, content, action);
+	xmlnode *description = xmlnode_get_child(node, "description");
+	if (description != NULL) {
+		JingleSession *session = jingle_content_get_session(rtp);
+		PurpleMedia *media = jingle_rtp_get_media(session);
+		gchar *media_type = jingle_rtp_get_media_type(rtp);
+		gchar *name = jingle_content_get_name(rtp);
+		GList *codecs = purple_media_get_local_codecs(media, name);
+
+		xmlnode_set_attrib(description, "media", media_type);
+
+		g_free(media_type);
+		g_free(name);
+		g_object_unref(session);
+
+		jingle_rtp_add_payloads(description, codecs);
+	}
+	return node;
+}
+
+static void
+jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *jingle, JingleActionType action)
+{
+	switch (action) {
+		case JINGLE_SESSION_ACCEPT: {
+			JingleSession *session = jingle_content_get_session(content);
+			xmlnode *description = xmlnode_get_child(jingle, "content/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);
+
+			g_object_unref(session);
+			break;
+		}
+		case JINGLE_SESSION_INITIATE: {
+			JingleSession *session = jingle_content_get_session(content);
+			xmlnode *description = xmlnode_get_child(jingle, "content/description");
+			xmlnode *transport = xmlnode_get_child(jingle, "content/transport");
+			FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport);
+			GList *candidates = g_list_append(NULL, candidate);
+			GList *codecs = jingle_rtp_parse_codecs(description);
+
+			jingle_rtp_init_media(content);
+
+			purple_media_set_remote_codecs(jingle_rtp_get_media(session),
+					jingle_content_get_name(content),
+					jingle_session_get_remote_jid(session), codecs);
+
+			/* manufacture rtcp candidate */
+			candidate = fs_candidate_copy(candidate);
+			candidate->component_id = 2;
+			candidate->port = candidate->port + 1;
+			candidates = g_list_append(candidates, candidate);
+
+			purple_media_add_remote_candidates(jingle_rtp_get_media(session),
+					jingle_content_get_name(content),
+					jingle_session_get_remote_jid(session),
+					candidates);
+
+			g_object_unref(session);
+			break;
+		}
+		case JINGLE_SESSION_TERMINATE: {
+			JingleSession *session = jingle_content_get_session(content);
+			purple_media_got_hangup(jingle_rtp_get_media(session));
+			g_object_unref(session);
+			break;
+		}
+		case JINGLE_TRANSPORT_INFO: {
+			JingleSession *session = jingle_content_get_session(content);
+			xmlnode *transport = xmlnode_get_child(jingle, "content/transport");
+			FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport);
+			GList *candidates = g_list_append(NULL, candidate);
+
+			/* manufacture rtcp candidate */
+			candidate = fs_candidate_copy(candidate);
+			candidate->component_id = 2;
+			candidate->port = candidate->port + 1;
+			candidates = g_list_append(candidates, candidate);
+
+			purple_media_add_remote_candidates(jingle_rtp_get_media(session),
+					jingle_content_get_name(content),
+					jingle_session_get_remote_jid(session),
+					candidates);
+			purple_media_got_accept(jingle_rtp_get_media(session));
+			g_object_unref(session);
+			break;
+		}
+		default:
+			break;
+	}
+}
+
+PurpleMedia *
+jingle_rtp_initiate_media(JabberStream *js, const gchar *who, 
+		      PurpleMediaSessionType type)
+{
+	/* create content negotiation */
+	JingleSession *session;
+	JingleContent *content;
+	JingleTransport *transport;
+	JabberBuddy *jb;
+	JabberBuddyResource *jbr;
+	
+	gchar *jid = NULL, *me = NULL, *sid = NULL;
+
+	/* construct JID to send to */
+	jb = jabber_buddy_find(js, who, FALSE);
+	if (!jb) {
+		purple_debug_error("jingle-rtp", "Could not find Jabber buddy\n");
+		return NULL;
+	}
+	jbr = jabber_buddy_find_resource(jb, NULL);
+	if (!jbr) {
+		purple_debug_error("jingle-rtp", "Could not find buddy's resource\n");
+	}
+
+	if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) {
+		jid = g_strdup_printf("%s/%s", who, jbr->name);
+	} else {
+		jid = g_strdup(who);
+	}
+	
+	/* set ourselves as initiator */
+	me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
+
+	sid = jabber_get_next_id(js);
+	session = jingle_session_create(js, sid, me, jid, TRUE);
+	g_free(sid);
+
+	transport = jingle_transport_create(JINGLE_TRANSPORT_RAWUDP);
+	content = jingle_content_create(JINGLE_APP_RTP, "initiator", "session", "test-session", "both", transport);
+	jingle_session_add_content(session, content);
+	if (purple_media_to_fs_media_type(type) == FS_MEDIA_TYPE_AUDIO)
+		JINGLE_RTP(content)->priv->media_type = g_strdup("audio");
+	else
+		JINGLE_RTP(content)->priv->media_type = g_strdup("video");
+
+	jingle_rtp_init_media(content);
+
+	purple_media_wait(jingle_rtp_get_media(session));
+
+	g_free(jid);
+	g_free(me);
+
+	return NULL;
+}
+
+void
+jingle_rtp_terminate_session(JabberStream *js, const gchar *who)
+{
+	JingleSession *session;
+/* XXX: This may cause file transfers and xml sessions to stop as well */
+	session = jingle_session_find_by_jid(js, who);
+
+	if (session) {
+		PurpleMedia *media = jingle_rtp_get_media(session);
+		if (media) {
+			purple_debug_info("jingle-rtp", "hanging up media\n");
+			purple_media_hangup(media);
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.h	Mon Oct 20 00:11:33 2008 +0000
@@ -0,0 +1,91 @@
+/**
+ * @file rtp.h
+ *
+ * purple
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef JINGLE_RTP_H
+#define JINGLE_RTP_H
+
+#include "config.h"
+
+#ifdef USE_VV
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "content.h"
+#include "media.h"
+#include "xmlnode.h"
+
+G_BEGIN_DECLS
+
+#define JINGLE_TYPE_RTP            (jingle_rtp_get_type())
+#define JINGLE_RTP(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_RTP, JingleRtp))
+#define JINGLE_RTP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_RTP, JingleRtpClass))
+#define JINGLE_IS_RTP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_RTP))
+#define JINGLE_IS_RTP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JINGLE_TYPE_RTP))
+#define JINGLE_RTP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), JINGLE_TYPE_RTP, JingleRtpClass))
+
+/** @copydoc _JingleRtp */
+typedef struct _JingleRtp JingleRtp;
+/** @copydoc _JingleRtpClass */
+typedef struct _JingleRtpClass JingleRtpClass;
+/** @copydoc _JingleRtpPrivate */
+typedef struct _JingleRtpPrivate JingleRtpPrivate;
+
+/** The rtp class */
+struct _JingleRtpClass
+{
+	JingleContentClass parent_class;     /**< The parent class. */
+};
+
+/** The rtp class's private data */
+struct _JingleRtp
+{
+	JingleContent parent;                /**< The parent of this object. */
+	JingleRtpPrivate *priv;      /**< The private data of this object. */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Gets the rtp class's GType
+ *
+ * @return The rtp class's GType.
+ */
+GType jingle_rtp_get_type(void);
+
+gchar *jingle_rtp_get_media_type(JingleContent *content);
+
+PurpleMedia *jingle_rtp_initiate_media(JabberStream *js,
+				   const gchar *who,
+				   PurpleMediaSessionType type);
+void jingle_rtp_terminate_session(JabberStream *js, const gchar *who);
+
+#ifdef __cplusplus
+}
+#endif
+
+G_END_DECLS
+
+#endif /* USE_VV */
+
+#endif /* JINGLE_RTP_H */
+
--- a/libpurple/protocols/jabber/jingle/session.h	Sun Oct 19 04:59:51 2008 +0000
+++ b/libpurple/protocols/jabber/jingle/session.h	Mon Oct 20 00:11:33 2008 +0000
@@ -91,15 +91,6 @@
 
 void jingle_session_handle_action(JingleSession *session, xmlnode *jingle, JingleActionType action);
 
-#define jingle_session_create_session_accept(session) \
-	jingle_session_to_packet(session, JINGLE_SESSION_ACCEPT)
-#define jingle_session_create_session_info(session) \
-	jingle_session_to_packet(session, JINGLE_SESSION_INFO)
-#define jingle_session_create_session_initiate(session) \
-	jingle_session_to_packet(session, JINGLE_SESSION_INITIATE)
-#define jingle_session_create_session_terminate(session) \
-	jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE)
-
 struct _JingleContent *jingle_session_find_content(JingleSession *session,
 					const gchar *name, const gchar *creator);
 struct _JingleContent *jingle_session_find_pending_content(JingleSession *session,
--- a/libpurple/protocols/jabber/jingle/transport.h	Sun Oct 19 04:59:51 2008 +0000
+++ b/libpurple/protocols/jabber/jingle/transport.h	Mon Oct 20 00:11:33 2008 +0000
@@ -75,13 +75,6 @@
 const gchar *jingle_transport_get_transport_type(JingleTransport *transport);
 void jingle_transport_add_candidate();
 
-#define jingle_transport_create_transport_accept(session) \
-	jingle_session_to_packet(session, JINGLE_TRANSPORT_ACCEPT)
-#define jingle_transport_create_transport_info(session) \
-	jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO)
-#define jingle_transport_create_transport_replace(session) \
-	jingle_session_to_packet(session, JINGLE_TRANSPORT_REPLACE)
-
 JingleTransport *jingle_transport_parse(xmlnode *transport);
 xmlnode *jingle_transport_to_xml(JingleTransport *transport, xmlnode *content, JingleActionType action);