# HG changeset patch # User Mike Ruprecht # Date 1211510552 0 # Node ID e1c8ec1259de544776f2955d3b1e967bed97993c # Parent 69d54f84350aa431155b9beb7d70b77c5c60e634 Updates voice and video to use Farsight 2, gets XMPP voice conferences closer to XEP-0167, and fixes a lot of bugs. diff -r 69d54f84350a -r e1c8ec1259de configure.ac --- a/configure.ac Sun Apr 13 17:53:46 2008 +0000 +++ b/configure.ac Fri May 23 02:42:32 2008 +0000 @@ -318,6 +318,9 @@ AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) +GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` +AC_SUBST(GLIB_GENMARSHAL) + AC_ARG_WITH([extraversion], AC_HELP_STRING([--with-extraversion=STRING], [extra version number to be displayed in Help->About and --help (for packagers)]), @@ -721,11 +724,11 @@ dnl ####################################################################### dnl # Check for Farsight dnl ####################################################################### -AC_ARG_ENABLE(farsight, +AC_ARG_ENABLE(farsight2, [AC_HELP_STRING([--disable-vv], [compile without voice and video support])], enable_farsight="$enableval", enable_farsight="yes") if test "x$enable_farsight" != "xno"; then - PKG_CHECK_MODULES(FARSIGHT, [farsight-0.1], [ + PKG_CHECK_MODULES(FARSIGHT, [farsight2-0.10], [ AC_DEFINE(USE_FARSIGHT, 1, [Use Farsight for voice and video]) AC_SUBST(FARSIGHT_CFLAGS) AC_SUBST(FARSIGHT_LIBS) diff -r 69d54f84350a -r e1c8ec1259de finch/gntmedia.c --- a/finch/gntmedia.c Sun Apr 13 17:53:46 2008 +0000 +++ b/finch/gntmedia.c Fri May 23 02:42:32 2008 +0000 @@ -42,8 +42,6 @@ /* An incredibly large part of the following is from gtkmedia.c */ #ifdef USE_FARSIGHT -#include - #undef hangup struct _FinchMediaPrivate diff -r 69d54f84350a -r e1c8ec1259de finch/gntmedia.h --- a/finch/gntmedia.h Sun Apr 13 17:53:46 2008 +0000 +++ b/finch/gntmedia.h Fri May 23 02:42:32 2008 +0000 @@ -33,7 +33,6 @@ #ifdef USE_FARSIGHT -#include #include #include "gntbox.h" diff -r 69d54f84350a -r e1c8ec1259de libpurple/Makefile.am --- a/libpurple/Makefile.am Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/Makefile.am Fri May 23 02:42:32 2008 +0000 @@ -1,6 +1,7 @@ EXTRA_DIST = \ dbus-analyze-functions.py \ dbus-analyze-types.py \ + marshallers.list \ purple-notifications-example \ purple-remote \ purple-send \ @@ -51,6 +52,7 @@ idle.c \ imgstore.c \ log.c \ + marshallers.c \ media.c \ mediamanager.c \ mime.c \ @@ -105,6 +107,7 @@ idle.h \ imgstore.h \ log.h \ + marshallers.h \ media.h \ mediamanager.h \ mime.h \ @@ -139,6 +142,14 @@ purple_builtheaders = purple.h version.h +marshallers.h: marshallers.list + @echo "Generating marshallers.h" + $(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --header > marshallers.h + +marshallers.c: marshallers.list + @echo "Generating marshallers.c" + $(GLIB_GENMARSHAL) --prefix=purple_smarshal $(srcdir)/marshallers.list --body > marshallers.c + if ENABLE_DBUS CLEANFILES = \ @@ -147,6 +158,8 @@ dbus-client-binding.h \ dbus-types.c \ dbus-types.h \ + marshallers.c \ + marshallers.h \ purple-client-bindings.c \ purple-client-bindings.h \ purple.service @@ -217,6 +230,8 @@ dbus-types.c \ dbus-types.h \ dbus-bindings.c \ + marshallers.c \ + marshallers.h \ purple-client-bindings.c \ purple-client-bindings.h diff -r 69d54f84350a -r e1c8ec1259de libpurple/marshallers.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/marshallers.list Fri May 23 02:42:32 2008 +0000 @@ -0,0 +1,1 @@ +VOID:BOXED,BOXED diff -r 69d54f84350a -r e1c8ec1259de libpurple/media.c --- a/libpurple/media.c Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/media.c Fri May 23 02:42:32 2008 +0000 @@ -29,6 +29,7 @@ #include "connection.h" #include "media.h" +#include "marshallers.h" #include "debug.h" @@ -36,11 +37,11 @@ #ifdef USE_GSTPROPS #include -#include +#include struct _PurpleMediaPrivate { - FarsightSession *farsight_session; + FsConference *conference; char *name; PurpleConnection *connection; @@ -49,8 +50,23 @@ GstElement *video_src; GstElement *video_sink; - FarsightStream *audio_stream; - FarsightStream *video_stream; + FsSession *audio_session; + FsSession *video_session; + + GList *participants; /* FsParticipant list */ + GList *audio_streams; /* FsStream list */ + GList *video_streams; /* FsStream list */ + + /* might be able to just combine these two */ + GstElement *audio_pipeline; + GstElement *video_pipeline; + + /* this will need to be stored/handled per stream + * once having multiple streams is supported */ + GList *local_candidates; + + FsCandidate *local_candidate; + FsCandidate *remote_candidate; }; #define PURPLE_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEDIA, PurpleMediaPrivate)) @@ -73,21 +89,23 @@ REJECT, GOT_HANGUP, GOT_ACCEPT, + CANDIDATES_PREPARED, + CANDIDATE_PAIR, LAST_SIGNAL }; static guint purple_media_signals[LAST_SIGNAL] = {0}; enum { PROP_0, - PROP_FARSIGHT_SESSION, + PROP_FS_CONFERENCE, PROP_NAME, PROP_CONNECTION, PROP_AUDIO_SRC, PROP_AUDIO_SINK, PROP_VIDEO_SRC, PROP_VIDEO_SINK, - PROP_VIDEO_STREAM, - PROP_AUDIO_STREAM + PROP_VIDEO_SESSION, + PROP_AUDIO_SESSION }; GType @@ -113,7 +131,6 @@ return type; } - static void purple_media_class_init (PurpleMediaClass *klass) { @@ -124,11 +141,11 @@ gobject_class->set_property = purple_media_set_property; gobject_class->get_property = purple_media_get_property; - g_object_class_install_property(gobject_class, PROP_FARSIGHT_SESSION, - g_param_spec_object("farsight-session", - "Farsight session", - "The FarsightSession associated with this media.", - FARSIGHT_TYPE_SESSION, + g_object_class_install_property(gobject_class, PROP_FS_CONFERENCE, + g_param_spec_object("farsight-conference", + "Farsight conference", + "The FsConference associated with this media.", + FS_TYPE_CONFERENCE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_object_class_install_property(gobject_class, PROP_NAME, @@ -172,18 +189,18 @@ GST_TYPE_ELEMENT, G_PARAM_READWRITE)); - g_object_class_install_property(gobject_class, PROP_VIDEO_STREAM, - g_param_spec_object("video-stream", + g_object_class_install_property(gobject_class, PROP_VIDEO_SESSION, + g_param_spec_object("video-session", "Video stream", "The FarsightStream used for video", - FARSIGHT_TYPE_STREAM, + FS_TYPE_SESSION, G_PARAM_READWRITE)); - g_object_class_install_property(gobject_class, PROP_AUDIO_STREAM, - g_param_spec_object("audio-stream", + g_object_class_install_property(gobject_class, PROP_AUDIO_SESSION, + g_param_spec_object("audio-session", "Audio stream", "The FarsightStream used for audio", - FARSIGHT_TYPE_STREAM, + FS_TYPE_SESSION, G_PARAM_READWRITE)); purple_media_signals[READY] = g_signal_new("ready", G_TYPE_FROM_CLASS(klass), @@ -214,6 +231,14 @@ G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + purple_media_signals[CANDIDATES_PREPARED] = g_signal_new("candidates-prepared", G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + purple_media_signals[CANDIDATE_PAIR] = g_signal_new("candidate-pair", G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + purple_smarshal_VOID__BOXED_BOXED, + G_TYPE_NONE, 2, FS_TYPE_CANDIDATE, FS_TYPE_CANDIDATE); g_type_class_add_private(klass, sizeof(PurpleMediaPrivate)); } @@ -241,11 +266,11 @@ media = PURPLE_MEDIA(object); switch (prop_id) { - case PROP_FARSIGHT_SESSION: - if (media->priv->farsight_session) - g_object_unref(media->priv->farsight_session); - media->priv->farsight_session = g_value_get_object(value); - g_object_ref(media->priv->farsight_session); + case PROP_FS_CONFERENCE: + if (media->priv->conference) + g_object_unref(media->priv->conference); + media->priv->conference = g_value_get_object(value); + g_object_ref(media->priv->conference); break; case PROP_NAME: g_free(media->priv->name); @@ -259,12 +284,16 @@ gst_object_unref(media->priv->audio_src); media->priv->audio_src = g_value_get_object(value); gst_object_ref(media->priv->audio_src); + gst_bin_add(GST_BIN(purple_media_get_audio_pipeline(media)), + media->priv->audio_src); break; case PROP_AUDIO_SINK: if (media->priv->audio_sink) gst_object_unref(media->priv->audio_sink); media->priv->audio_sink = g_value_get_object(value); gst_object_ref(media->priv->audio_sink); + gst_bin_add(GST_BIN(purple_media_get_audio_pipeline(media)), + media->priv->audio_sink); break; case PROP_VIDEO_SRC: if (media->priv->video_src) @@ -278,17 +307,17 @@ media->priv->video_sink = g_value_get_object(value); gst_object_ref(media->priv->video_sink); break; - case PROP_VIDEO_STREAM: - if (media->priv->video_stream) - g_object_unref(media->priv->video_stream); - media->priv->video_stream = g_value_get_object(value); - gst_object_ref(media->priv->video_stream); + case PROP_VIDEO_SESSION: + if (media->priv->video_session) + g_object_unref(media->priv->video_session); + media->priv->video_session = g_value_get_object(value); + gst_object_ref(media->priv->video_session); break; - case PROP_AUDIO_STREAM: - if (media->priv->audio_stream) - g_object_unref(media->priv->audio_stream); - media->priv->audio_stream = g_value_get_object(value); - gst_object_ref(media->priv->audio_stream); + case PROP_AUDIO_SESSION: + if (media->priv->audio_session) + g_object_unref(media->priv->audio_session); + media->priv->audio_session = g_value_get_object(value); + gst_object_ref(media->priv->audio_session); break; default: @@ -306,8 +335,8 @@ media = PURPLE_MEDIA(object); switch (prop_id) { - case PROP_FARSIGHT_SESSION: - g_value_set_object(value, media->priv->farsight_session); + case PROP_FS_CONFERENCE: + g_value_set_object(value, media->priv->conference); break; case PROP_NAME: g_value_set_string(value, media->priv->name); @@ -327,11 +356,11 @@ case PROP_VIDEO_SINK: g_value_set_object(value, media->priv->video_sink); break; - case PROP_VIDEO_STREAM: - g_value_set_object(value, media->priv->video_stream); + case PROP_VIDEO_SESSION: + g_value_set_object(value, media->priv->video_session); break; - case PROP_AUDIO_STREAM: - g_value_set_object(value, media->priv->audio_stream); + case PROP_AUDIO_SESSION: + g_value_set_object(value, media->priv->audio_session); break; default: @@ -415,12 +444,12 @@ GstElement * purple_media_get_audio_pipeline(PurpleMedia *media) { - FarsightStream *stream; - g_object_get(G_OBJECT(media), "audio-stream", &stream, NULL); -printf("stream: %d\n\n\n", stream); -GstElement *l = farsight_stream_get_pipeline(stream); -printf("Element: %d\n", l); - return farsight_stream_get_pipeline(stream); + if (!media->priv->audio_pipeline) { + media->priv->audio_pipeline = gst_pipeline_new(media->priv->name); + gst_bin_add(GST_BIN(media->priv->audio_pipeline), GST_ELEMENT(media->priv->conference)); + } + + return media->priv->audio_pipeline; } PurpleConnection * @@ -631,5 +660,237 @@ purple_debug_info("media", "purple_media_audio_init_recv end\n"); } +static void +purple_media_new_local_candidate(FsStream *stream, + FsCandidate *local_candidate, + PurpleMedia *media) +{ + purple_debug_info("media", "got new local candidate: %s\n", local_candidate->candidate_id); + media->priv->local_candidates = g_list_append(media->priv->local_candidates, + fs_candidate_copy(local_candidate)); +} + +static void +purple_media_candidates_prepared(FsStream *stream, PurpleMedia *media) +{ + g_signal_emit(media, purple_media_signals[CANDIDATES_PREPARED], 0); +} + +/* callback called when a pair of transport candidates (local and remote) + * has been established */ +static void +purple_media_candidate_pair_established(FsStream *stream, + FsCandidate *native_candidate, + FsCandidate *remote_candidate, + PurpleMedia *media) +{ + media->priv->local_candidate = fs_candidate_copy(native_candidate); + media->priv->remote_candidate = fs_candidate_copy(remote_candidate); + + purple_debug_info("media", "candidate pair established\n"); + g_signal_emit(media, purple_media_signals[CANDIDATE_PAIR], 0, + media->priv->local_candidate, + media->priv->remote_candidate); +} + +static void +purple_media_src_pad_added(FsStream *stream, GstPad *srcpad, + FsCodec *codec, PurpleMedia *media) +{ + GstElement *pipeline = purple_media_get_audio_pipeline(media); + GstPad *sinkpad = gst_element_get_static_pad(purple_media_get_audio_sink(media), "ghostsink"); + purple_debug_info("media", "connecting new src pad: %s\n", + gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK ? "success" : "failure"); + gst_element_set_state(pipeline, GST_STATE_PLAYING); +} + +static void +purple_media_add_stream_internal(PurpleMedia *media, FsSession **session, GList **streams, + GstElement *src, const gchar *who, FsMediaType type, + FsStreamDirection type_direction, const gchar *transmitter) +{ + char *cname = NULL; + FsParticipant *participant = NULL; + GList *l = NULL; + FsStream *stream = NULL; + FsParticipant *p = NULL; + FsStreamDirection *direction = NULL; + FsSession *s = NULL; + + if (!*session) { + *session = fs_conference_new_session(media->priv->conference, type, NULL); + if (src) { + GstPad *sinkpad; + GstPad *srcpad; + g_object_get(*session, "sink-pad", &sinkpad, NULL); + srcpad = gst_element_get_static_pad(src, "ghostsrc"); + purple_debug_info("media", "connecting pad: %s\n", + gst_pad_link(srcpad, sinkpad) == GST_PAD_LINK_OK + ? "success" : "failure"); + } + } + + for (l = media->priv->participants; l != NULL; l = g_list_next(l)) { + g_object_get(l->data, "cname", cname, NULL); + if (!strcmp(cname, who)) { + g_free(cname); + participant = l->data; + break; + } + g_free(cname); + } + + if (!participant) { + participant = fs_conference_new_participant(media->priv->conference, (gchar*)who, NULL); + media->priv->participants = g_list_prepend(media->priv->participants, participant); + } + + for (l = *streams; l != NULL; l = g_list_next(l)) { + g_object_get(l->data, "participant", &p, "direction", &direction, "session", &s, NULL); + + if (participant == p && *session == s) { + stream = l->data; + break; + } + } + + if (!stream) { + stream = fs_session_new_stream(*session, participant, + type_direction, transmitter, 0, NULL, NULL); + *streams = g_list_prepend(*streams, stream); + /* callback for new local candidate (new local candidate retreived) */ + g_signal_connect(G_OBJECT(stream), + "new-local-candidate", G_CALLBACK(purple_media_new_local_candidate), media); + /* callback for source pad added (new stream source ready) */ + g_signal_connect(G_OBJECT(stream), + "src-pad-added", G_CALLBACK(purple_media_src_pad_added), media); + /* callback for local candidates prepared (local candidates ready to send) */ + g_signal_connect(G_OBJECT(stream), + "local-candidates-prepared", + G_CALLBACK(purple_media_candidates_prepared), media); + /* callback for new active candidate pair (established connection) */ + g_signal_connect(G_OBJECT(stream), + "new-active-candidate-pair", + G_CALLBACK(purple_media_candidate_pair_established), media); + } else if (*direction != type_direction) { + /* change direction */ + g_object_set(stream, "direction", type_direction, NULL); + } +} + +void +purple_media_add_stream(PurpleMedia *media, const gchar *who, + PurpleMediaStreamType type, + const gchar *transmitter) +{ + FsStreamDirection type_direction; + + if (type & PURPLE_MEDIA_AUDIO) { + if (type & PURPLE_MEDIA_SEND_AUDIO && type & PURPLE_MEDIA_RECV_AUDIO) + type_direction = FS_DIRECTION_BOTH; + else if (type & PURPLE_MEDIA_SEND_AUDIO) + type_direction = FS_DIRECTION_SEND; + else if (type & PURPLE_MEDIA_RECV_AUDIO) + type_direction = FS_DIRECTION_RECV; + else + type_direction = FS_DIRECTION_NONE; + + purple_media_add_stream_internal(media, &media->priv->audio_session, + &media->priv->audio_streams, + media->priv->audio_src, who, + FS_MEDIA_TYPE_AUDIO, type_direction, + transmitter); + } + if (type & PURPLE_MEDIA_VIDEO) { + if (type & PURPLE_MEDIA_SEND_VIDEO && type & PURPLE_MEDIA_RECV_VIDEO) + type_direction = FS_DIRECTION_BOTH; + else if (type & PURPLE_MEDIA_SEND_VIDEO) + type_direction = FS_DIRECTION_SEND; + else if (type & PURPLE_MEDIA_RECV_VIDEO) + type_direction = FS_DIRECTION_RECV; + else + type_direction = FS_DIRECTION_NONE; + + purple_media_add_stream_internal(media, &media->priv->video_session, + &media->priv->video_streams, + media->priv->video_src, who, + FS_MEDIA_TYPE_VIDEO, type_direction, + transmitter); + } +} + +void +purple_media_remove_stream(PurpleMedia *media, const gchar *who, PurpleMediaStreamType type) +{ + +} + +static FsStream * +purple_media_get_audio_stream(PurpleMedia *media, const gchar *name) +{ + GList *streams = media->priv->audio_streams; + for (; streams; streams = streams->next) { + FsParticipant *participant; + gchar *cname; + g_object_get(streams->data, "participant", &participant, NULL); + g_object_get(participant, "cname", &cname, NULL); + + if (!strcmp(cname, name)) { + return streams->data; + } + } + + return NULL; +} + +GList * +purple_media_get_local_audio_codecs(PurpleMedia *media) +{ + GList *codecs; + g_object_get(G_OBJECT(media->priv->audio_session), "local-codecs", &codecs, NULL); + return codecs; +} + +GList * +purple_media_get_local_audio_candidates(PurpleMedia *media) +{ + return media->priv->local_candidates; +} + +GList * +purple_media_get_negotiated_audio_codecs(PurpleMedia *media) +{ + GList *codec_intersection; + g_object_get(media->priv->audio_session, "negotiated-codecs", &codec_intersection, NULL); + return codec_intersection; +} + +void +purple_media_add_remote_audio_candidates(PurpleMedia *media, const gchar *name, GList *remote_candidates) +{ + FsStream *stream = purple_media_get_audio_stream(media, name); + GList *candidates = remote_candidates; + for (; candidates; candidates = candidates->next) + fs_stream_add_remote_candidate(stream, candidates->data, NULL); +} + +FsCandidate * +purple_media_get_local_candidate(PurpleMedia *media) +{ + return media->priv->local_candidate; +} + +FsCandidate * +purple_media_get_remote_candidate(PurpleMedia *media) +{ + return media->priv->remote_candidate; +} + +void +purple_media_set_remote_audio_codecs(PurpleMedia *media, const gchar *name, GList *codecs) +{ + fs_stream_set_remote_codecs(purple_media_get_audio_stream(media, name), codecs, NULL); +} + #endif /* USE_GSTPROPS */ #endif /* USE_FARSIGHT */ diff -r 69d54f84350a -r e1c8ec1259de libpurple/media.h --- a/libpurple/media.h Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/media.h Fri May 23 02:42:32 2008 +0000 @@ -29,7 +29,9 @@ #ifdef USE_FARSIGHT #ifdef USE_GSTPROPS -#include +#include +#include +#include #include #include @@ -53,6 +55,8 @@ PURPLE_MEDIA_SEND_AUDIO = 1 << 1, PURPLE_MEDIA_RECV_VIDEO = 1 << 2, PURPLE_MEDIA_SEND_VIDEO = 1 << 3, + PURPLE_MEDIA_AUDIO = PURPLE_MEDIA_RECV_AUDIO | PURPLE_MEDIA_SEND_AUDIO, + PURPLE_MEDIA_VIDEO = PURPLE_MEDIA_RECV_VIDEO | PURPLE_MEDIA_SEND_VIDEO } PurpleMediaStreamType; struct _PurpleMediaClass @@ -109,6 +113,20 @@ void purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel); +void purple_media_add_stream(PurpleMedia *media, const gchar *who, + PurpleMediaStreamType type, const gchar *transmitter); +void purple_media_remove_stream(PurpleMedia *media, const gchar *who, PurpleMediaStreamType type); + +GList *purple_media_get_local_audio_candidates(PurpleMedia *media); +GList *purple_media_get_negotiated_audio_codecs(PurpleMedia *media); + +GList *purple_media_get_local_audio_codecs(PurpleMedia *media); +void purple_media_add_remote_audio_candidates(PurpleMedia *media, const gchar *name, + GList *remote_candidates); +FsCandidate *purple_media_get_local_candidate(PurpleMedia *media); +FsCandidate *purple_media_get_remote_candidate(PurpleMedia *media); +void purple_media_set_remote_audio_codecs(PurpleMedia *media, const gchar *name, GList *codecs); + G_END_DECLS #endif /* USE_GSTPROPS */ diff -r 69d54f84350a -r e1c8ec1259de libpurple/mediamanager.c --- a/libpurple/mediamanager.c Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/mediamanager.c Fri May 23 02:42:32 2008 +0000 @@ -31,7 +31,7 @@ #ifdef USE_FARSIGHT -#include +#include struct _PurpleMediaManagerPrivate { @@ -127,18 +127,19 @@ return manager; } -PurpleMedia* -purple_media_manager_create_media(PurpleMediaManager *manager, +PurpleMedia * +purple_media_manager_create_media(PurpleMediaManager *manager, PurpleConnection *gc, - const char *screenname, - FarsightStream *audio_stream, - FarsightStream *video_stream) + const char *conference_type, + const char *remote_user) { + FsConference *conference = FS_CONFERENCE(gst_element_factory_make(conference_type, NULL)); + PurpleMedia *media = PURPLE_MEDIA(g_object_new(purple_media_get_type(), - "screenname", screenname, + "screenname", remote_user, "connection", gc, - "audio-stream", audio_stream, - "video-stream", video_stream, NULL)); + "farsight-conference", conference, + NULL)); manager->priv->medias = g_list_append(manager->priv->medias, media); g_signal_emit(manager, purple_media_manager_signals[INIT_MEDIA], 0, media); return media; diff -r 69d54f84350a -r e1c8ec1259de libpurple/mediamanager.h --- a/libpurple/mediamanager.h Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/mediamanager.h Fri May 23 02:42:32 2008 +0000 @@ -28,7 +28,7 @@ #ifdef USE_FARSIGHT -#include +#include #include #include @@ -61,12 +61,10 @@ GType purple_media_manager_get_type(void); PurpleMediaManager *purple_media_manager_get(void); - PurpleMedia *purple_media_manager_create_media(PurpleMediaManager *manager, - PurpleConnection *gc, - const char *screenname, - FarsightStream *audio_stream, - FarsightStream *video_stream); + PurpleConnection *gc, + const char *conference_type, + const char *remote_user); G_END_DECLS diff -r 69d54f84350a -r e1c8ec1259de libpurple/protocols/jabber/google.c --- a/libpurple/protocols/jabber/google.c Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/protocols/jabber/google.c Fri May 23 02:42:32 2008 +0000 @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ -#include +#include #include "internal.h" #include "debug.h" @@ -49,7 +49,6 @@ GoogleSessionId id; GoogleSessionState state; PurpleMedia *media; - FarsightStream *stream; JabberStream *js; char *remote_jid; } GoogleSession; @@ -84,7 +83,6 @@ g_free(session->id.initiator); g_free(session->remote_jid); g_object_unref(session->media); - g_object_unref(session->stream); g_free(session); } @@ -103,7 +101,7 @@ google_session_send_accept(GoogleSession *session) { xmlnode *sess, *desc, *payload; - GList *codecs = farsight_stream_get_codec_intersection(session->stream); + GList *codecs = purple_media_get_negotiated_audio_codecs(session->media); JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); xmlnode_set_attrib(iq->node, "to", session->remote_jid); @@ -113,7 +111,7 @@ xmlnode_set_namespace(desc, "http://www.google.com/session/phone"); for (;codecs; codecs = codecs->next) { - FarsightCodec *codec = (FarsightCodec*)codecs->data; + FsCodec *codec = (FsCodec*)codecs->data; char id[8], clockrate[10]; payload = xmlnode_new_child(desc, "payload-type"); g_snprintf(id, sizeof(id), "%d", codec->id); @@ -123,15 +121,15 @@ xmlnode_set_attrib(payload, "clockrate", clockrate); } + fs_codec_list_destroy(codecs); jabber_iq_send(iq); - farsight_stream_start(session->stream); + gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING); } static void google_session_send_terminate(GoogleSession *session) { xmlnode *sess; - GList *codecs = farsight_stream_get_codec_intersection(session->stream); JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); xmlnode_set_attrib(iq->node, "to", session->remote_jid); @@ -139,7 +137,6 @@ xmlnode_insert_child(iq->node, sess); jabber_iq_send(iq); - farsight_stream_stop(session->stream); google_session_destroy(session); } @@ -147,7 +144,6 @@ google_session_send_reject(GoogleSession *session) { xmlnode *sess; - GList *codecs = farsight_stream_get_codec_intersection(session->stream); JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); xmlnode_set_attrib(iq->node, "to", session->remote_jid); @@ -155,17 +151,16 @@ xmlnode_insert_child(iq->node, sess); jabber_iq_send(iq); - farsight_stream_stop(session->stream); google_session_destroy(session); } static void -google_session_candidates_prepared (FarsightStream *stream, gchar *candidate_id, GoogleSession *session) +google_session_candidates_prepared (PurpleMedia *media, GoogleSession *session) { JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); - GList *candidates = farsight_stream_get_native_candidate_list(stream); - FarsightTransportInfo *transport; + GList *candidates = purple_media_get_local_audio_candidates(session->media); + FsCandidate *transport; xmlnode *sess; xmlnode *candidate; sess = google_session_create_xmlnode(session, "candidates"); @@ -173,9 +168,9 @@ xmlnode_set_attrib(iq->node, "to", session->remote_jid); for (;candidates;candidates = candidates->next) { - transport = (FarsightTransportInfo*)(candidates->data); char port[8]; char pref[8]; + transport = (FsCandidate*)(candidates->data); if (!strcmp(transport->ip, "127.0.0.1")) continue; @@ -183,7 +178,7 @@ candidate = xmlnode_new("candidate"); g_snprintf(port, sizeof(port), "%d", transport->port); - g_snprintf(pref, sizeof(pref), "%f", transport->preference); + g_snprintf(pref, sizeof(pref), "%d", transport->priority); xmlnode_set_attrib(candidate, "address", transport->ip); xmlnode_set_attrib(candidate, "port", port); @@ -191,10 +186,10 @@ xmlnode_set_attrib(candidate, "username", transport->username); xmlnode_set_attrib(candidate, "password", transport->password); xmlnode_set_attrib(candidate, "preference", pref); - xmlnode_set_attrib(candidate, "protocol", transport->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? "udp" : "tcp"); - xmlnode_set_attrib(candidate, "type", transport->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? "local" : - transport->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? "stun" : - transport->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? "relay" : NULL); + xmlnode_set_attrib(candidate, "protocol", transport->proto == FS_NETWORK_PROTOCOL_UDP ? "udp" : "tcp"); + xmlnode_set_attrib(candidate, "type", transport->type == FS_CANDIDATE_TYPE_HOST ? "local" : + transport->type == FS_CANDIDATE_TYPE_PRFLX ? "stun" : + transport->type == FS_CANDIDATE_TYPE_RELAY ? "relay" : NULL); xmlnode_set_attrib(candidate, "generation", "0"); xmlnode_set_attrib(candidate, "network", "0"); xmlnode_insert_child(sess, candidate); @@ -206,30 +201,24 @@ static void google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) { - PurpleMedia *media; JabberIq *result; - FarsightSession *fs; GList *codecs = NULL; xmlnode *desc_element, *codec_element; - FarsightCodec *codec; + FsCodec *codec; const char *id, *encoding_name, *clock_rate; - int res; if (session->state != UNINIT) { purple_debug_error("jabber", "Received initiate for active session.\n"); - return FALSE; + return; } - fs = farsight_session_factory_make("rtp"); - if (!fs) { - purple_debug_error("jabber", "Farsight's rtp plugin not installed"); - return FALSE; - } - - session->stream = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, FARSIGHT_STREAM_DIRECTION_BOTH); + session->media = purple_media_manager_create_media(purple_media_manager_get(), js->gc, + "fsrtpconference", session->remote_jid); - g_object_set(G_OBJECT(session->stream), "transmitter", "libjingle", NULL); - + /* "rawudp" will need to be changed to "nice" when libnice is finished */ + purple_media_add_stream(session->media, session->remote_jid, + PURPLE_MEDIA_AUDIO, "rawudp"); + desc_element = xmlnode_get_child(sess, "description"); for (codec_element = xmlnode_get_child(desc_element, "payload-type"); @@ -239,31 +228,25 @@ id = xmlnode_get_attrib(codec_element, "id"); clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); - codec = g_new0(FarsightCodec, 1); - farsight_codec_init(codec, atoi(id), encoding_name, FARSIGHT_MEDIA_TYPE_AUDIO, clock_rate ? atoi(clock_rate) : 0); + codec = fs_codec_new(atoi(id), encoding_name, FS_MEDIA_TYPE_AUDIO, + clock_rate ? atoi(clock_rate) : 0); codecs = g_list_append(codecs, codec); } - session->media = media = purple_media_manager_create_media(purple_media_manager_get(), js->gc, session->remote_jid, session->stream, NULL); + purple_media_set_remote_audio_codecs(session->media, session->remote_jid, codecs); - g_signal_connect_swapped(G_OBJECT(media), "accepted", G_CALLBACK(google_session_send_accept), session); - g_signal_connect_swapped(G_OBJECT(media), "reject", G_CALLBACK(google_session_send_reject), session); - g_signal_connect_swapped(G_OBJECT(media), "hangup", G_CALLBACK(google_session_send_terminate), session); + g_signal_connect_swapped(G_OBJECT(session->media), "accepted", + G_CALLBACK(google_session_send_accept), session); + g_signal_connect_swapped(G_OBJECT(session->media), "reject", + G_CALLBACK(google_session_send_reject), session); + g_signal_connect_swapped(G_OBJECT(session->media), "hangup", + G_CALLBACK(google_session_send_terminate), session); + g_signal_connect(G_OBJECT(session->media), "candidates-prepared", + G_CALLBACK(google_session_candidates_prepared), session); + purple_media_ready(session->media); - - GstElement *e = purple_media_get_audio_src(media); - farsight_stream_set_source(session->stream, e); + fs_codec_list_destroy(codecs); - e = purple_media_get_audio_sink(media); - farsight_stream_set_sink(session->stream, e); - - farsight_stream_prepare_transports(session->stream); - res = farsight_stream_set_remote_codecs(session->stream, codecs); - - purple_media_ready(media); - - farsight_codec_list_destroy(codecs); - g_signal_connect(G_OBJECT(session->stream), "new-native-candidate", G_CALLBACK(google_session_candidates_prepared), session); result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); xmlnode_set_attrib(result->node, "to", session->remote_jid); @@ -280,24 +263,26 @@ char n[4]; for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) { - FarsightTransportInfo *info = g_new0(FarsightTransportInfo, 1); + FsCandidate *info; g_snprintf(n, sizeof(n), "S%d", name++); - info->ip = xmlnode_get_attrib(cand, "address"); - info->port = atoi(xmlnode_get_attrib(cand, "port")); - info->proto = !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? FARSIGHT_NETWORK_PROTOCOL_UDP : FARSIGHT_NETWORK_PROTOCOL_TCP; - info->preference = atof(xmlnode_get_attrib(cand, "preference")); - info->type = !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? FARSIGHT_CANDIDATE_TYPE_LOCAL : - !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? FARSIGHT_CANDIDATE_TYPE_DERIVED : - !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? FARSIGHT_CANDIDATE_TYPE_RELAY : FARSIGHT_CANDIDATE_TYPE_LOCAL; - info->candidate_id = n; - info->username = xmlnode_get_attrib(cand, "username"); - info->password = xmlnode_get_attrib(cand, "password"); + info = fs_candidate_new(n, FS_COMPONENT_RTP, !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? + FS_CANDIDATE_TYPE_HOST : + !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? + FS_CANDIDATE_TYPE_PRFLX : + !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? + FS_CANDIDATE_TYPE_RELAY : FS_CANDIDATE_TYPE_HOST, + !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? + FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP, + xmlnode_get_attrib(cand, "address"), atoi(xmlnode_get_attrib(cand, "port"))); + + info->username = g_strdup(xmlnode_get_attrib(cand, "username")); + info->password = g_strdup(xmlnode_get_attrib(cand, "password")); + list = g_list_append(list, info); } - farsight_stream_add_remote_candidate(session->stream, list); - g_list_foreach(list, g_free, NULL); - g_list_free(list); + purple_media_add_remote_audio_candidates(session->media, session->remote_jid, list); + fs_candidate_list_destroy(list); result = jabber_iq_new(js, JABBER_IQ_RESULT); jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); @@ -308,7 +293,6 @@ static void google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) { - farsight_stream_stop(session->stream); purple_media_got_hangup(session->media); google_session_destroy(session); @@ -317,7 +301,6 @@ static void google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) { - farsight_stream_stop(session->stream); purple_media_got_hangup(session->media); google_session_destroy(session); @@ -346,7 +329,6 @@ { GoogleSession *session; GoogleSessionId id; - JabberIq *result; xmlnode *session_node; xmlnode *desc_node; @@ -358,11 +340,11 @@ if (!session_node) return; - id.id = xmlnode_get_attrib(session_node, "id"); + id.id = (gchar*)xmlnode_get_attrib(session_node, "id"); if (!id.id) return; - id.initiator = xmlnode_get_attrib(session_node, "initiator"); + id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator"); if (!id.initiator) return; diff -r 69d54f84350a -r e1c8ec1259de libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/protocols/jabber/jabber.c Fri May 23 02:42:32 2008 +0000 @@ -58,6 +58,8 @@ #include "adhoccommands.h" #include "jingle.h" +#include + #define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) static PurplePlugin *my_protocol = NULL; @@ -1240,6 +1242,16 @@ { JabberStream *js = gc->proto_data; +#ifdef USE_FARSIGHT + /* Close all of the open media sessions on this stream */ + GList *iter = jabber_jingle_session_find_by_js(js); + + for (; iter; iter = iter->next) { + JingleSession *session = (JingleSession *)iter->data; + purple_media_hangup(session->media); + } +#endif + /* Don't perform any actions on the ssl connection * if we were forcibly disconnected because it will crash * on some SSL backends. @@ -1862,10 +1874,20 @@ JabberID *jid; JabberBuddy *jb; JabberBuddyResource *jbr; - +#ifdef USE_FARSIGHT + JingleSession *session; +#endif if(!(jid = jabber_id_new(who))) return; +#ifdef USE_FARSIGHT + session = jabber_jingle_session_find_by_jid(js, who); + + if (session) { + purple_media_hangup(session->media); + } + +#endif if((jb = jabber_buddy_find(js, who, TRUE)) && (jbr = jabber_buddy_find_resource(jb, jid->resource))) { if(jbr->thread_id) { @@ -2357,11 +2379,9 @@ xmlnode_insert_child(result->node, jingle); jabber_iq_send(result); purple_debug_info("jabber", "Sent session accept, starting stream\n"); - farsight_stream_start(jabber_jingle_session_get_stream(session)); - farsight_stream_set_remote_codecs( - jabber_jingle_session_get_stream(session), - jabber_jingle_session_get_remote_codecs(session)); - + gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING); + + session->session_started = TRUE; } static void @@ -2388,7 +2408,6 @@ jabber_jingle_session_get_remote_jid(session)); xmlnode_insert_child(result->node, jingle); jabber_iq_send(result); - farsight_stream_stop(jabber_jingle_session_get_stream(session)); jabber_jingle_session_destroy(session); } @@ -2403,117 +2422,135 @@ jabber_jingle_session_get_remote_jid(session)); xmlnode_insert_child(result->node, jingle); jabber_iq_send(result); - farsight_stream_stop(jabber_jingle_session_get_stream(session)); 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(FarsightStream *stream, gchar *candidate_id, - JingleSession *session) +jabber_session_candidates_prepared(PurpleMedia *media, JingleSession *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, - candidate_id); - purple_debug_info("jabber", "jabber_session_candidates_prepared called for candidate_id = %s\n", - candidate_id); - xmlnode_set_attrib(result->node, "to", - jabber_jingle_session_get_remote_jid(session)); - - xmlnode_insert_child(result->node, jingle); - jabber_iq_send(result); + 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(FarsightStream *stream, - gchar *native_candidate_id, - gchar *remote_candidate_id, - JingleSession *session) +jabber_session_candidate_pair_established(PurpleMedia *media, + FsCandidate *native_candidate, + FsCandidate *remote_candidate, + JingleSession *session) { - purple_debug_info("jabber", "jabber_candidate_pair_established called"); + 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)) { - purple_debug_info("jabber", - "we are the initiator, let's send conten-modify\n"); - JabberIq *result = jabber_iq_new(jabber_jingle_session_get_js(session), - JABBER_IQ_SET); + 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" */ - xmlnode *jingle = + jingle = jabber_jingle_session_create_content_replace(session, - native_candidate_id, - remote_candidate_id); + 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); } - /* - farsight_stream_set_active_candidate_pair(stream, native_candidate_id, - remote_candidate_id); - */ +} + +static void +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); + /* this will need to be changed to "nice" once the libnice transmitter is finished */ + purple_media_add_stream(media, remote_jid, PURPLE_MEDIA_AUDIO, "rawudp"); + + 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); } - -PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, +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) { /* create content negotiation */ JabberStream *js = gc->proto_data; JabberIq *request = jabber_iq_new(js, JABBER_IQ_SET); - xmlnode *jingle, *content, *description, *payload_type, *transport; - FarsightSession *fs = NULL; - FarsightStream *audio = NULL; /* only audio for now... */ + xmlnode *jingle, *content, *description, *transport; GList *codecs; - GList *codec_iter = NULL; - FarsightCodec *codec = NULL; - PurpleMedia *media = NULL; JingleSession *session; JabberBuddy *jb; JabberBuddyResource *jbr; - char id[10]; - char clock_rate[10]; - char channels[10]; - char jid[256]; - char me[256]; - - /* for debug */ - char *output; - int len; - - /* setup stream */ - fs = farsight_session_factory_make("rtp"); - if (fs == NULL) { - purple_debug_error("jabber", "Farsight's rtp plugin not installed"); - return NULL; - } - - /* check media stream type, and so on... */ - /* only do audio for now... */ - - /* get stuff from Farsight... */ - audio = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, - FARSIGHT_STREAM_DIRECTION_BOTH); - g_object_set(G_OBJECT(audio), "transmitter", "libjingle", NULL); - - purple_debug_info("jabber", "Getting local codecs\n"); - codecs = farsight_stream_get_local_codecs(audio); - purple_debug_info("jabber", "number of codecs: %d\n", g_list_length(codecs)); - - if (audio == NULL) { - purple_debug_error("jabber", "Unable to create Farsight stream for audio"); - /* destroy FarsightSession? */ - return NULL; - } - - media = purple_media_manager_create_media(purple_media_manager_get(), - gc, who, audio, NULL); - purple_debug_info("jabber", "After purple_media_manager_create_media\n"); + char *jid = NULL, *me = NULL; + /* construct JID to send to */ jb = jabber_buddy_find(js, who, FALSE); if (!jb) { @@ -2524,42 +2561,24 @@ if (!jbr) { purple_debug_error("jabber", "Could not find buddy's resource\n"); } - - g_snprintf(jid, 255, "%s/%s", who, jbr->name); + + 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); - jabber_jingle_session_set_remote_jid(session, jid); /* set ourselves as initiator */ - g_snprintf(me, sizeof(me), "%s@%s/%s", js->user->node, js->user->domain, - js->user->resource); - jabber_jingle_session_set_initiator(session, me); - - jabber_jingle_session_set_stream(session, audio); - jabber_jingle_session_set_media(session, media); - - 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); - - GstElement *e = purple_media_get_audio_src(media); - farsight_stream_set_source(jabber_jingle_session_get_stream(session), e); - e = purple_media_get_audio_sink(media); - farsight_stream_set_sink(jabber_jingle_session_get_stream(session), e); - - farsight_stream_prepare_transports(audio); - /* callback for new native (local) transport candidates for the stream */ - g_signal_connect(G_OBJECT(audio), - "new-native-candidate", - G_CALLBACK(jabber_session_candidates_prepared), session); - /* callback for new active candidate pair (established connection) */ - g_signal_connect(G_OBJECT(audio), - "new-active-candidate-pair", - G_CALLBACK(jabber_session_candidate_pair_established), - session); - + me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource); + + jabber_initiate_media_internal(session, me, jid); + + g_free(jid); + g_free(me); + + codecs = purple_media_get_local_audio_codecs(session->media); + /* create request */ xmlnode_set_attrib(request->node, "to", @@ -2568,40 +2587,27 @@ 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", me); + 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 = xmlnode_new_child(content, "description"); - xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp"); - - /* create payload-type nodes */ - purple_debug_info("jabber", "Generating payload_type elements\n"); - for (; codecs ; codecs = codecs->next) { - codec = (FarsightCodec *) codecs->data; - purple_debug_info("jabber", "Generating payload_type for (%d) %s\n", - codec->id, codec->encoding_name); - sprintf(id, "%d", codec->id); - sprintf(clock_rate, "%d", codec->clock_rate); - sprintf(channels, "%d", codec->channels); - - payload_type = xmlnode_new_child(description, "payload-type"); - xmlnode_set_attrib(payload_type, "id", id); - xmlnode_set_attrib(payload_type, "name", codec->encoding_name); - xmlnode_set_attrib(payload_type, "clockrate", clock_rate); - xmlnode_set_attrib(payload_type, "channels", channels); - } - + + 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-tcp"); - + 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); - return media; + fs_codec_list_destroy(codecs); + + return session->media; } gboolean jabber_can_do_media(PurpleConnection *gc, const char *who, @@ -2620,11 +2626,10 @@ const char *sid = xmlnode_get_attrib(jingle, "sid"); const char *action = xmlnode_get_attrib(jingle, "action"); JingleSession *session = jabber_jingle_session_find_by_id(sid); - FarsightStream *stream = jabber_jingle_session_get_stream(session); GList *remote_codecs = NULL; GList *remote_transports = NULL; - GList *codec_intersection = NULL; - FarsightCodec *top = NULL; + GList *codec_intersection; + FsCodec *top = NULL; xmlnode *description = NULL; xmlnode *transport = NULL; @@ -2634,7 +2639,7 @@ jabber_jingle_session_get_remote_jid(session)); jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); - description = xmlnode_get_child(jingle, "description"); + description = xmlnode_get_child(content, "description"); transport = xmlnode_get_child(content, "transport"); /* fetch codecs from remote party */ @@ -2650,27 +2655,29 @@ purple_debug_info("jabber", "Setting remote codecs on stream\n"); - farsight_stream_set_remote_codecs(stream, remote_codecs); - if (!strcmp(action, "session-accept")) { - jabber_jingle_session_set_remote_codecs(session, remote_codecs); - } - - codec_intersection = farsight_stream_get_codec_intersection(stream); + 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 = (FarsightCodec *) codec_intersection->data; - purple_debug_info("jabber", "setting active codec on stream = %d\n", + top = (FsCodec *) codec_intersection->data; + purple_debug_info("jabber", "Found a suitable codec on stream = %d\n", top->id); - farsight_stream_set_active_codec(stream, 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) { - farsight_stream_set_remote_candidate_list(stream, remote_transports); + 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)) { @@ -2685,10 +2692,12 @@ 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"); - farsight_stream_start(jabber_jingle_session_get_stream(session)); + gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING); } jabber_iq_send(result); + + session->session_started = TRUE; } void @@ -2707,11 +2716,10 @@ /* 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); - farsight_stream_stop(jabber_jingle_session_get_stream(session)); jabber_jingle_session_destroy(session); } @@ -2726,6 +2734,9 @@ const char *sid = xmlnode_get_attrib(jingle, "sid"); JingleSession *session = jabber_jingle_session_find_by_id(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")); @@ -2733,10 +2744,10 @@ /* add candidates to our list of remote candidates */ if (g_list_length(remote_candidates) > 0) { - farsight_stream_add_remote_candidate( - jabber_jingle_session_get_stream(session), - remote_candidates); - jabber_jingle_session_add_remote_candidate(session, remote_candidates); + purple_media_add_remote_audio_candidates(session->media, + xmlnode_get_attrib(packet, "from"), + remote_candidates); + fs_candidate_list_destroy(remote_candidates); } } @@ -2744,25 +2755,28 @@ void jabber_handle_session_content_replace(JabberStream *js, xmlnode *packet) { - JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT); - JabberIq *accept = jabber_iq_new(js, JABBER_IQ_SET); - xmlnode *content_accept = NULL; xmlnode *jingle = xmlnode_get_child(packet, "jingle"); const char *sid = xmlnode_get_attrib(jingle, "sid"); JingleSession *session = jabber_jingle_session_find_by_id(sid); - /* 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); + 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 @@ -2772,18 +2786,10 @@ xmlnode *jingle = xmlnode_get_child(packet, "jingle"); xmlnode *content = NULL; xmlnode *description = NULL; - char *sid = NULL; - char *initiator = NULL; + const char *sid = NULL; + const char *initiator = NULL; GList *codecs = NULL; - FarsightSession *fs = NULL; - FarsightStream *audio = NULL; - PurpleMedia *media = NULL; JabberIq *result = NULL; - JabberIq *content_accept = NULL; - xmlnode *content_accept_jingle = NULL; - GList *codec_intersection = NULL; - - int res; if (!jingle) { purple_debug_error("jabber", "Malformed request"); @@ -2791,14 +2797,14 @@ } sid = xmlnode_get_attrib(jingle, "sid"); - //initiator = xmlnode_get_attrib(jingle, "initiator"); - initiator = xmlnode_get_attrib(packet, "from"); + initiator = xmlnode_get_attrib(jingle, "initiator"); + + if (jabber_jingle_session_find_by_id(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); - jabber_jingle_session_set_remote_jid(session, - xmlnode_get_attrib(packet, "from")); - /* set "from" as iniator (we are responder) */ - jabber_jingle_session_set_initiator(session, - xmlnode_get_attrib(packet, "from")); /* init media */ content = xmlnode_get_child(jingle, "content"); @@ -2811,92 +2817,21 @@ description = xmlnode_get_child(content, "description"); if (!description) { - purple_debug_error("jabber", "content tag must contain description tag"); + purple_debug_error("jabber", "content tag must contain description tag\n"); /* we should create an error iq here */ return; } + jabber_initiate_media_internal(session, initiator, initiator); + codecs = jabber_jingle_get_codecs(description); - fs = farsight_session_factory_make("rtp"); - if (!fs) { - purple_debug_error("jabber", - "Could not initialize Farsight's RTP plugin"); - return; - } - - audio = farsight_session_create_stream(fs, - FARSIGHT_MEDIA_TYPE_AUDIO, - FARSIGHT_STREAM_DIRECTION_BOTH); - - g_object_set(G_OBJECT(audio), "transmitter", "libjingle", NULL); - - media = purple_media_manager_create_media(purple_media_manager_get(), - js->gc, initiator, audio, NULL); - jabber_jingle_session_set_media(session, media); - jabber_jingle_session_set_stream(session, audio); - - - 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); - - - GstElement *e = purple_media_get_audio_src(media); - farsight_stream_set_source(jabber_jingle_session_get_stream(session), e); - - e = purple_media_get_audio_sink(media); - farsight_stream_set_sink(jabber_jingle_session_get_stream(session), e); - - farsight_stream_prepare_transports(jabber_jingle_session_get_stream(session)); - /* For some reason Farsight starts the stream immediatly when calling - farsight_stream_set_remote_codecs, before having called farsight_stream_start - As a "workaround" (maybe this gets fixed in FS2) I'll store the list in - the session to call it later when accepting the call */ - /* - res = - farsight_stream_set_remote_codecs(jabber_jingle_session_get_stream(session), - codecs); - */ - jabber_jingle_session_set_remote_codecs(session, codecs); - - purple_media_ready(media); - - /* We store the remote candidates in the session object... */ - /* - farsight_codec_list_destroy(codecs); - */ - - /* callback for new native (local) transport candidates for the stream */ - g_signal_connect(G_OBJECT(jabber_jingle_session_get_stream(session)), - "new-native-candidate", - G_CALLBACK(jabber_session_candidates_prepared), session); - /* callback for new active candidate pair (established connection) */ - g_signal_connect(G_OBJECT(jabber_jingle_session_get_stream(session)), - "new-active-candidate-pair", - G_CALLBACK(jabber_session_candidate_pair_established), - session); + 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); - - /* should send a content-accept */ - /* It crashes after this gets sent, also the id of this iq is set to - "purple0", that seems odd... maybe I'm making some mistake here... */ - /* - content_accept = jabber_iq_new(jabber_jingle_session_get_stream(session), - JABBER_IQ_SET); - content_accept_jingle = jabber_jingle_session_create_content_accept(session); - xmlnode_set_attrib(content_accept->node, "to", - jabber_jingle_session_get_remote_jid(session)); - xmlnode_insert_child(content_accept->node, content_accept_jingle); - jabber_iq_send(content_accept); - */ } #endif diff -r 69d54f84350a -r e1c8ec1259de libpurple/protocols/jabber/jingle.c --- a/libpurple/protocols/jabber/jingle.c Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/protocols/jabber/jingle.c Fri May 23 02:42:32 2008 +0000 @@ -28,8 +28,7 @@ #ifdef USE_FARSIGHT -#include -#include +#include /* keep a hash table of JingleSessions */ static GHashTable *sessions = NULL; @@ -66,10 +65,9 @@ purple_debug_info("jingle", "inserting session with key: %s into table\n", sess->id); g_hash_table_insert(sessions, sess->id, sess); - - sess->remote_candidates = NULL; - sess->remote_codecs = NULL; - + + sess->session_started = FALSE; + return sess; } @@ -106,8 +104,6 @@ { g_hash_table_remove(sessions, sess->id); g_free(sess->id); - farsight_codec_list_destroy(sess->remote_codecs); - g_list_free(sess->remote_candidates); g_free(sess); } @@ -115,20 +111,55 @@ jabber_jingle_session_find_by_id(const char *id) { purple_debug_info("jingle", "find_by_id %s\n", id); - purple_debug_info("jingle", "hash table: %lx\n", sessions); + purple_debug_info("jingle", "hash table: %p\n", sessions); purple_debug_info("jingle", "hash table size %d\n", g_hash_table_size(sessions)); - purple_debug_info("jingle", "lookup: %lx\n", g_hash_table_lookup(sessions, id)); + purple_debug_info("jingle", "lookup: %p\n", g_hash_table_lookup(sessions, id)); return (JingleSession *) g_hash_table_lookup(sessions, id); } GList * +jabber_jingle_session_find_by_js(JabberStream *js) +{ + GList *values = g_hash_table_get_values(sessions); + GList *iter = values; + GList *found = NULL; + + for (; iter; iter = iter->next) { + JingleSession *session = (JingleSession *)iter->data; + if (session->js == js) { + found = g_list_prepend(found, session); + } + } + + g_list_free(values); + return found; +} + +JingleSession *jabber_jingle_session_find_by_jid(JabberStream *js, const char *jid) +{ + GList *values = g_hash_table_get_values(sessions); + GList *iter = values; + + for (; iter; iter = iter->next) { + JingleSession *session = (JingleSession *)iter->data; + if (session->js == js && !strcmp(jid, session->remote_jid)) { + g_list_free(values); + return session; + } + } + + g_list_free(values); + return NULL; +} + +GList * jabber_jingle_get_codecs(const xmlnode *description) { GList *codecs = NULL; xmlnode *codec_element = NULL; const char *encoding_name,*id, *clock_rate; - FarsightCodec *codec; + FsCodec *codec; for (codec_element = xmlnode_get_child(description, "payload-type") ; codec_element ; @@ -137,10 +168,9 @@ id = xmlnode_get_attrib(codec_element, "id"); clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); - codec = g_new0(FarsightCodec, 1); - farsight_codec_init(codec, atoi(id), encoding_name, - FARSIGHT_MEDIA_TYPE_AUDIO, - clock_rate ? atoi(clock_rate) : 0); + codec = fs_codec_new(atoi(id), encoding_name, + FS_MEDIA_TYPE_AUDIO, + clock_rate ? atoi(clock_rate) : 0); codecs = g_list_append(codecs, codec); } return codecs; @@ -151,48 +181,31 @@ { GList *candidates = NULL; xmlnode *candidate = NULL; - FarsightTransportInfo *ti; + FsCandidate *c; for (candidate = xmlnode_get_child(transport, "candidate") ; candidate ; candidate = xmlnode_get_next_twin(candidate)) { const char *type = xmlnode_get_attrib(candidate, "type"); - ti = g_new0(FarsightTransportInfo, 1); - ti->component = atoi(xmlnode_get_attrib(candidate, "component")); - ti->ip = xmlnode_get_attrib(candidate, "ip"); - ti->port = atoi(xmlnode_get_attrib(candidate, "port")); - ti->proto = strcmp(xmlnode_get_attrib(candidate, "protocol"), + c = fs_candidate_new(xmlnode_get_attrib(candidate, "component"), + atoi(xmlnode_get_attrib(candidate, "component")), + strcmp(type, "host") == 0 ? + FS_CANDIDATE_TYPE_HOST : + strcmp(type, "prflx") == 0 ? + FS_CANDIDATE_TYPE_PRFLX : + FS_CANDIDATE_TYPE_RELAY, + strcmp(xmlnode_get_attrib(candidate, "protocol"), "udp") == 0 ? - FARSIGHT_NETWORK_PROTOCOL_UDP : - FARSIGHT_NETWORK_PROTOCOL_TCP; - /* it seems Farsight RTP doesn't handle this correctly right now */ - ti->username = xmlnode_get_attrib(candidate, "ufrag"); - ti->password = xmlnode_get_attrib(candidate, "pwd"); - /* not quite sure about this */ - ti->type = strcmp(type, "host") == 0 ? - FARSIGHT_CANDIDATE_TYPE_LOCAL : - strcmp(type, "prflx") == 0 ? - FARSIGHT_CANDIDATE_TYPE_DERIVED : - FARSIGHT_CANDIDATE_TYPE_RELAY; - - candidates = g_list_append(candidates, ti); + FS_NETWORK_PROTOCOL_UDP : + FS_NETWORK_PROTOCOL_TCP, + xmlnode_get_attrib(candidate, "ip"), + atoi(xmlnode_get_attrib(candidate, "port"))); + candidates = g_list_append(candidates, c); } return candidates; } -FarsightStream * -jabber_jingle_session_get_stream(const JingleSession *sess) -{ - return sess->stream; -} - -void -jabber_jingle_session_set_stream(JingleSession *sess, FarsightStream *stream) -{ - sess->stream = stream; -} - PurpleMedia * jabber_jingle_session_get_media(const JingleSession *sess) { @@ -237,36 +250,6 @@ return sess->is_initiator; } -void -jabber_jingle_session_add_remote_candidate(JingleSession *sess, - const GList *candidate) -{ - /* the length of the candidate list should be 1... */ - GList *cand = candidate; - for (; cand ; cand = cand->next) { - purple_debug_info("jingle", "Adding remote candidate with id = %s\n", - ((FarsightTransportInfo *) cand->data)->candidate_id); - sess->remote_candidates = g_list_append(sess->remote_candidates, - cand->data); - } -} - -static GList * -jabber_jingle_session_get_remote_candidate(const JingleSession *sess, - const gchar *id) -{ - GList *candidates = NULL; - GList *find = sess->remote_candidates; - for (; find ; find = find->next) { - const FarsightTransportInfo *candidate = - (FarsightTransportInfo *) find->data; - if (!strcmp(candidate->candidate_id, id)) { - candidates = g_list_append(candidates, (void *) candidate); - } - } - return candidates; -} - static xmlnode * jabber_jingle_session_create_jingle_element(const JingleSession *sess, const char *action) @@ -301,32 +284,105 @@ return jingle; } -static xmlnode * +xmlnode * jabber_jingle_session_create_description(const JingleSession *sess) { - GList *codecs = - farsight_stream_get_local_codecs(jabber_jingle_session_get_stream(sess)); - + GList *codecs = purple_media_get_local_audio_codecs(sess->media); xmlnode *description = xmlnode_new("description"); + xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp"); /* get codecs */ for (; codecs ; codecs = codecs->next) { - FarsightCodec *codec = (FarsightCodec*)codecs->data; - char id[8], clockrate[10]; + FsCodec *codec = (FsCodec*)codecs->data; + char id[8], clockrate[10], channels[10]; 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); } + fs_codec_list_destroy(codecs); return description; } +static guint +jabber_jingle_get_priority(guint type, guint network) +{ + switch (type) { + case FS_CANDIDATE_TYPE_HOST: + return network == 0 ? 4096 : network == 1 ? 2048 : 1024; + break; + case FS_CANDIDATE_TYPE_PRFLX: + return 126; + break; + case FS_CANDIDATE_TYPE_RELAY: + return 100; + break; + default: + return 0; /* unknown type, should not happen */ + } +} + +static xmlnode * +jabber_jingle_session_create_candidate_info(FsCandidate *c, FsCandidate *remote) +{ + char port[8]; + char prio[8]; + char component[8]; + xmlnode *candidate = NULL; + + candidate = xmlnode_new("candidate"); + + g_snprintf(port, sizeof(port), "%d", c->port); + g_snprintf(prio, sizeof(prio), "%d", + jabber_jingle_get_priority(c->type, 0)); + g_snprintf(component, sizeof(component), "%d", c->component_id); + + xmlnode_set_attrib(candidate, "component", component); + xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */ + xmlnode_set_attrib(candidate, "generation", "0"); /* ? */ + xmlnode_set_attrib(candidate, "ip", c->ip); + xmlnode_set_attrib(candidate, "network", "0"); /* ? */ + xmlnode_set_attrib(candidate, "port", port); + xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */ + xmlnode_set_attrib(candidate, "protocol", + c->proto == FS_NETWORK_PROTOCOL_UDP ? + "udp" : "tcp"); + if (c->username) + xmlnode_set_attrib(candidate, "ufrag", c->username); + if (c->password) + xmlnode_set_attrib(candidate, "pwd", c->password); + + xmlnode_set_attrib(candidate, "type", + c->type == FS_CANDIDATE_TYPE_HOST ? + "host" : + c->type == FS_CANDIDATE_TYPE_PRFLX ? + "prflx" : + c->type == FS_CANDIDATE_TYPE_RELAY ? + "relay" : NULL); + + /* relay */ + if (c->type == FS_CANDIDATE_TYPE_RELAY) { + /* set rel-addr and rel-port? How? */ + } + + if (remote) { + char remote_port[8]; + g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port); + xmlnode_set_attrib(candidate, "rem-addr", remote->ip); + xmlnode_set_attrib(candidate, "rem-port", remote_port); + } + + return candidate; +} + /* split into two separate methods, one to generate session-accept (includes codecs) and one to generate transport-info (includes transports candidates) */ @@ -337,6 +393,8 @@ jabber_jingle_session_create_jingle_element(sess, "session-accept"); xmlnode *content = NULL; xmlnode *description = NULL; + xmlnode *transport = NULL; + xmlnode *candidate = NULL; content = xmlnode_new_child(jingle, "content"); @@ -345,199 +403,82 @@ xmlnode_set_attrib(content, "profile", "RTP/AVP"); description = jabber_jingle_session_create_description(sess); - xmlnode_insert_child(jingle, description); - + xmlnode_insert_child(content, description); + + transport = xmlnode_new_child(content, "transport"); + xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp"); + candidate = jabber_jingle_session_create_candidate_info( + purple_media_get_local_candidate(sess->media), + purple_media_get_remote_candidate(sess->media)); + xmlnode_insert_child(transport, candidate); + return jingle; } -static guint -jabber_jingle_get_priority(guint type, guint network) -{ - switch (type) { - case FARSIGHT_CANDIDATE_TYPE_LOCAL: - return network == 0 ? 4096 : network == 1 ? 2048 : 1024; - break; - case FARSIGHT_CANDIDATE_TYPE_DERIVED: - return 126; - break; - case FARSIGHT_CANDIDATE_TYPE_RELAY: - return 100; - break; - default: - return 0; /* unknown type, should not happen */ - } -} xmlnode * -jabber_jingle_session_create_transport_info(const JingleSession *sess, - gchar *candidate_id) +jabber_jingle_session_create_transport_info(const JingleSession *sess) { xmlnode *jingle = jabber_jingle_session_create_jingle_element(sess, "transport-info"); xmlnode *content = NULL; xmlnode *transport = NULL; - GList *candidates = - farsight_stream_get_native_candidate( - jabber_jingle_session_get_stream(sess), candidate_id); - + GList *candidates = purple_media_get_local_audio_candidates(sess->media); + content = xmlnode_new_child(jingle, "content"); xmlnode_set_attrib(content, "creator", "initiator"); xmlnode_set_attrib(content, "name", "audio-content"); xmlnode_set_attrib(content, "profile", "RTP/AVP"); transport = xmlnode_new_child(content, "transport"); - xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp"); + xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp"); /* get transport candidate */ for (; candidates ; candidates = candidates->next) { - FarsightTransportInfo *transport_info = - (FarsightTransportInfo *) candidates->data; - char port[8]; - char prio[8]; - char component[8]; - xmlnode *candidate = NULL; - - if (!strcmp(transport_info->ip, "127.0.0.1")) { + FsCandidate *c = (FsCandidate *) candidates->data; + + if (!strcmp(c->ip, "127.0.0.1")) { continue; } - - candidate = xmlnode_new_child(transport, "candidate"); - - g_snprintf(port, sizeof(port), "%d", transport_info->port); - g_snprintf(prio, sizeof(prio), "%d", - jabber_jingle_get_priority(transport_info->type, 0)); - g_snprintf(component, sizeof(component), "%d", transport_info->component); - - xmlnode_set_attrib(candidate, "component", component); - xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */ - xmlnode_set_attrib(candidate, "generation", "0"); /* ? */ - xmlnode_set_attrib(candidate, "ip", transport_info->ip); - xmlnode_set_attrib(candidate, "network", "0"); /* ? */ - xmlnode_set_attrib(candidate, "port", port); - xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */ - xmlnode_set_attrib(candidate, "protocol", - transport_info->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? - "udp" : "tcp"); - if (transport_info->username) - xmlnode_set_attrib(candidate, "ufrag", transport_info->username); - if (transport_info->password) - xmlnode_set_attrib(candidate, "pwd", transport_info->password); - - xmlnode_set_attrib(candidate, "type", - transport_info->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? - "host" : - transport_info->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? - "prflx" : - transport_info->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? - "relay" : NULL); - + + xmlnode_insert_child(transport, + jabber_jingle_session_create_candidate_info(c, NULL)); } - farsight_transport_list_destroy(candidates); + fs_candidate_list_destroy(candidates); return jingle; } xmlnode * jabber_jingle_session_create_content_replace(const JingleSession *sess, - gchar *native_candidate_id, - gchar *remote_candidate_id) + FsCandidate *native_candidate, + FsCandidate *remote_candidate) { xmlnode *jingle = jabber_jingle_session_create_jingle_element(sess, "content-replace"); xmlnode *content = NULL; xmlnode *transport = NULL; - xmlnode *candidate = NULL; - xmlnode *description = NULL; - xmlnode *payload_type = NULL; - char local_port[8]; - char remote_port[8]; - char prio[8]; - char component[8]; - + purple_debug_info("jingle", "creating content-modify for native candidate %s " \ - ", remote candidate %s\n", native_candidate_id, - remote_candidate_id); - - /* It seems the ID's we get from the Farsight callback is phony... */ - /* - GList *native_candidates = - farsight_stream_get_native_candidate(jabber_jingle_session_get_stream(sess), - native_candidate_id); - purple_debug_info("jingle", "found %d native candidates with id %s\n", - g_list_length(native_candidates), native_candidate_id); - GList *remote_candidates = - jabber_jingle_session_get_remote_candidate(sess, remote_candidate_id); - */ - - /* we assume lists have length == 1, I think they must... */ - /* - FarsightTransportInfo *native = - (FarsightTransportInfo *) native_candidates->data; - FarsightTransportInfo *remote = - (FarsightTransportInfo *) remote_candidates->data; - */ - + ", remote candidate %s\n", native_candidate->candidate_id, + remote_candidate->candidate_id); + content = xmlnode_new_child(jingle, "content"); xmlnode_set_attrib(content, "creator", "initiator"); xmlnode_set_attrib(content, "name", "audio-content"); xmlnode_set_attrib(content, "profile", "RTP/AVP"); - description = xmlnode_new_child(content, "description"); - xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp"); - - payload_type = xmlnode_new_child(description, "payload-type"); /* get top codec from codec_intersection to put here... */ /* later on this should probably handle changing codec */ - - /* Skip creating the actual "content" element for now, since we don't - get enough info in the Farsight callback */ -#if 0 - transport = xmlnode_new_child(content, "transport"); - xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp"); - - candidate = xmlnode_new_child(transport, "candidate"); - - g_snprintf(local_port, sizeof(local_port), "%d", native->port); - g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port); - g_snprintf(prio, sizeof(prio), "%d", - jabber_jingle_get_priority(native->type, 0)); - g_snprintf(component, sizeof(component), "%d", native->component); + + xmlnode_insert_child(content, jabber_jingle_session_create_description(sess)); - xmlnode_set_attrib(candidate, "component", component); - xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */ - xmlnode_set_attrib(candidate, "generation", "0"); /* ? */ - xmlnode_set_attrib(candidate, "ip", native->ip); - xmlnode_set_attrib(candidate, "network", "1"); /* ? */ - xmlnode_set_attrib(candidate, "port", local_port); - xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */ - xmlnode_set_attrib(candidate, "protocol", - native->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? - "udp" : "tcp"); - if (native->username) - xmlnode_set_attrib(candidate, "ufrag", native->username); - if (native->password) - xmlnode_set_attrib(candidate, "pwd", native->password); - - xmlnode_set_attrib(candidate, "type", - native->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? - "host" : - native->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? - "prflx" : - native->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? - "relay" : NULL); - /* relay */ - if (native->type == FARSIGHT_CANDIDATE_TYPE_RELAY) { - /* set rel-addr and rel-port? How? */ - } - - xmlnode_set_attrib(candidate, "rem-addr", remote->ip); - xmlnode_set_attrib(candidate, "rem-port", remote_port); - - farsight_transport_list_destroy(native_candidates); - farsight_transport_list_destroy(remote_candidates); - -#endif /* 0 */ - + transport = xmlnode_new_child(content, "transport"); + xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-udp"); + xmlnode_insert_child(transport, + jabber_jingle_session_create_candidate_info(native_candidate, + remote_candidate)); + purple_debug_info("jingle", "End create content modify\n"); return jingle; @@ -556,24 +497,9 @@ xmlnode_set_attrib(content, "name", "audio-content"); xmlnode_set_attrib(content, "profile", "RTP/AVP"); - xmlnode_insert_child(jingle, description); + xmlnode_insert_child(content, description); return jingle; } -void -jabber_jingle_session_set_remote_codecs(JingleSession *sess, GList *codecs) -{ - if (sess->remote_codecs) { - farsight_codec_list_destroy(sess->remote_codecs); - } - sess->remote_codecs = codecs; -} - -GList * -jabber_jingle_session_get_remote_codecs(const JingleSession *sess) -{ - return sess->remote_codecs; -} - #endif /* USE_FARSIGHT */ diff -r 69d54f84350a -r e1c8ec1259de libpurple/protocols/jabber/jingle.h --- a/libpurple/protocols/jabber/jingle.h Sun Apr 13 17:53:46 2008 +0000 +++ b/libpurple/protocols/jabber/jingle.h Fri May 23 02:42:32 2008 +0000 @@ -26,20 +26,16 @@ #ifdef USE_FARSIGHT -#include - G_BEGIN_DECLS typedef struct { char *id; JabberStream *js; - FarsightStream *stream; PurpleMedia *media; char *remote_jid; char *initiator; gboolean is_initiator; - GList *remote_candidates; - GList *remote_codecs; + gboolean session_started; } JingleSession; JingleSession *jabber_jingle_session_create(JabberStream *js); @@ -52,9 +48,8 @@ void jabber_jingle_session_destroy(JingleSession *sess); JingleSession *jabber_jingle_session_find_by_id(const char *id); - -FarsightStream *jabber_jingle_session_get_stream(const JingleSession *sess); -void jabber_jingle_session_set_stream(JingleSession *sess, FarsightStream *stream); +GList *jabber_jingle_session_find_by_js(JabberStream *js); +JingleSession *jabber_jingle_session_find_by_jid(JabberStream *js, const char *jid); PurpleMedia *jabber_jingle_session_get_media(const JingleSession *sess); void jabber_jingle_session_set_media(JingleSession *sess, PurpleMedia *media); @@ -70,20 +65,16 @@ void jabber_jingle_session_set_initiator(JingleSession *sess, const char *initiator); -void jabber_jingle_session_add_remote_candidate(JingleSession *sess, - const GList *candidate); - xmlnode *jabber_jingle_session_create_terminate(const JingleSession *sess, const char *reasoncode, const char *reasontext); - xmlnode *jabber_jingle_session_create_session_accept(const JingleSession *sess); -xmlnode *jabber_jingle_session_create_transport_info(const JingleSession *sess, - gchar *candidate_id); +xmlnode *jabber_jingle_session_create_transport_info(const JingleSession *sess); xmlnode *jabber_jingle_session_create_content_replace(const JingleSession *sess, - gchar *native_candidate_id, - gchar *remote_candidate_id); + FsCandidate *native_candidate, + FsCandidate *remote_candidate); xmlnode *jabber_jingle_session_create_content_accept(const JingleSession *sess); +xmlnode *jabber_jingle_session_create_description(const JingleSession *sess); /** * Gets a list of Farsight codecs from a Jingle tag @@ -95,10 +86,6 @@ GList *jabber_jingle_get_candidates(const xmlnode *transport); -void jabber_jingle_session_set_remote_codecs(JingleSession *sess, - GList *codecs); -GList *jabber_jingle_session_get_remote_codecs(const JingleSession *sess); - G_END_DECLS #endif /* USE_FARSIGHT */ diff -r 69d54f84350a -r e1c8ec1259de pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Sun Apr 13 17:53:46 2008 +0000 +++ b/pidgin/gtkmedia.c Fri May 23 02:42:32 2008 +0000 @@ -32,8 +32,6 @@ #ifdef USE_FARSIGHT -#include - typedef enum { /* Waiting for response */ @@ -181,37 +179,18 @@ gtk_widget_show_all(media->priv->reject); } -static void -pidgin_media_finalize (GObject *media) -{ - PidginMedia *gtkmedia = PIDGIN_MEDIA(media); - if (gtkmedia->priv->media) - g_object_unref(gtkmedia->priv->media); - if (gtkmedia->priv->send_level) - gst_object_unref(gtkmedia->priv->send_level); - if (gtkmedia->priv->recv_level) - gst_object_unref(gtkmedia->priv->recv_level); -} - -static void -pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg) -{ - g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg); -} - static gboolean level_message_cb(GstBus *bus, GstMessage *message, PidginMedia *gtkmedia) { const GstStructure *s; const gchar *name; - int channels; - gdouble rms_db, peak_db, decay_db; - gdouble rms; + gdouble rms_db; + gdouble percent; const GValue *list; const GValue *value; - GstElement *src = GST_ELEMENT(message); + GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(message)); if (message->type != GST_MESSAGE_ELEMENT) return TRUE; @@ -228,14 +207,50 @@ value = gst_value_list_get_value(list, 0); rms_db = g_value_get_double(value); + percent = pow(10, rms_db / 20) * 5; + + if(percent > 1.0) + percent = 1.0; + if (!strcmp(gst_element_get_name(src), "sendlevel")) - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->send_progress), pow(10, rms_db / 20) * 5); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->send_progress), percent); else - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->recv_progress), pow(10, rms_db / 20) * 5); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtkmedia->priv->recv_progress), percent); return TRUE; } + +static void +pidgin_media_disconnect_levels(PurpleMedia *media, PidginMedia *gtkmedia) +{ + GstElement *element = purple_media_get_audio_pipeline(media); + gulong handler_id = g_signal_handler_find(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), + G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, + NULL, G_CALLBACK(level_message_cb), gtkmedia); + g_signal_handler_disconnect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), handler_id); +} + +static void +pidgin_media_finalize (GObject *media) +{ + PidginMedia *gtkmedia = PIDGIN_MEDIA(media); + if (gtkmedia->priv->media) { + pidgin_media_disconnect_levels(gtkmedia->priv->media, gtkmedia); + g_object_unref(gtkmedia->priv->media); + } + if (gtkmedia->priv->send_level) + gst_object_unref(gtkmedia->priv->send_level); + if (gtkmedia->priv->recv_level) + gst_object_unref(gtkmedia->priv->recv_level); +} + +static void +pidgin_media_emit_message(PidginMedia *gtkmedia, const char *msg) +{ + g_signal_emit(gtkmedia, pidgin_media_signals[MESSAGE], 0, msg); +} + static void pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia) { diff -r 69d54f84350a -r e1c8ec1259de pidgin/gtkmedia.h --- a/pidgin/gtkmedia.h Sun Apr 13 17:53:46 2008 +0000 +++ b/pidgin/gtkmedia.h Fri May 23 02:42:32 2008 +0000 @@ -28,7 +28,6 @@ #ifdef USE_FARSIGHT -#include #include #include