# HG changeset patch # User Mike Ruprecht # Date 1224461493 0 # Node ID 7252e3d0c62766001de309b2eb1da6b0e0b5e0f4 # Parent 46387cbfaf85c7f5f3e6e4c34a1ebe70d2c1bf89 Add files I missed committing before and remove a few unnecessary functions. diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/rawudp.c --- /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 + +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; +} + diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/rawudp.h --- /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 +#include + +#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 */ + diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/rtp.c --- /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 + +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); + } + } +} + diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/rtp.h --- /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 +#include + +#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 */ + diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/session.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, diff -r 46387cbfaf85 -r 7252e3d0c627 libpurple/protocols/jabber/jingle/transport.h --- 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);