pidgin: 870436d8: Add Gmail video support.
maiku at soc.pidgin.im
maiku at soc.pidgin.im
Tue Jun 2 01:15:38 EDT 2009
-----------------------------------------------------------------
Revision: 870436d8e969e6b58532a1361f5e04f6572dfb75
Ancestor: b21df22c130f2f2b998c7ac6f698dde998913c7e
Author: maiku at soc.pidgin.im
Date: 2009-06-02T05:00:20
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/870436d8e969e6b58532a1361f5e04f6572dfb75
Modified files:
libpurple/media.c libpurple/protocols/jabber/disco.c
libpurple/protocols/jabber/google.c
libpurple/protocols/jabber/google.h
libpurple/protocols/jabber/jabber.c
libpurple/protocols/jabber/jabber.h
libpurple/protocols/jabber/presence.c
ChangeLog:
Add Gmail video support.
Thanks to Eion for all his testing help.
-------------- next part --------------
============================================================
--- libpurple/media.c 55b23817c6b261667aef1715b41262d8f699e507
+++ libpurple/media.c 429807c9e9686b5c12cd134613627ca4d051ae55
@@ -43,6 +43,7 @@
#ifdef USE_VV
#include <gst/farsight/fs-conference-iface.h>
+#include <gst/farsight/fs-element-added-notifier.h>
/** @copydoc _PurpleMediaSession */
typedef struct _PurpleMediaSession PurpleMediaSession;
@@ -2380,6 +2381,18 @@ purple_media_src_pad_added_cb(FsStream *
stream->connected_cb_id = purple_timeout_add(0,
(GSourceFunc)purple_media_connected_cb, stream);
}
+
+static void
+purple_media_element_added_cb(FsElementAddedNotifier *self,
+ GstBin *bin, GstElement *element, gpointer user_data)
+{
+ /*
+ * Hack to make H264 work with Gmail video.
+ */
+ if (!strncmp(GST_ELEMENT_NAME(element), "x264", 4)) {
+ g_object_set(GST_OBJECT(element), "cabac", FALSE, NULL);
+ }
+}
#endif /* USE_VV */
gboolean
@@ -2456,6 +2469,19 @@ purple_media_add_stream(PurpleMedia *med
g_object_set(G_OBJECT(session->session),
"no-rtcp-timeout", 0, NULL);
+ /*
+ * Hack to make x264 work with Gmail video.
+ */
+ if (is_nice && !strcmp(sess_id, "google-video")) {
+ FsElementAddedNotifier *notifier =
+ fs_element_added_notifier_new();
+ g_signal_connect(G_OBJECT(notifier), "element-added",
+ G_CALLBACK(purple_media_element_added_cb),
+ stream);
+ fs_element_added_notifier_add(notifier,
+ GST_BIN(media->priv->conference));
+ }
+
fs_codec_list_destroy(codec_conf);
session->id = g_strdup(sess_id);
@@ -2670,7 +2696,8 @@ purple_media_get_local_candidates(Purple
PurpleMediaStream *stream;
g_return_val_if_fail(PURPLE_IS_MEDIA(media), NULL);
stream = purple_media_get_stream(media, sess_id, participant);
- return purple_media_candidate_list_from_fs(stream->local_candidates);
+ return stream ? purple_media_candidate_list_from_fs(
+ stream->local_candidates) : NULL;
#else
return NULL;
#endif
============================================================
--- libpurple/protocols/jabber/disco.c 5d2574926a8baafe240717056fd7d15224598124
+++ libpurple/protocols/jabber/disco.c 96a0c9dece68107a98f5df9cf56b9357857d6f03
@@ -148,6 +148,18 @@ void jabber_disco_info_parse(JabberStrea
*/
xmlnode *feature = xmlnode_new_child(query, "feature");
xmlnode_set_attrib(feature, "var", "http://www.google.com/xmpp/protocol/voice/v1");
+ } else if (g_str_equal(node, CAPS0115_NODE "#" "video-v1")) {
+ /*
+ * HUGE HACK! We advertise this ext (see jabber_presence_create_js
+ * where we add <c/> to the <presence/>) for the Google Talk
+ * clients that don't actually check disco#info features.
+ *
+ * This specific feature is redundant but is what
+ * node='http://mail.google.com/xmpp/client/caps', ver='1.1'
+ * advertises as 'video-v1'.
+ */
+ xmlnode *feature = xmlnode_new_child(query, "feature");
+ xmlnode_set_attrib(feature, "var", "http://www.google.com/xmpp/protocol/video/v1");
#endif
} else {
xmlnode *error, *inf;
============================================================
--- libpurple/protocols/jabber/google.c b9c39a7c0ae213221b919210ce14f8e0fe1b3742
+++ libpurple/protocols/jabber/google.c 06a942c82e81c1324da3208abc35d6712a4e53a7
@@ -36,6 +36,9 @@
#ifdef USE_VV
+#define NS_GOOGLE_VIDEO "http://www.google.com/session/video"
+#define NS_GOOGLE_PHONE "http://www.google.com/session/phone"
+
typedef struct {
char *id;
char *initiator;
@@ -55,6 +58,7 @@ typedef struct {
PurpleMedia *media;
JabberStream *js;
char *remote_jid;
+ gboolean video;
} GoogleSession;
static gboolean
@@ -104,22 +108,25 @@ google_session_send_candidates(PurpleMed
google_session_send_candidates(PurpleMedia *media, gchar *session_id,
gchar *participant, GoogleSession *session)
{
- GList *candidates = purple_media_get_local_candidates(session->media, "google-voice",
- session->remote_jid);
+ GList *candidates = purple_media_get_local_candidates(
+ session->media, session_id, session->remote_jid);
PurpleMediaCandidate *transport;
+ gboolean video = FALSE;
+ if (!strcmp(session_id, "google-video"))
+ video = TRUE;
+
for (;candidates;candidates = candidates->next) {
JabberIq *iq;
gchar *ip, *port, *pref, *username, *password;
PurpleMediaCandidateType type;
xmlnode *sess;
xmlnode *candidate;
+ guint component_id;
transport = (PurpleMediaCandidate*)(candidates->data);
+ component_id = purple_media_candidate_get_component_id(
+ transport);
- if (purple_media_candidate_get_component_id(transport)
- != PURPLE_MEDIA_COMPONENT_RTP)
- continue;
-
iq = jabber_iq_new(session->js, JABBER_IQ_SET);
sess = google_session_create_xmlnode(session, "candidates");
xmlnode_insert_child(iq->node, sess);
@@ -139,7 +146,11 @@ google_session_send_candidates(PurpleMed
xmlnode_set_attrib(candidate, "address", ip);
xmlnode_set_attrib(candidate, "port", port);
- xmlnode_set_attrib(candidate, "name", "rtp");
+ xmlnode_set_attrib(candidate, "name",
+ component_id == PURPLE_MEDIA_COMPONENT_RTP ?
+ video ? "video_rtp" : "rtp" :
+ component_id == PURPLE_MEDIA_COMPONENT_RTCP ?
+ video ? "video_rtcp" : "rtcp" : "none");
xmlnode_set_attrib(candidate, "username", username);
/*
* As of this writing, Farsight 2 in Google compatibility
@@ -205,14 +216,39 @@ google_session_ready(GoogleSession *sess
google_session_send_candidates(session->media,
"google-voice", session->remote_jid,
session);
+ google_session_send_candidates(session->media,
+ "google-video", session->remote_jid,
+ session);
xmlnode_set_attrib(iq->node, "to", session->remote_jid);
xmlnode_set_attrib(iq->node, "from", me);
sess = google_session_create_xmlnode(session, "accept");
}
xmlnode_insert_child(iq->node, sess);
desc = xmlnode_new_child(sess, "description");
- xmlnode_set_namespace(desc, "http://www.google.com/session/phone");
+ if (session->video)
+ xmlnode_set_namespace(desc, NS_GOOGLE_VIDEO);
+ else
+ xmlnode_set_namespace(desc, NS_GOOGLE_PHONE);
+ codecs = purple_media_get_codecs(media, "google-video");
+
+ for (iter = codecs; iter; iter = g_list_next(iter)) {
+ PurpleMediaCodec *codec = (PurpleMediaCodec*)iter->data;
+ gchar *id = g_strdup_printf("%d",
+ purple_media_codec_get_id(codec));
+ gchar *encoding_name =
+ purple_media_codec_get_encoding_name(codec);
+ payload = xmlnode_new_child(desc, "payload-type");
+ xmlnode_set_attrib(payload, "id", id);
+ xmlnode_set_attrib(payload, "name", encoding_name);
+ xmlnode_set_attrib(payload, "width", "320");
+ xmlnode_set_attrib(payload, "height", "200");
+ xmlnode_set_attrib(payload, "framerate", "30");
+ g_free(encoding_name);
+ g_free(id);
+ }
+ purple_media_codec_list_free(codecs);
+
codecs = purple_media_get_codecs(media, "google-voice");
for (iter = codecs; iter; iter = g_list_next(iter)) {
@@ -224,6 +260,8 @@ google_session_ready(GoogleSession *sess
gchar *clock_rate = g_strdup_printf("%d",
purple_media_codec_get_clock_rate(codec));
payload = xmlnode_new_child(desc, "payload-type");
+ if (session->video)
+ xmlnode_set_namespace(payload, NS_GOOGLE_PHONE);
xmlnode_set_attrib(payload, "id", id);
xmlnode_set_attrib(payload, "name", encoding_name);
xmlnode_set_attrib(payload, "clockrate", clock_rate);
@@ -235,10 +273,14 @@ google_session_ready(GoogleSession *sess
jabber_iq_send(iq);
- if (is_initiator)
+ if (is_initiator) {
google_session_send_candidates(session->media,
"google-voice", session->remote_jid,
session);
+ google_session_send_candidates(session->media,
+ "google-video", session->remote_jid,
+ session);
+ }
g_signal_handlers_disconnect_by_func(G_OBJECT(session->media),
G_CALLBACK(google_session_ready), session);
@@ -339,6 +381,9 @@ jabber_google_session_initiate(JabberStr
session->js = js;
session->remote_jid = jid;
+ if (type & PURPLE_MEDIA_VIDEO)
+ session->video = TRUE;
+
session->media = purple_media_manager_create_media(
purple_media_manager_get(),
purple_connection_get_account(js->gc),
@@ -349,8 +394,12 @@ jabber_google_session_initiate(JabberStr
params = jabber_google_session_get_params(js, &num_params);
if (purple_media_add_stream(session->media, "google-voice",
- session->remote_jid, PURPLE_MEDIA_AUDIO,
- TRUE, "nice", num_params, params) == FALSE) {
+ session->remote_jid, PURPLE_MEDIA_AUDIO,
+ TRUE, "nice", num_params, params) == FALSE ||
+ (session->video && purple_media_add_stream(
+ session->media, "google-video",
+ session->remote_jid, PURPLE_MEDIA_VIDEO,
+ TRUE, "nice", num_params, params) == FALSE)) {
purple_media_error(session->media, "Error adding stream.");
purple_media_stream_info(session->media,
PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
@@ -378,10 +427,10 @@ google_session_handle_initiate(JabberStr
google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
{
JabberIq *result;
- GList *codecs = NULL;
+ GList *codecs = NULL, *video_codecs = NULL;
xmlnode *desc_element, *codec_element;
PurpleMediaCodec *codec;
- const char *id, *encoding_name, *clock_rate;
+ const char *xmlns;
GParameter *params;
guint num_params;
@@ -390,6 +439,19 @@ google_session_handle_initiate(JabberStr
return;
}
+ desc_element = xmlnode_get_child(sess, "description");
+ xmlns = xmlnode_get_namespace(desc_element);
+
+ if (purple_strequal(xmlns, NS_GOOGLE_PHONE))
+ session->video = FALSE;
+ else if (purple_strequal(xmlns, NS_GOOGLE_VIDEO))
+ session->video = TRUE;
+ else {
+ purple_debug_error("jabber", "Received initiate with "
+ "invalid namespace %s.\n", xmlns);
+ return;
+ }
+
session->media = purple_media_manager_create_media(
purple_media_manager_get(),
purple_connection_get_account(js->gc),
@@ -401,7 +463,11 @@ google_session_handle_initiate(JabberStr
if (purple_media_add_stream(session->media, "google-voice",
session->remote_jid, PURPLE_MEDIA_AUDIO, FALSE,
- "nice", num_params, params) == FALSE) {
+ "nice", num_params, params) == FALSE ||
+ (session->video && purple_media_add_stream(
+ session->media, "google-video",
+ session->remote_jid, PURPLE_MEDIA_VIDEO,
+ FALSE, "nice", num_params, params) == FALSE)) {
purple_media_error(session->media, "Error adding stream.");
purple_media_stream_info(session->media,
PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, TRUE);
@@ -412,24 +478,56 @@ google_session_handle_initiate(JabberStr
g_free(params);
- desc_element = xmlnode_get_child(sess, "description");
+ for (codec_element = xmlnode_get_child(desc_element, "payload-type");
+ codec_element; codec_element = codec_element->next) {
+ const char *id, *encoding_name, *clock_rate,
+ *width, *height, *framerate;
+ gboolean video;
+ if (codec_element->name &&
+ strcmp(codec_element->name, "payload-type"))
+ continue;
- for (codec_element = xmlnode_get_child(desc_element, "payload-type");
- codec_element;
- codec_element = xmlnode_get_next_twin(codec_element)) {
+ xmlns = xmlnode_get_namespace(codec_element);
encoding_name = xmlnode_get_attrib(codec_element, "name");
id = xmlnode_get_attrib(codec_element, "id");
- clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
+ if (!session->video ||
+ (xmlns && !strcmp(xmlns, NS_GOOGLE_PHONE))) {
+ clock_rate = xmlnode_get_attrib(
+ codec_element, "clockrate");
+ video = FALSE;
+ } else {
+ width = xmlnode_get_attrib(codec_element, "width");
+ height = xmlnode_get_attrib(codec_element, "height");
+ framerate = xmlnode_get_attrib(
+ codec_element, "framerate");
+ clock_rate = "90000";
+ video = TRUE;
+ }
+
if (id) {
- codec = purple_media_codec_new(atoi(id), encoding_name, PURPLE_MEDIA_AUDIO,
- clock_rate ? atoi(clock_rate) : 0);
- codecs = g_list_append(codecs, codec);
+ codec = purple_media_codec_new(atoi(id), encoding_name,
+ video ? PURPLE_MEDIA_VIDEO :
+ PURPLE_MEDIA_AUDIO,
+ clock_rate ? atoi(clock_rate) : 0);
+ if (video)
+ video_codecs = g_list_append(
+ video_codecs, codec);
+ else
+ codecs = g_list_append(codecs, codec);
}
}
- purple_media_set_remote_codecs(session->media, "google-voice", session->remote_jid, codecs);
+ if (codecs)
+ purple_media_set_remote_codecs(session->media, "google-voice",
+ session->remote_jid, codecs);
+ if (video_codecs)
+ purple_media_set_remote_codecs(session->media, "google-video",
+ session->remote_jid, video_codecs);
+ purple_media_codec_list_free(codecs);
+ purple_media_codec_list_free(video_codecs);
+
g_signal_connect_swapped(G_OBJECT(session->media), "accepted",
G_CALLBACK(google_session_ready), session);
g_signal_connect_swapped(G_OBJECT(session->media),
@@ -442,8 +540,6 @@ google_session_handle_initiate(JabberStr
g_signal_connect(G_OBJECT(session->media), "stream-info",
G_CALLBACK(google_session_stream_info_cb), session);
- purple_media_codec_list_free(codecs);
-
result = jabber_iq_new(js, JABBER_IQ_RESULT);
jabber_iq_set_id(result, iq_id);
xmlnode_set_attrib(result->node, "to", session->remote_jid);
@@ -454,19 +550,22 @@ google_session_handle_candidates(JabberS
google_session_handle_candidates(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
{
JabberIq *result;
- GList *list = NULL;
+ GList *list = NULL, *video_list = NULL;
xmlnode *cand;
static int name = 0;
char n[4];
- for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) {
+ for (cand = xmlnode_get_child(sess, "candidate"); cand;
+ cand = xmlnode_get_next_twin(cand)) {
PurpleMediaCandidate *info;
+ const gchar *cname = xmlnode_get_attrib(cand, "name");
const gchar *type = xmlnode_get_attrib(cand, "type");
const gchar *protocol = xmlnode_get_attrib(cand, "protocol");
const gchar *address = xmlnode_get_attrib(cand, "address");
const gchar *port = xmlnode_get_attrib(cand, "port");
+ guint component_id;
- if (type && address && port) {
+ if (cname && type && address && port) {
PurpleMediaCandidateType candidate_type;
g_snprintf(n, sizeof(n), "S%d", name++);
@@ -480,7 +579,13 @@ google_session_handle_candidates(JabberS
else
candidate_type = PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
- info = purple_media_candidate_new(n, PURPLE_MEDIA_COMPONENT_RTP,
+ if (purple_strequal(cname, "rtcp") ||
+ purple_strequal(cname, "video_rtcp"))
+ component_id = PURPLE_MEDIA_COMPONENT_RTCP;
+ else
+ component_id = PURPLE_MEDIA_COMPONENT_RTP;
+
+ info = purple_media_candidate_new(n, component_id,
candidate_type,
purple_strequal(protocol, "udp") ?
PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
@@ -489,12 +594,23 @@ google_session_handle_candidates(JabberS
atoi(port));
g_object_set(info, "username", xmlnode_get_attrib(cand, "username"),
"password", xmlnode_get_attrib(cand, "password"), NULL);
- list = g_list_append(list, info);
+ if (!strncmp(cname, "video_", 6))
+ video_list = g_list_append(video_list, info);
+ else
+ list = g_list_append(list, info);
}
}
- purple_media_add_remote_candidates(session->media, "google-voice", session->remote_jid, list);
+ if (list)
+ purple_media_add_remote_candidates(
+ session->media, "google-voice",
+ session->remote_jid, list);
+ if (video_list)
+ purple_media_add_remote_candidates(
+ session->media, "google-video",
+ session->remote_jid, video_list);
purple_media_candidate_list_free(list);
+ purple_media_candidate_list_free(video_list);
result = jabber_iq_new(js, JABBER_IQ_RESULT);
jabber_iq_set_id(result, iq_id);
@@ -506,28 +622,57 @@ google_session_handle_accept(JabberStrea
google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
{
xmlnode *desc_element = xmlnode_get_child(sess, "description");
- xmlnode *codec_element = xmlnode_get_child(desc_element, "payload-type");
- GList *codecs = NULL;
+ xmlnode *codec_element = xmlnode_get_child(
+ desc_element, "payload-type");
+ GList *codecs = NULL, *video_codecs = NULL;
JabberIq *result = NULL;
+ const gchar *xmlns = xmlnode_get_namespace(desc_element);
+ gboolean video = (xmlns && !strcmp(xmlns, NS_GOOGLE_VIDEO));
- for (; codec_element; codec_element =
- xmlnode_get_next_twin(codec_element)) {
- const gchar *encoding_name =
- xmlnode_get_attrib(codec_element, "name");
- const gchar *id = xmlnode_get_attrib(codec_element, "id");
- const gchar *clock_rate =
- xmlnode_get_attrib(codec_element, "clockrate");
+ for (; codec_element; codec_element = codec_element->next) {
+ const gchar *xmlns, *encoding_name, *id,
+ *clock_rate, *width, *height, *framerate;
+ gboolean video_codec = FALSE;
+ if (!purple_strequal(codec_element->name, "payload-type"))
+ continue;
+
+ xmlns = xmlnode_get_namespace(codec_element);
+ encoding_name = xmlnode_get_attrib(codec_element, "name");
+ id = xmlnode_get_attrib(codec_element, "id");
+
+ if (!video || purple_strequal(xmlns, NS_GOOGLE_PHONE))
+ clock_rate = xmlnode_get_attrib(
+ codec_element, "clockrate");
+ else {
+ clock_rate = "90000";
+ width = xmlnode_get_attrib(codec_element, "width");
+ height = xmlnode_get_attrib(codec_element, "height");
+ framerate = xmlnode_get_attrib(
+ codec_element, "framerate");
+ video_codec = TRUE;
+ }
+
if (id && encoding_name) {
- PurpleMediaCodec *codec = purple_media_codec_new(atoi(id),
- encoding_name, PURPLE_MEDIA_AUDIO,
+ PurpleMediaCodec *codec = purple_media_codec_new(
+ atoi(id), encoding_name,
+ video_codec ? PURPLE_MEDIA_VIDEO :
+ PURPLE_MEDIA_AUDIO,
clock_rate ? atoi(clock_rate) : 0);
- codecs = g_list_append(codecs, codec);
+ if (video_codec)
+ video_codecs = g_list_append(
+ video_codecs, codec);
+ else
+ codecs = g_list_append(codecs, codec);
}
}
- purple_media_set_remote_codecs(session->media, "google-voice",
- session->remote_jid, codecs);
+ if (codecs)
+ purple_media_set_remote_codecs(session->media, "google-voice",
+ session->remote_jid, codecs);
+ if (video_codecs)
+ purple_media_set_remote_codecs(session->media, "google-video",
+ session->remote_jid, video_codecs);
purple_media_stream_info(session->media, PURPLE_MEDIA_INFO_ACCEPT,
NULL, NULL, FALSE);
============================================================
--- libpurple/protocols/jabber/google.h 68e1b0e843201f8196f405b56d57fc0f783e3d7f
+++ libpurple/protocols/jabber/google.h 7c3fbd371479a0b8cd7ab1661dc925d1d84fd8c8
@@ -28,6 +28,7 @@
#include "media.h"
#define GOOGLE_VOICE_CAP "http://www.google.com/xmpp/protocol/voice/v1"
+#define GOOGLE_VIDEO_CAP "http://www.google.com/xmpp/protocol/video/v1"
#define GOOGLE_JINGLE_INFO_NAMESPACE "google:jingleinfo"
void jabber_gmail_init(JabberStream *js);
============================================================
--- libpurple/protocols/jabber/jabber.c c009147d5640ad3b4f1ed60288b3d93c7fab7e2e
+++ libpurple/protocols/jabber/jabber.c 00c90b35a7384234fae6b69942fe1d088d89abdc
@@ -2949,7 +2949,7 @@ jabber_audio_enabled(JabberStream *js, c
return (caps & (PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION));
}
-static gboolean
+gboolean
jabber_video_enabled(JabberStream *js, const char *namespace)
{
PurpleMediaManager *manager = purple_media_manager_get();
@@ -3189,8 +3189,12 @@ PurpleMediaCaps jabber_get_media_caps(Pu
caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION |
PURPLE_MEDIA_CAPS_CHANGE_DIRECTION;
}
- if (jabber_resource_has_capability(jbr, GOOGLE_VOICE_CAP))
+ if (jabber_resource_has_capability(jbr, GOOGLE_VOICE_CAP)) {
caps |= PURPLE_MEDIA_CAPS_AUDIO;
+ if (jabber_resource_has_capability(jbr,
+ GOOGLE_VIDEO_CAP))
+ caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO;
+ }
return caps;
}
============================================================
--- libpurple/protocols/jabber/jabber.h bbe0a9889aa19b62ade36273dd189dac47bd0c31
+++ libpurple/protocols/jabber/jabber.h 35bbd194c9d67d9cb00fca8a48faee1ba76fa174
@@ -366,6 +366,7 @@ gboolean jabber_audio_enabled(JabberStre
GList *jabber_actions(PurplePlugin *plugin, gpointer context);
gboolean jabber_audio_enabled(JabberStream *js, const char *unused);
+gboolean jabber_video_enabled(JabberStream *js, const char *unused);
gboolean jabber_initiate_media(PurpleAccount *account, const char *who,
PurpleMediaSessionType type);
PurpleMediaCaps jabber_get_media_caps(PurpleAccount *account, const char *who);
============================================================
--- libpurple/protocols/jabber/presence.c 08776f9cf028f2b8e7fb26de753400c3e3c32cd4
+++ libpurple/protocols/jabber/presence.c 8e84724e28ac7953a70cd3b572f8e439984406a7
@@ -245,6 +245,7 @@ xmlnode *jabber_presence_create_js(Jabbe
{
xmlnode *show, *status, *presence, *pri, *c;
const char *show_string = NULL;
+ gboolean audio_enabled, video_enabled;
presence = xmlnode_new("presence");
@@ -300,9 +301,18 @@ xmlnode *jabber_presence_create_js(Jabbe
* just assume that if we specify a 'voice-v1' ext (ignoring that
* these are to be assigned no semantic value), we support receiving voice
* calls.
+ *
+ * Ditto for 'video-v1'.
*/
- if (jabber_audio_enabled(js, NULL /* unused */))
+ audio_enabled = jabber_audio_enabled(js, NULL /* unused */);
+ video_enabled = jabber_video_enabled(js, NULL /* unused */);
+
+ if (audio_enabled && video_enabled)
+ xmlnode_set_attrib(c, "ext", "voice-v1 video-v1");
+ else if (audio_enabled)
xmlnode_set_attrib(c, "ext", "voice-v1");
+ else if (video_enabled)
+ xmlnode_set_attrib(c, "ext", "video-v1");
#endif
return presence;
More information about the Commits
mailing list