soc.2008.vv: 2e652889: Moved Jingle message handlers from jabbe...
maiku at soc.pidgin.im
maiku at soc.pidgin.im
Mon Jun 2 18:21:04 EDT 2008
-----------------------------------------------------------------
Revision: 2e652889513f0ea3dd9a66c1b8463c673fcb0d72
Ancestor: 0e3d104cc0b327bc26b945dee862a84caca15e65
Author: maiku at soc.pidgin.im
Date: 2008-06-02T20:59:20
Branch: im.pidgin.soc.2008.vv
URL: http://d.pidgin.im/viewmtn/revision/info/2e652889513f0ea3dd9a66c1b8463c673fcb0d72
Modified files:
libpurple/protocols/jabber/iq.c
libpurple/protocols/jabber/jabber.c
libpurple/protocols/jabber/jabber.h
libpurple/protocols/jabber/jingle.c
libpurple/protocols/jabber/jingle.h
ChangeLog:
Moved Jingle message handlers from jabber.c to jingle.c.
-------------- next part --------------
============================================================
--- libpurple/protocols/jabber/iq.c 7a607f60a3ed869e0e1cd7f078f7040b0c2ad13b
+++ libpurple/protocols/jabber/iq.c 7f63385edddedba271c2eae006fc343ee8dec510
@@ -28,6 +28,7 @@
#include "disco.h"
#include "google.h"
#include "iq.h"
+#include "jingle.h"
#include "oob.h"
#include "roster.h"
#include "si.h"
@@ -368,16 +369,16 @@ void jabber_iq_parse(JabberStream *js, x
purple_debug_info("jabber", "got Jingle package action = %s\n",
action);
if (!strcmp(action, "session-initiate")) {
- jabber_handle_session_initiate(js, packet);
+ jabber_jingle_session_handle_session_initiate(js, packet);
} else if (!strcmp(action, "session-accept")
|| !strcmp(action, "content-accept")) {
- jabber_handle_session_accept(js, packet);
+ jabber_jingle_session_handle_session_accept(js, packet);
} else if (!strcmp(action, "session-terminate")) {
- jabber_handle_session_terminate(js, packet);
+ jabber_jingle_session_handle_session_terminate(js, packet);
} else if (!strcmp(action, "transport-info")) {
- jabber_handle_session_candidates(js, packet);
+ jabber_jingle_session_handle_transport_info(js, packet);
} else if (!strcmp(action, "content-replace")) {
- jabber_handle_session_content_replace(js, packet);
+ jabber_jingle_session_handle_content_replace(js, packet);
}
return;
============================================================
--- libpurple/protocols/jabber/jabber.c 922014ad3970f8eddeea38b52e6a2e7785a3d913
+++ libpurple/protocols/jabber/jabber.c ed2fa2eeed0d27193fd2dbe4f66df24958dd4777
@@ -2382,264 +2382,11 @@ gboolean jabber_offline_message(const Pu
#ifdef USE_VV
-static void
-jabber_session_send_accept(JingleSession *session)
-{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_session_accept(session);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
-
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
- purple_debug_info("jabber", "Sent session accept, starting stream\n");
- gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
-
- session->session_started = TRUE;
-}
-
-static void
-jabber_session_send_content_accept(JingleSession *session)
-{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_content_accept(session);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
-
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
-}
-
-static void
-jabber_session_send_reject(JingleSession *session)
-{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_terminate(session,
- "decline", NULL);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
- jabber_jingle_session_destroy(session);
-}
-
-static void
-jabber_session_send_terminate(JingleSession *session)
-{
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_terminate(session,
- "no-error", NULL);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
- jabber_jingle_session_destroy(session);
-}
-
-/* callback called when new local transport candidate(s) are available on the
- Farsight stream */
-static void
-jabber_session_candidates_prepared(PurpleMedia *media, JingleSession *session)
-{
- if (!jabber_jingle_session_is_initiator(session)) {
- /* create transport-info package */
- JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
- JABBER_IQ_SET);
- xmlnode *jingle = jabber_jingle_session_create_transport_info(session);
- purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
- g_list_length(purple_media_get_local_audio_candidates(session->media)));
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
-
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
- }
-}
-
-/* callback called when a pair of transport candidates (local and remote)
- has been established */
-static void
-jabber_session_candidate_pair_established(PurpleMedia *media,
- FsCandidate *native_candidate,
- FsCandidate *remote_candidate,
- JingleSession *session)
-{
- purple_debug_info("jabber", "jabber_candidate_pair_established called\n");
- /* if we are the initiator, we should send a content-modify message */
- if (jabber_jingle_session_is_initiator(session)) {
- JabberIq *result;
- xmlnode *jingle;
-
- purple_debug_info("jabber", "we are the initiator, let's send content-modify\n");
-
- result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
-
- /* shall change this to a "content-replace" */
- jingle =
- jabber_jingle_session_create_content_replace(session,
- native_candidate,
- remote_candidate);
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
- }
-}
-
-static gboolean
-jabber_initiate_media_internal(JingleSession *session, const char *initiator, const char *remote_jid)
-{
- PurpleMedia *media = NULL;
-
- media = purple_media_manager_create_media(purple_media_manager_get(),
- session->js->gc, "fsrtpconference", remote_jid);
-
- if (!media) {
- purple_debug_error("jabber", "Couldn't create fsrtpconference\n");
- return FALSE;
- }
-
- /* this will need to be changed to "nice" once the libnice transmitter is finished */
- if (!purple_media_add_stream(media, remote_jid, PURPLE_MEDIA_AUDIO, "rawudp")) {
- purple_debug_error("jabber", "Couldn't create audio stream\n");
- purple_media_reject(media);
- return FALSE;
- }
-
- jabber_jingle_session_set_remote_jid(session, remote_jid);
- jabber_jingle_session_set_initiator(session, initiator);
- jabber_jingle_session_set_media(session, media);
-
- /* connect callbacks */
- g_signal_connect_swapped(G_OBJECT(media), "accepted",
- G_CALLBACK(jabber_session_send_accept), session);
- g_signal_connect_swapped(G_OBJECT(media), "reject",
- G_CALLBACK(jabber_session_send_reject), session);
- g_signal_connect_swapped(G_OBJECT(media), "hangup",
- G_CALLBACK(jabber_session_send_terminate), session);
- g_signal_connect(G_OBJECT(media), "candidates-prepared",
- G_CALLBACK(jabber_session_candidates_prepared), session);
- g_signal_connect(G_OBJECT(media), "candidate-pair",
- G_CALLBACK(jabber_session_candidate_pair_established), session);
-
- purple_media_ready(media);
-
- return TRUE;
-}
-
-static void
-jabber_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
-{
- const char *from = xmlnode_get_attrib(packet, "from");
- JingleSession *session = jabber_jingle_session_find_by_jid(js, from);
- PurpleMedia *media = session->media;
- JabberIq *result;
- xmlnode *jingle;
-
- if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) {
- purple_media_got_hangup(media);
- return;
- }
-
- /* catch errors */
- if (xmlnode_get_child(packet, "error")) {
- purple_media_got_hangup(media);
- return;
- }
-
- /* create transport-info package */
- result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
- jingle = jabber_jingle_session_create_transport_info(session);
- purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
- g_list_length(purple_media_get_local_audio_candidates(session->media)));
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
-
- xmlnode_insert_child(result->node, jingle);
- jabber_iq_send(result);
-}
-
PurpleMedia *
jabber_initiate_media(PurpleConnection *gc, const char *who,
- PurpleMediaStreamType type)
+ PurpleMediaStreamType type)
{
- /* create content negotiation */
- JabberStream *js = gc->proto_data;
- JabberIq *request = jabber_iq_new(js, JABBER_IQ_SET);
- xmlnode *jingle, *content, *description, *transport;
- GList *codecs;
- JingleSession *session;
- JabberBuddy *jb;
- JabberBuddyResource *jbr;
-
- char *jid = NULL, *me = NULL;
-
- /* construct JID to send to */
- jb = jabber_buddy_find(js, who, FALSE);
- if (!jb) {
- purple_debug_error("jabber", "Could not find Jabber buddy\n");
- return NULL;
- }
- jbr = jabber_buddy_find_resource(jb, NULL);
- if (!jbr) {
- purple_debug_error("jabber", "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);
- }
-
- session = jabber_jingle_session_create(js);
- /* set ourselves as initiator */
- me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
-
- if (!jabber_initiate_media_internal(session, me, jid)) {
- g_free(jid);
- g_free(me);
- jabber_jingle_session_destroy(session);
- return NULL;
- }
-
- g_free(jid);
- g_free(me);
-
- codecs = purple_media_get_local_audio_codecs(session->media);
-
- /* create request */
-
- xmlnode_set_attrib(request->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- jingle = xmlnode_new_child(request->node, "jingle");
- xmlnode_set_namespace(jingle, "urn:xmpp:tmp:jingle");
- xmlnode_set_attrib(jingle, "action", "session-initiate");
- /* get our JID and a session id... */
- xmlnode_set_attrib(jingle, "initiator", jabber_jingle_session_get_initiator(session));
- xmlnode_set_attrib(jingle, "sid", jabber_jingle_session_get_id(session));
-
- content = xmlnode_new_child(jingle, "content");
- xmlnode_set_attrib(content, "name", "audio-content");
- xmlnode_set_attrib(content, "profile", "RTP/AVP");
-
- description = jabber_jingle_session_create_description(session);
- xmlnode_insert_child(content, description);
-
- transport = xmlnode_new_child(content, "transport");
- xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
-
- jabber_iq_set_callback(request, jabber_session_initiate_result_cb, NULL);
-
- /* send request to other part */
- jabber_iq_send(request);
-
- fs_codec_list_destroy(codecs);
-
- return session->media;
+ return jabber_jingle_session_initiate_media(gc, who, type);
}
gboolean jabber_can_do_media(PurpleConnection *gc, const char *who,
@@ -2685,234 +2432,6 @@ gboolean jabber_can_do_media(PurpleConne
return FALSE;
}
-
-void
-jabber_handle_session_accept(JabberStream *js, xmlnode *packet)
-{
- JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- xmlnode *content = xmlnode_get_child(jingle, "content");
- const char *sid = xmlnode_get_attrib(jingle, "sid");
- const char *action = xmlnode_get_attrib(jingle, "action");
- JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
- GList *remote_codecs = NULL;
- GList *remote_transports = NULL;
- GList *codec_intersection;
- FsCodec *top = NULL;
- xmlnode *description = NULL;
- xmlnode *transport = NULL;
-
- /* We should probably check validity of the incoming XML... */
-
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
-
- description = xmlnode_get_child(content, "description");
- transport = xmlnode_get_child(content, "transport");
-
- /* fetch codecs from remote party */
- purple_debug_info("jabber", "get codecs from session-accept\n");
- remote_codecs = jabber_jingle_get_codecs(description);
- purple_debug_info("jabber", "get transport candidates from session accept\n");
- remote_transports = jabber_jingle_get_candidates(transport);
-
- purple_debug_info("jabber", "Got %d codecs from responder\n",
- g_list_length(remote_codecs));
- purple_debug_info("jabber", "Got %d transport candidates from responder\n",
- g_list_length(remote_transports));
-
- purple_debug_info("jabber", "Setting remote codecs on stream\n");
-
- purple_media_set_remote_audio_codecs(session->media,
- jabber_jingle_session_get_remote_jid(session),
- remote_codecs);
-
- codec_intersection = purple_media_get_negotiated_audio_codecs(session->media);
- purple_debug_info("jabber", "codec_intersection contains %d elems\n",
- g_list_length(codec_intersection));
- /* get the top codec */
- if (g_list_length(codec_intersection) > 0) {
- top = (FsCodec *) codec_intersection->data;
- purple_debug_info("jabber", "Found a suitable codec on stream = %d\n",
- top->id);
-
- /* we have found a suitable codec, but we will not start the stream
- just yet, wait for transport negotiation to complete... */
- }
- /* if we also got transport candidates, add them to our streams
- list of known remote candidates */
- if (g_list_length(remote_transports) > 0) {
- purple_media_add_remote_audio_candidates(session->media,
- jabber_jingle_session_get_remote_jid(session),
- remote_transports);
- fs_candidate_list_destroy(remote_transports);
- }
- if (g_list_length(codec_intersection) == 0 &&
- g_list_length(remote_transports)) {
- /* we didn't get any candidates and the codec intersection is empty,
- this means this was not a content-accept message and we couldn't
- find any suitable codecs, should return error and hang up */
-
- }
-
- g_list_free(codec_intersection);
-
- if (!strcmp(action, "session-accept")) {
- purple_media_got_accept(jabber_jingle_session_get_media(session));
- purple_debug_info("jabber", "Got session-accept, starting stream\n");
- gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
- }
-
- jabber_iq_send(result);
-
- session->session_started = TRUE;
-}
-
-void
-jabber_handle_session_terminate(JabberStream *js, xmlnode *packet)
-{
- JabberIq *result = jabber_iq_new(js, JABBER_IQ_SET);
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- const char *sid = xmlnode_get_attrib(jingle, "sid");
- JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
-
- if(!session) {
- purple_debug_error("jabber", "jabber_handle_session_terminate couldn't find session\n");
- return;
- }
-
- xmlnode_set_attrib(result->node, "to",
- jabber_jingle_session_get_remote_jid(session));
- xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
-
-
-
- /* maybe we should look at the reasoncode to determine if it was
- a hangup or a reject, and call different callbacks to purple_media */
- gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_NULL);
-
- purple_media_got_hangup(jabber_jingle_session_get_media(session));
- jabber_iq_send(result);
- jabber_jingle_session_destroy(session);
-}
-
-void
-jabber_handle_session_candidates(JabberStream *js, xmlnode *packet)
-{
- JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- xmlnode *content = xmlnode_get_child(jingle, "content");
- xmlnode *transport = xmlnode_get_child(content, "transport");
- GList *remote_candidates = jabber_jingle_get_candidates(transport);
- const char *sid = xmlnode_get_attrib(jingle, "sid");
- JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
-
- if(!session)
- purple_debug_error("jabber", "jabber_handle_session_candidates couldn't find session\n");
-
- /* send acknowledement */
- xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
- jabber_iq_send(result);
-
- /* add candidates to our list of remote candidates */
- if (g_list_length(remote_candidates) > 0) {
- purple_media_add_remote_audio_candidates(session->media,
- xmlnode_get_attrib(packet, "from"),
- remote_candidates);
- fs_candidate_list_destroy(remote_candidates);
- }
-}
-
-/* change this to content-replace */
-void
-jabber_handle_session_content_replace(JabberStream *js, xmlnode *packet)
-{
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- const char *sid = xmlnode_get_attrib(jingle, "sid");
- JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
-
- if (!jabber_jingle_session_is_initiator(session) && session->session_started) {
- JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
- JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET);
- xmlnode *content_accept = NULL;
-
- /* send acknowledement */
- xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
- jabber_iq_send(result);
-
- /* send content-accept */
- content_accept = jabber_jingle_session_create_content_accept(session);
- xmlnode_set_attrib(accept->node, "id", xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(accept->node, "to", xmlnode_get_attrib(packet, "from"));
- xmlnode_insert_child(accept->node, content_accept);
-
- jabber_iq_send(accept);
- }
-}
-
-void
-jabber_handle_session_initiate(JabberStream *js, xmlnode *packet)
-{
- JingleSession *session = NULL;
- xmlnode *jingle = xmlnode_get_child(packet, "jingle");
- xmlnode *content = NULL;
- xmlnode *description = NULL;
- const char *sid = NULL;
- const char *initiator = NULL;
- GList *codecs = NULL;
- JabberIq *result = NULL;
-
- if (!jingle) {
- purple_debug_error("jabber", "Malformed request");
- return;
- }
-
- sid = xmlnode_get_attrib(jingle, "sid");
- initiator = xmlnode_get_attrib(jingle, "initiator");
-
- if (jabber_jingle_session_find_by_id(js, sid)) {
- /* This should only happen if you start a session with yourself */
- purple_debug_error("jabber", "Jingle session with id={%s} already exists\n", sid);
- return;
- }
- session = jabber_jingle_session_create_by_id(js, sid);
-
- /* init media */
- content = xmlnode_get_child(jingle, "content");
- if (!content) {
- purple_debug_error("jabber", "jingle tag must contain content tag\n");
- /* should send error here */
- return;
- }
-
- description = xmlnode_get_child(content, "description");
-
- if (!description) {
- purple_debug_error("jabber", "content tag must contain description tag\n");
- /* we should create an error iq here */
- return;
- }
-
- if (!jabber_initiate_media_internal(session, initiator, initiator)) {
- purple_debug_error("jabber", "Couldn't start media session with %s\n", initiator);
- jabber_jingle_session_destroy(session);
- /* we should create an error iq here */
- return;
- }
-
- codecs = jabber_jingle_get_codecs(description);
-
- purple_media_set_remote_audio_codecs(session->media, initiator, codecs);
-
- result = jabber_iq_new(js, JABBER_IQ_RESULT);
- jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
- xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
- jabber_iq_send(result);
-}
-
#endif
void jabber_register_commands(void)
============================================================
--- libpurple/protocols/jabber/jabber.h 29e84f9799d5342e1efa3ed2fe7695e9409eea45
+++ libpurple/protocols/jabber/jabber.h c00fd6dca4543d57ad1c24eee013e58eb4e38e09
@@ -278,14 +278,6 @@ gboolean jabber_can_do_media(PurpleConne
#ifdef USE_VV
PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, PurpleMediaStreamType type);
gboolean jabber_can_do_media(PurpleConnection *gc, const char *who, PurpleMediaStreamType type);
-
-/* Jingle handle session messages */
-void jabber_handle_session_initiate(JabberStream *js, xmlnode *packet);
-void jabber_handle_session_accept(JabberStream *js, xmlnode *packet);
-void jabber_handle_session_terminate(JabberStream *js, xmlnode *packet);
-void jabber_handle_session_candidates(JabberStream *js, xmlnode *packet);
-void jabber_handle_session_content_replace(JabberStream *js, xmlnode *packet);
-
#endif
#endif /* _PURPLE_JABBER_H_ */
============================================================
--- libpurple/protocols/jabber/jingle.c 87806795592d1b81365a624f4bdd3a948afe5525
+++ libpurple/protocols/jabber/jingle.c 945f8c9f72e5ef30faf7d46eb9d26377c341dd67
@@ -21,6 +21,7 @@
#include "purple.h"
#include "jingle.h"
#include "xmlnode.h"
+#include "iq.h"
#include <stdlib.h>
#include <string.h>
@@ -487,4 +488,492 @@ jabber_jingle_session_create_content_acc
return jingle;
}
+static void
+jabber_jingle_session_send_content_accept(JingleSession *session)
+{
+ JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+ JABBER_IQ_SET);
+ xmlnode *jingle = jabber_jingle_session_create_content_accept(session);
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+}
+
+static void
+jabber_jingle_session_send_session_accept(JingleSession *session)
+{
+ JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+ JABBER_IQ_SET);
+ xmlnode *jingle = jabber_jingle_session_create_session_accept(session);
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+ purple_debug_info("jabber", "Sent session accept, starting stream\n");
+ gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
+
+ session->session_started = TRUE;
+}
+
+static void
+jabber_jingle_session_send_session_reject(JingleSession *session)
+{
+ JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+ JABBER_IQ_SET);
+ xmlnode *jingle = jabber_jingle_session_create_terminate(session,
+ "decline", NULL);
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+ jabber_jingle_session_destroy(session);
+}
+
+static void
+jabber_jingle_session_send_session_terminate(JingleSession *session)
+{
+ JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+ JABBER_IQ_SET);
+ xmlnode *jingle = jabber_jingle_session_create_terminate(session,
+ "no-error", NULL);
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+ jabber_jingle_session_destroy(session);
+}
+
+/* callback called when new local transport candidate(s) are available on the
+ Farsight stream */
+static void
+jabber_jingle_session_candidates_prepared(PurpleMedia *media, JingleSession *session)
+{
+ if (!jabber_jingle_session_is_initiator(session)) {
+ /* create transport-info package */
+ JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session),
+ JABBER_IQ_SET);
+ xmlnode *jingle = jabber_jingle_session_create_transport_info(session);
+ purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
+ g_list_length(purple_media_get_local_audio_candidates(session->media)));
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+ }
+}
+
+/* callback called when a pair of transport candidates (local and remote)
+ has been established */
+static void
+jabber_jingle_session_candidate_pair_established(PurpleMedia *media,
+ FsCandidate *native_candidate,
+ FsCandidate *remote_candidate,
+ JingleSession *session)
+{
+ purple_debug_info("jabber", "jabber_candidate_pair_established called\n");
+ /* if we are the initiator, we should send a content-modify message */
+ if (jabber_jingle_session_is_initiator(session)) {
+ JabberIq *result;
+ xmlnode *jingle;
+
+ purple_debug_info("jabber", "we are the initiator, let's send content-modify\n");
+
+ result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
+
+ /* shall change this to a "content-replace" */
+ jingle = jabber_jingle_session_create_content_replace(session,
+ native_candidate,
+ remote_candidate);
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+ }
+}
+
+static gboolean
+jabber_jingle_session_initiate_media_internal(JingleSession *session,
+ const char *initiator,
+ const char *remote_jid)
+{
+ PurpleMedia *media = NULL;
+
+ media = purple_media_manager_create_media(purple_media_manager_get(),
+ session->js->gc, "fsrtpconference", remote_jid);
+
+ if (!media) {
+ purple_debug_error("jabber", "Couldn't create fsrtpconference\n");
+ return FALSE;
+ }
+
+ /* this will need to be changed to "nice" once the libnice transmitter is finished */
+ if (!purple_media_add_stream(media, remote_jid, PURPLE_MEDIA_AUDIO, "rawudp")) {
+ purple_debug_error("jabber", "Couldn't create audio stream\n");
+ purple_media_reject(media);
+ return FALSE;
+ }
+
+ jabber_jingle_session_set_remote_jid(session, remote_jid);
+ jabber_jingle_session_set_initiator(session, initiator);
+ jabber_jingle_session_set_media(session, media);
+
+ /* connect callbacks */
+ g_signal_connect_swapped(G_OBJECT(media), "accepted",
+ G_CALLBACK(jabber_jingle_session_send_session_accept), session);
+ g_signal_connect_swapped(G_OBJECT(media), "reject",
+ G_CALLBACK(jabber_jingle_session_send_session_reject), session);
+ g_signal_connect_swapped(G_OBJECT(media), "hangup",
+ G_CALLBACK(jabber_jingle_session_send_session_terminate), session);
+ g_signal_connect(G_OBJECT(media), "candidates-prepared",
+ G_CALLBACK(jabber_jingle_session_candidates_prepared), session);
+ g_signal_connect(G_OBJECT(media), "candidate-pair",
+ G_CALLBACK(jabber_jingle_session_candidate_pair_established), session);
+
+ purple_media_ready(media);
+
+ return TRUE;
+}
+
+static void
+jabber_jingle_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+ const char *from = xmlnode_get_attrib(packet, "from");
+ JingleSession *session = jabber_jingle_session_find_by_jid(js, from);
+ PurpleMedia *media = session->media;
+ JabberIq *result;
+ xmlnode *jingle;
+
+ if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) {
+ purple_media_got_hangup(media);
+ return;
+ }
+
+ /* catch errors */
+ if (xmlnode_get_child(packet, "error")) {
+ purple_media_got_hangup(media);
+ return;
+ }
+
+ /* create transport-info package */
+ result = jabber_iq_new(jabber_jingle_session_get_js(session), JABBER_IQ_SET);
+ jingle = jabber_jingle_session_create_transport_info(session);
+ purple_debug_info("jabber", "jabber_session_candidates_prepared: %d candidates\n",
+ g_list_length(purple_media_get_local_audio_candidates(session->media)));
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+
+ xmlnode_insert_child(result->node, jingle);
+ jabber_iq_send(result);
+}
+
+PurpleMedia *
+jabber_jingle_session_initiate_media(PurpleConnection *gc, const char *who,
+ PurpleMediaStreamType type)
+{
+ /* create content negotiation */
+ JabberStream *js = gc->proto_data;
+ JabberIq *request = jabber_iq_new(js, JABBER_IQ_SET);
+ xmlnode *jingle, *content, *description, *transport;
+ GList *codecs;
+ JingleSession *session;
+ JabberBuddy *jb;
+ JabberBuddyResource *jbr;
+
+ char *jid = NULL, *me = NULL;
+
+ /* construct JID to send to */
+ jb = jabber_buddy_find(js, who, FALSE);
+ if (!jb) {
+ purple_debug_error("jabber", "Could not find Jabber buddy\n");
+ return NULL;
+ }
+ jbr = jabber_buddy_find_resource(jb, NULL);
+ if (!jbr) {
+ purple_debug_error("jabber", "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);
+ }
+
+ session = jabber_jingle_session_create(js);
+ /* set ourselves as initiator */
+ me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource);
+
+ if (!jabber_jingle_session_initiate_media_internal(session, me, jid)) {
+ g_free(jid);
+ g_free(me);
+ jabber_jingle_session_destroy(session);
+ return NULL;
+ }
+
+ g_free(jid);
+ g_free(me);
+
+ codecs = purple_media_get_local_audio_codecs(session->media);
+
+ /* create request */
+
+ xmlnode_set_attrib(request->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ jingle = xmlnode_new_child(request->node, "jingle");
+ xmlnode_set_namespace(jingle, "urn:xmpp:tmp:jingle");
+ xmlnode_set_attrib(jingle, "action", "session-initiate");
+ /* get our JID and a session id... */
+ xmlnode_set_attrib(jingle, "initiator", jabber_jingle_session_get_initiator(session));
+ xmlnode_set_attrib(jingle, "sid", jabber_jingle_session_get_id(session));
+
+ content = xmlnode_new_child(jingle, "content");
+ xmlnode_set_attrib(content, "name", "audio-content");
+ xmlnode_set_attrib(content, "profile", "RTP/AVP");
+
+ description = jabber_jingle_session_create_description(session);
+ xmlnode_insert_child(content, description);
+
+ transport = xmlnode_new_child(content, "transport");
+ xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp");
+
+ jabber_iq_set_callback(request, jabber_jingle_session_initiate_result_cb, NULL);
+
+ /* send request to other part */
+ jabber_iq_send(request);
+
+ fs_codec_list_destroy(codecs);
+
+ return session->media;
+}
+
+void
+jabber_jingle_session_handle_content_replace(JabberStream *js, xmlnode *packet)
+{
+ xmlnode *jingle = xmlnode_get_child(packet, "jingle");
+ const char *sid = xmlnode_get_attrib(jingle, "sid");
+ JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+ if (!jabber_jingle_session_is_initiator(session) && session->session_started) {
+ JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET);
+ xmlnode *content_accept = NULL;
+
+ /* send acknowledement */
+ xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+ xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
+ jabber_iq_send(result);
+
+ /* send content-accept */
+ content_accept = jabber_jingle_session_create_content_accept(session);
+ xmlnode_set_attrib(accept->node, "id", xmlnode_get_attrib(packet, "id"));
+ xmlnode_set_attrib(accept->node, "to", xmlnode_get_attrib(packet, "from"));
+ xmlnode_insert_child(accept->node, content_accept);
+
+ jabber_iq_send(accept);
+ }
+}
+
+void
+jabber_jingle_session_handle_session_accept(JabberStream *js, xmlnode *packet)
+{
+ JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ xmlnode *jingle = xmlnode_get_child(packet, "jingle");
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ const char *sid = xmlnode_get_attrib(jingle, "sid");
+ const char *action = xmlnode_get_attrib(jingle, "action");
+ JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+ GList *remote_codecs = NULL;
+ GList *remote_transports = NULL;
+ GList *codec_intersection;
+ FsCodec *top = NULL;
+ xmlnode *description = NULL;
+ xmlnode *transport = NULL;
+
+ /* We should probably check validity of the incoming XML... */
+
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+
+ description = xmlnode_get_child(content, "description");
+ transport = xmlnode_get_child(content, "transport");
+
+ /* fetch codecs from remote party */
+ purple_debug_info("jabber", "get codecs from session-accept\n");
+ remote_codecs = jabber_jingle_get_codecs(description);
+ purple_debug_info("jabber", "get transport candidates from session accept\n");
+ remote_transports = jabber_jingle_get_candidates(transport);
+
+ purple_debug_info("jabber", "Got %d codecs from responder\n",
+ g_list_length(remote_codecs));
+ purple_debug_info("jabber", "Got %d transport candidates from responder\n",
+ g_list_length(remote_transports));
+
+ purple_debug_info("jabber", "Setting remote codecs on stream\n");
+
+ purple_media_set_remote_audio_codecs(session->media,
+ jabber_jingle_session_get_remote_jid(session),
+ remote_codecs);
+
+ codec_intersection = purple_media_get_negotiated_audio_codecs(session->media);
+ purple_debug_info("jabber", "codec_intersection contains %d elems\n",
+ g_list_length(codec_intersection));
+ /* get the top codec */
+ if (g_list_length(codec_intersection) > 0) {
+ top = (FsCodec *) codec_intersection->data;
+ purple_debug_info("jabber", "Found a suitable codec on stream = %d\n",
+ top->id);
+
+ /* we have found a suitable codec, but we will not start the stream
+ just yet, wait for transport negotiation to complete... */
+ }
+ /* if we also got transport candidates, add them to our streams
+ list of known remote candidates */
+ if (g_list_length(remote_transports) > 0) {
+ purple_media_add_remote_audio_candidates(session->media,
+ jabber_jingle_session_get_remote_jid(session),
+ remote_transports);
+ fs_candidate_list_destroy(remote_transports);
+ }
+ if (g_list_length(codec_intersection) == 0 &&
+ g_list_length(remote_transports)) {
+ /* we didn't get any candidates and the codec intersection is empty,
+ this means this was not a content-accept message and we couldn't
+ find any suitable codecs, should return error and hang up */
+
+ }
+
+ g_list_free(codec_intersection);
+
+ if (!strcmp(action, "session-accept")) {
+ purple_media_got_accept(jabber_jingle_session_get_media(session));
+ purple_debug_info("jabber", "Got session-accept, starting stream\n");
+ gst_element_set_state(purple_media_get_audio_pipeline(session->media),
+ GST_STATE_PLAYING);
+ }
+
+ jabber_iq_send(result);
+
+ session->session_started = TRUE;
+}
+
+void
+jabber_jingle_session_handle_session_initiate(JabberStream *js, xmlnode *packet)
+{
+ JingleSession *session = NULL;
+ xmlnode *jingle = xmlnode_get_child(packet, "jingle");
+ xmlnode *content = NULL;
+ xmlnode *description = NULL;
+ const char *sid = NULL;
+ const char *initiator = NULL;
+ GList *codecs = NULL;
+ JabberIq *result = NULL;
+
+ if (!jingle) {
+ purple_debug_error("jabber", "Malformed request");
+ return;
+ }
+
+ sid = xmlnode_get_attrib(jingle, "sid");
+ initiator = xmlnode_get_attrib(jingle, "initiator");
+
+ if (jabber_jingle_session_find_by_id(js, sid)) {
+ /* This should only happen if you start a session with yourself */
+ purple_debug_error("jabber", "Jingle session with id={%s} already exists\n", sid);
+ return;
+ }
+ session = jabber_jingle_session_create_by_id(js, sid);
+
+ /* init media */
+ content = xmlnode_get_child(jingle, "content");
+ if (!content) {
+ purple_debug_error("jabber", "jingle tag must contain content tag\n");
+ /* should send error here */
+ return;
+ }
+
+ description = xmlnode_get_child(content, "description");
+
+ if (!description) {
+ purple_debug_error("jabber", "content tag must contain description tag\n");
+ /* we should create an error iq here */
+ return;
+ }
+
+ if (!jabber_jingle_session_initiate_media_internal(session, initiator, initiator)) {
+ purple_debug_error("jabber", "Couldn't start media session with %s\n", initiator);
+ jabber_jingle_session_destroy(session);
+ /* we should create an error iq here */
+ return;
+ }
+
+ codecs = jabber_jingle_get_codecs(description);
+
+ purple_media_set_remote_audio_codecs(session->media, initiator, codecs);
+
+ result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+ xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
+ jabber_iq_send(result);
+}
+
+void
+jabber_jingle_session_handle_session_terminate(JabberStream *js, xmlnode *packet)
+{
+ JabberIq *result = jabber_iq_new(js, JABBER_IQ_SET);
+ xmlnode *jingle = xmlnode_get_child(packet, "jingle");
+ const char *sid = xmlnode_get_attrib(jingle, "sid");
+ JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+ if (!session) {
+ purple_debug_error("jabber", "jabber_handle_session_terminate couldn't find session\n");
+ return;
+ }
+
+ xmlnode_set_attrib(result->node, "to",
+ jabber_jingle_session_get_remote_jid(session));
+ xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+
+
+
+ /* maybe we should look at the reasoncode to determine if it was
+ a hangup or a reject, and call different callbacks to purple_media */
+ gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_NULL);
+
+ purple_media_got_hangup(jabber_jingle_session_get_media(session));
+ jabber_iq_send(result);
+ jabber_jingle_session_destroy(session);
+}
+
+void
+jabber_jingle_session_handle_transport_info(JabberStream *js, xmlnode *packet)
+{
+ JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
+ xmlnode *jingle = xmlnode_get_child(packet, "jingle");
+ xmlnode *content = xmlnode_get_child(jingle, "content");
+ xmlnode *transport = xmlnode_get_child(content, "transport");
+ GList *remote_candidates = jabber_jingle_get_candidates(transport);
+ const char *sid = xmlnode_get_attrib(jingle, "sid");
+ JingleSession *session = jabber_jingle_session_find_by_id(js, sid);
+
+ if (!session)
+ purple_debug_error("jabber", "jabber_handle_session_candidates couldn't find session\n");
+
+ /* send acknowledement */
+ xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+ xmlnode_set_attrib(result->node, "to", xmlnode_get_attrib(packet, "from"));
+ jabber_iq_send(result);
+
+ /* add candidates to our list of remote candidates */
+ if (g_list_length(remote_candidates) > 0) {
+ purple_media_add_remote_audio_candidates(session->media,
+ xmlnode_get_attrib(packet, "from"),
+ remote_candidates);
+ fs_candidate_list_destroy(remote_candidates);
+ }
+}
+
#endif /* USE_VV */
============================================================
--- libpurple/protocols/jabber/jingle.h ba76ec08a4692526284147c9f0063e1786343bcf
+++ libpurple/protocols/jabber/jingle.h c20c28f4ddaeb3e76099f63fa4e33029f0c2fd69
@@ -85,6 +85,17 @@ GList *jabber_jingle_get_candidates(cons
GList *jabber_jingle_get_candidates(const xmlnode *transport);
+PurpleMedia *jabber_jingle_session_initiate_media(PurpleConnection *gc,
+ const char *who,
+ PurpleMediaStreamType type);
+
+/* Jingle message handlers */
+void jabber_jingle_session_handle_content_replace(JabberStream *js, xmlnode *packet);
+void jabber_jingle_session_handle_session_accept(JabberStream *js, xmlnode *packet);
+void jabber_jingle_session_handle_session_initiate(JabberStream *js, xmlnode *packet);
+void jabber_jingle_session_handle_session_terminate(JabberStream *js, xmlnode *packet);
+void jabber_jingle_session_handle_transport_info(JabberStream *js, xmlnode *packet);
+
G_END_DECLS
#endif /* USE_VV */
More information about the Commits
mailing list