changeset 26112:1fa62c559a78

merge of 'd47b8ff41e04be89d7152ac8f587e633fff7c1cb' and 'e6e2272c5b1e49a6ee2565437cd3d6b8963085c9'
author Mike Ruprecht <maiku@soc.pidgin.im>
date Thu, 19 Feb 2009 11:28:01 +0000
parents fcfb7571515c (diff) 260a606e2570 (current diff)
children 9fcff08ce726
files
diffstat 10 files changed, 160 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/media.c	Thu Feb 19 11:28:01 2009 +0000
@@ -69,6 +69,8 @@
 	gchar *participant;
 	FsStream *stream;
 	GstElement *sink;
+	GstElement *src;
+	GstElement *tee;
 
 	GList *local_candidates;
 	GList *remote_candidates;
@@ -83,6 +85,7 @@
 
 struct _PurpleMediaPrivate
 {
+	PurpleMediaManager *manager;
 	FsConference *conference;
 	gboolean initiator;
 
@@ -129,6 +132,7 @@
 
 enum {
 	PROP_0,
+	PROP_MANAGER,
 	PROP_CONFERENCE,
 	PROP_INITIATOR,
 };
@@ -183,6 +187,13 @@
 	gobject_class->set_property = purple_media_set_property;
 	gobject_class->get_property = purple_media_get_property;
 
+	g_object_class_install_property(gobject_class, PROP_MANAGER,
+			g_param_spec_object("manager",
+			"Purple Media Manager",
+			"The media manager that contains this media session.",
+			PURPLE_TYPE_MEDIA_MANAGER,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
 	g_object_class_install_property(gobject_class, PROP_CONFERENCE,
 			g_param_spec_object("conference",
 			"Farsight conference",
@@ -276,8 +287,7 @@
 
 	purple_debug_info("media","purple_media_dispose\n");
 
-	purple_media_manager_remove_media(purple_media_manager_get(),
-			PURPLE_MEDIA(media));
+	purple_media_manager_remove_media(priv->manager, PURPLE_MEDIA(media));
 
 	if (priv->confbin) {
 		gst_element_set_state(GST_ELEMENT(priv->confbin),
@@ -312,6 +322,11 @@
 			g_object_unref(participants->data);
 	}
 
+	if (priv->manager) {
+		g_object_unref(priv->manager);
+		priv->manager = NULL;
+	}
+
 	G_OBJECT_CLASS(parent_class)->finalize(media);
 }
 
@@ -344,6 +359,10 @@
 	media = PURPLE_MEDIA(object);
 
 	switch (prop_id) {
+		case PROP_MANAGER:
+			media->priv->manager = g_value_get_object(value);
+			g_object_ref(media->priv->manager);
+			break;
 		case PROP_CONFERENCE: {
 			gchar *name;
 
@@ -384,6 +403,9 @@
 	media = PURPLE_MEDIA(object);
 
 	switch (prop_id) {
+		case PROP_MANAGER:
+			g_value_set_object(value, media->priv->manager);
+			break;
 		case PROP_CONFERENCE:
 			g_value_set_object(value, media->priv->conference);
 			break;
@@ -1181,7 +1203,7 @@
 }
 
 static gboolean
-media_bus_call(GstBus *bus, GstMessage *msg, gpointer dummy)
+media_bus_call(GstBus *bus, GstMessage *msg, PurpleMediaManager *manager)
 {
 	switch(GST_MESSAGE_TYPE(msg)) {
 		case GST_MESSAGE_EOS:
@@ -1206,7 +1228,7 @@
 			PurpleMedia *media = NULL;
 			if (FS_IS_CONFERENCE(GST_MESSAGE_SRC(msg))) {
 				GList *iter = purple_media_manager_get_media(
-						purple_media_manager_get());
+						manager);
 				for (; iter; iter = g_list_next(iter)) {
 					if (PURPLE_MEDIA(iter->data)->priv->conference
 							== FS_CONFERENCE(GST_MESSAGE_SRC(msg))) {
@@ -1335,7 +1357,8 @@
 		bus = gst_pipeline_get_bus(GST_PIPELINE(media->priv->pipeline));
 		gst_bus_add_signal_watch(GST_BUS(bus));
 		g_signal_connect(G_OBJECT(bus), "message",
-				G_CALLBACK(media_bus_call), NULL);
+				G_CALLBACK(media_bus_call),
+				media->priv->manager);
 		gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, NULL);
 		gst_object_unref(bus);
 		gst_element_set_state(pipeline, GST_STATE_PLAYING);
@@ -1576,7 +1599,7 @@
 void
 purple_media_audio_init_recv(GstElement **recvbin, GstElement **recvlevel)
 {
-	GstElement *sink, *volume;
+	GstElement *sink, *volume, *queue;
 	GstPad *pad, *ghost;
 	double output_volume = purple_prefs_get_int(
 			"/purple/media/audio/volume/output")/10.0;
@@ -1589,10 +1612,13 @@
 	volume = gst_element_factory_make("volume", "purpleaudiooutputvolume");
 	g_object_set(volume, "volume", output_volume, NULL);
 	*recvlevel = gst_element_factory_make("level", "recvlevel");
-	gst_bin_add_many(GST_BIN(*recvbin), sink, volume, *recvlevel, NULL);
+	queue = gst_element_factory_make("queue", NULL);
+	gst_bin_add_many(GST_BIN(*recvbin), sink, volume,
+			*recvlevel, queue, NULL);
 	gst_element_link(*recvlevel, sink);
 	gst_element_link(volume, *recvlevel);
-	pad = gst_element_get_pad(volume, "sink");
+	gst_element_link(queue, volume);
+	pad = gst_element_get_pad(queue, "sink");
 	ghost = gst_ghost_pad_new("ghostsink", pad);
 	gst_element_add_pad(*recvbin, ghost);
 	g_object_set(G_OBJECT(*recvlevel), "message", TRUE, NULL);
@@ -1738,21 +1764,53 @@
 purple_media_src_pad_added_cb(FsStream *fsstream, GstPad *srcpad,
 			      FsCodec *codec, PurpleMediaStream *stream)
 {
-	PurpleMediaSessionType type = purple_media_from_fs(codec->media_type, FS_DIRECTION_RECV);
-	GstPad *sinkpad = NULL;
+	PurpleMediaPrivate *priv;
+	GstPad *sinkpad;
 
 	g_return_if_fail(FS_IS_STREAM(fsstream));
 	g_return_if_fail(stream != NULL);
 
-	if (stream->sink == NULL)
-		stream->sink = purple_media_manager_get_element(
-			purple_media_manager_get(), type);
-
-	gst_bin_add(GST_BIN(stream->session->media->priv->confbin),
-		    stream->sink);
-	sinkpad = gst_element_get_static_pad(stream->sink, "ghostsink");
+	priv = stream->session->media->priv;
+
+	if (stream->src == NULL) {
+		GstElement *sink;
+
+		if (codec->media_type == FS_MEDIA_TYPE_AUDIO) {
+			/*
+			 * Should this instead be:
+			 *  audioconvert ! audioresample ! liveadder !
+			 *   audioresample ! audioconvert ! realsink
+			 */
+			stream->src = gst_element_factory_make(
+					"liveadder", NULL);
+			sink = purple_media_manager_get_element(priv->manager,
+					PURPLE_MEDIA_RECV_AUDIO);
+		} else if (codec->media_type == FS_MEDIA_TYPE_VIDEO) {
+			stream->src = gst_element_factory_make(
+					"fsfunnel", NULL);
+			sink = gst_element_factory_make(
+					"fakesink", NULL);
+			g_object_set(G_OBJECT(sink), "async", FALSE, NULL);
+		}
+		stream->tee = gst_element_factory_make("tee", NULL);
+		gst_bin_add_many(GST_BIN(priv->confbin),
+				stream->src, stream->tee, sink, NULL);
+		gst_element_sync_state_with_parent(sink);
+		gst_element_sync_state_with_parent(stream->tee);
+		gst_element_sync_state_with_parent(stream->src);
+		gst_element_link_many(stream->src, stream->tee, sink, NULL);
+	}
+
+	sinkpad = gst_element_get_request_pad(stream->src, "sink%d");
 	gst_pad_link(srcpad, sinkpad);
-	gst_element_set_state(stream->sink, GST_STATE_PLAYING);
+	gst_object_unref(sinkpad);
+
+	if (codec->media_type == FS_MEDIA_TYPE_VIDEO &&
+			stream->sink != NULL) {
+		gst_bin_add(GST_BIN(priv->confbin), stream->sink);
+		gst_element_set_state(stream->sink, GST_STATE_PLAYING);
+		gst_element_link(stream->tee, stream->sink);
+	}
 
 	g_timeout_add_full(G_PRIORITY_HIGH, 0,
 			(GSourceFunc)purple_media_connected_cb, stream, NULL);
@@ -1841,7 +1899,7 @@
 		session_type = purple_media_from_fs(type, FS_DIRECTION_SEND);
 		purple_media_set_src(media, session->id,
 				purple_media_manager_get_element(
-				purple_media_manager_get(), session_type));
+				media->priv->manager, session_type));
 		gst_element_set_state(session->src, GST_STATE_PLAYING);
 	}
 
@@ -2376,7 +2434,7 @@
 		PurpleMediaStream *stream = purple_media_get_stream(
 				media, session_id, participant);
 		GstBus *bus;
-		GstElement *bin, *sink;
+		GstElement *bin, *queue, *sink;
 		GstPad *pad, *peer = NULL, *ghostpad;
 		PurpleMediaXOverlayData *data;
 		gchar *name;
@@ -2423,10 +2481,12 @@
 
 		name = g_strdup_printf("stream-sink_%s_%s",
 				session_id, participant);
+		queue = gst_element_factory_make("queue", NULL);
 		sink = gst_element_factory_make("autovideosink", name);
 
-		gst_bin_add(GST_BIN(bin), sink);
-		pad = gst_element_get_static_pad(sink, "sink");
+		gst_bin_add_many(GST_BIN(bin), queue, sink, NULL);
+		gst_element_link(queue, sink);
+		pad = gst_element_get_static_pad(queue, "sink");
 		ghostpad = gst_ghost_pad_new("ghostsink", pad);
 		gst_element_add_pad(bin, ghostpad);
 
@@ -2442,9 +2502,11 @@
 				G_CALLBACK(window_id_cb), data);
 		gst_object_unref(bus);
 
-		if (stream->sink != NULL) {
+		if (stream->tee != NULL) {
+			gst_bin_add(GST_BIN(GST_ELEMENT_PARENT(
+					stream->tee)), bin);
 			gst_element_set_state(bin, GST_STATE_PLAYING);
-			gst_pad_link(peer, ghostpad);
+			gst_element_link(stream->tee, bin);
 		}
 
 		stream->sink = bin;
--- a/libpurple/media.h	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/media.h	Thu Feb 19 11:28:01 2009 +0000
@@ -65,6 +65,18 @@
 
 #endif /* USE_VV */
 
+/** Media caps */
+typedef enum {
+	PURPLE_MEDIA_CAPS_NONE = 0,
+	PURPLE_MEDIA_CAPS_AUDIO = 1,
+	PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION = 1 << 1,
+	PURPLE_MEDIA_CAPS_VIDEO = 1 << 2,
+	PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION = 1 << 3,
+	PURPLE_MEDIA_CAPS_AUDIO_VIDEO = 1 << 4,
+	PURPLE_MEDIA_CAPS_MODIFY_SESSION = 1 << 5,
+	PURPLE_MEDIA_CAPS_CHANGE_DIRECTION = 1 << 6,
+} PurpleMediaCaps;
+
 /** Media session types */
 typedef enum {
 	PURPLE_MEDIA_NONE	= 0,
--- a/libpurple/mediamanager.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/mediamanager.c	Thu Feb 19 11:28:01 2009 +0000
@@ -165,6 +165,7 @@
 	}
 
 	media = PURPLE_MEDIA(g_object_new(purple_media_get_type(),
+			     "manager", manager,
 			     "conference", conference,
 			     "initiator", initiator,
 			     NULL));
--- a/libpurple/protocols/jabber/jabber.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Thu Feb 19 11:28:01 2009 +0000
@@ -2591,11 +2591,11 @@
 		return jingle_rtp_initiate_media(gc->proto_data, who, type);
 }
 
-gboolean jabber_can_do_media(PurpleConnection *gc, const char *who, 
-                             PurpleMediaSessionType type)
+PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who)
 {
 	JabberStream *js = (JabberStream *) gc->proto_data;
 	JabberBuddy *jb;
+	PurpleMediaCaps caps = PURPLE_MEDIA_CAPS_NONE;
 
 	if (!js) {
 		purple_debug_error("jabber", "jabber_can_do_media: NULL stream\n");
@@ -2609,34 +2609,30 @@
 		return FALSE;
 	}
 
-	if (!jabber_buddy_has_capability(jb, JINGLE_TRANSPORT_ICEUDP) &&
-			!jabber_buddy_has_capability(jb,
-			JINGLE_TRANSPORT_RAWUDP) &&
-			!jabber_buddy_has_capability(jb, GTALK_CAP)) {
-		purple_debug_info("jingle-rtp", "Buddy doesn't support "
-				"the same transport types\n");
-		return FALSE;
+	if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO))
+		caps |= PURPLE_MEDIA_CAPS_AUDIO |
+				PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION;
+	if (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO))
+		caps |= PURPLE_MEDIA_CAPS_VIDEO |
+				PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION;
+	if (caps & PURPLE_MEDIA_CAPS_AUDIO && caps & PURPLE_MEDIA_CAPS_VIDEO)
+		caps |= PURPLE_MEDIA_CAPS_AUDIO_VIDEO;
+	if (caps != PURPLE_MEDIA_CAPS_NONE) {
+		if (!jabber_buddy_has_capability(jb,
+				JINGLE_TRANSPORT_ICEUDP) &&
+				!jabber_buddy_has_capability(jb,
+				JINGLE_TRANSPORT_RAWUDP)) {
+			purple_debug_info("jingle-rtp", "Buddy doesn't "
+					"support the same transport types\n");
+			caps = PURPLE_MEDIA_CAPS_NONE;
+		} else
+			caps |= PURPLE_MEDIA_CAPS_MODIFY_SESSION |
+					PURPLE_MEDIA_CAPS_CHANGE_DIRECTION;
 	}
-
-	/* XMPP will only support two-way media, AFAIK... */
-	if (type == (PURPLE_MEDIA_AUDIO | PURPLE_MEDIA_VIDEO)) {
-		purple_debug_info("jabber", 
-				  "Checking audio/video XEP support for %s\n", who);
-		return (jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO) ||
-				jabber_buddy_has_capability(jb, GTALK_CAP)) && 
-				jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO);
-	} else if (type == (PURPLE_MEDIA_AUDIO)) {
-		purple_debug_info("jabber", 
-				  "Checking audio XEP support for %s\n", who);
-		return jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_AUDIO) ||
-				jabber_buddy_has_capability(jb, GTALK_CAP);
-	} else if (type == (PURPLE_MEDIA_VIDEO)) {
-		purple_debug_info("jabber", 
-				  "Checking video XEP support for %s\n", who);
-		return jabber_buddy_has_capability(jb, JINGLE_APP_RTP_SUPPORT_VIDEO);
-	}
-
-	return FALSE;
+	if (jabber_buddy_has_capability(jb, GTALK_CAP))
+		caps |= PURPLE_MEDIA_CAPS_AUDIO;
+
+	return caps;
 }
 
 #endif
--- a/libpurple/protocols/jabber/jabber.h	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Thu Feb 19 11:28:01 2009 +0000
@@ -329,7 +329,7 @@
 
 #ifdef USE_VV
 PurpleMedia *jabber_initiate_media(PurpleConnection *gc, const char *who, PurpleMediaSessionType type);
-gboolean jabber_can_do_media(PurpleConnection *gc, const char *who, PurpleMediaSessionType type);
+PurpleMediaCaps jabber_get_media_caps(PurpleConnection *gc, const char *who);
 #endif
 
 #endif /* _PURPLE_JABBER_H_ */
--- a/libpurple/protocols/jabber/libxmpp.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Thu Feb 19 11:28:01 2009 +0000
@@ -120,7 +120,7 @@
 	NULL, /* get_account_text_table */
 #ifdef USE_VV
 	jabber_initiate_media,          /* initiate_media */
-	jabber_can_do_media             /* can_do_media */
+	jabber_get_media_caps,                  /* get_media_caps */
 #else
 	NULL,					/* initiate_media */
 	NULL					/* can_do_media */
--- a/libpurple/prpl.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/prpl.c	Thu Feb 19 11:28:01 2009 +0000
@@ -524,10 +524,8 @@
 #endif
 }
 
-gboolean
-purple_prpl_can_do_media(PurpleAccount *account,
-			 const char *who, 
-			 PurpleMediaSessionType type)
+PurpleMediaCaps
+purple_prpl_get_media_caps(PurpleAccount *account, const char *who)
 {
 #ifdef USE_VV
 	PurpleConnection *gc = NULL;
@@ -541,14 +539,12 @@
 	if (prpl)
 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
 	
-	if (prpl_info && PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info, can_do_media)) {
-		return prpl_info->can_do_media(gc, who, type);
-	} else {
-		return FALSE;
+	if (prpl_info && PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl_info,
+			get_media_caps)) {
+		return prpl_info->get_media_caps(gc, who);
 	}
-#else
-	return FALSE;
 #endif
+	return PURPLE_MEDIA_CAPS_NONE;
 }
 
 /**************************************************************************
--- a/libpurple/prpl.h	Wed Feb 11 22:42:29 2009 +0000
+++ b/libpurple/prpl.h	Thu Feb 19 11:28:01 2009 +0000
@@ -466,11 +466,10 @@
 	 *
 	 * @param conn The connection the contact is on.
 	 * @param who The remote user to check for media capability with.
-	 * @param type The type of media session to check for.
-	 * @return @c TRUE The contact supports the given media type, or @c FALSE otherwise.
+	 * @return The media caps the contact supports.
 	 */
-	gboolean (*can_do_media)(PurpleConnection *gc, const char *who,
-				 PurpleMediaSessionType type);
+	PurpleMediaCaps (*get_media_caps)(PurpleConnection *gc,
+					  const char *who);
 };
 
 #define PURPLE_PROTOCOL_PLUGIN_HAS_FUNC(prpl, member) \
@@ -765,13 +764,11 @@
  *
  * @param account The account the user is on.
  * @param who The name of the contact to check capabilities for.
- * @param type The type of media session to check for.
  *
- * @return @c TRUE if the contact supports the session type, else @c FALSE.
+ * @return The media caps the contact supports.
  */
-gboolean purple_prpl_can_do_media(PurpleAccount *account,
-				  const char *who, 
-				  PurpleMediaSessionType type);
+PurpleMediaCaps purple_prpl_get_media_caps(PurpleAccount *account,
+				  const char *who);
 
 /**
  * Initiates a media session with the given contact.
--- a/pidgin/gtkblist.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/pidgin/gtkblist.c	Thu Feb 19 11:28:01 2009 +0000
@@ -348,8 +348,9 @@
 {
 	/* if the buddy supports both audio and video, start a combined call,
 	 otherwise start a pure video session */
-	if (purple_prpl_can_do_media(purple_buddy_get_account(b),
-		purple_buddy_get_name(b), PURPLE_MEDIA_AUDIO)) {
+	if (purple_prpl_get_media_caps(purple_buddy_get_account(b),
+			purple_buddy_get_name(b)) &
+			PURPLE_MEDIA_CAPS_AUDIO_VIDEO) {
 		purple_prpl_initiate_media(purple_buddy_get_account(b),
 			purple_buddy_get_name(b), PURPLE_MEDIA_AUDIO | PURPLE_MEDIA_VIDEO);
 	} else {
@@ -1463,20 +1464,20 @@
 			G_CALLBACK(gtk_blist_menu_im_cb), buddy, 0, 0, NULL);
 	
 #ifdef USE_VV
-	if (prpl_info && prpl_info->can_do_media) {
-		PurpleConnection *gc = 
-			purple_account_get_connection(purple_buddy_get_account(buddy));
+	if (prpl_info && prpl_info->get_media_caps) {
+		PurpleAccount *account = purple_buddy_get_account(buddy);
 		const gchar *who = purple_buddy_get_name(buddy);
-		if (prpl_info->can_do_media(gc, who, PURPLE_MEDIA_AUDIO)) {
+		PurpleMediaCaps caps = purple_prpl_get_media_caps(account, who);
+		if (caps & PURPLE_MEDIA_CAPS_AUDIO) {
 			pidgin_new_item_from_stock(menu, _("_Audio Call"),
 				PIDGIN_STOCK_TOOLBAR_AUDIO_CALL,
 				G_CALLBACK(gtk_blist_menu_audio_call_cb), buddy, 0, 0, NULL);
 		}
-		if (prpl_info->can_do_media(gc, who, PURPLE_MEDIA_VIDEO | PURPLE_MEDIA_AUDIO)) {
+		if (caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO) {
 			pidgin_new_item_from_stock(menu, _("Audio/_Video Call"),
 				PIDGIN_STOCK_TOOLBAR_VIDEO_CALL,
 				G_CALLBACK(gtk_blist_menu_video_call_cb), buddy, 0, 0, NULL);
-		} else if (prpl_info->can_do_media(gc, who, PURPLE_MEDIA_VIDEO)) {
+		} else if (caps & PURPLE_MEDIA_CAPS_VIDEO) {
 			pidgin_new_item_from_stock(menu, _("_Video Call"),
 				PIDGIN_STOCK_TOOLBAR_VIDEO_CALL,
 				G_CALLBACK(gtk_blist_menu_video_call_cb), buddy, 0, 0, NULL);
--- a/pidgin/gtkconv.c	Wed Feb 11 22:42:29 2009 +0000
+++ b/pidgin/gtkconv.c	Thu Feb 19 11:28:01 2009 +0000
@@ -6446,19 +6446,19 @@
 			supports it */
 		if (account != NULL && purple_conversation_get_type(conv)
 					== PURPLE_CONV_TYPE_IM) {
-			gboolean audio = purple_prpl_can_do_media(account,
-					purple_conversation_get_name(conv),
-					PURPLE_MEDIA_AUDIO);
-			gboolean video = purple_prpl_can_do_media(account,
-					purple_conversation_get_name(conv),
-					PURPLE_MEDIA_VIDEO);
-			gboolean av = purple_prpl_can_do_media(account,
-					purple_conversation_get_name(conv),
-					PURPLE_MEDIA_AUDIO | PURPLE_MEDIA_VIDEO);
-
-			gtk_widget_set_sensitive(win->menu.audio_call, audio ? TRUE : FALSE);
-			gtk_widget_set_sensitive(win->menu.video_call, video ? TRUE : FALSE);
-			gtk_widget_set_sensitive(win->menu.audio_video_call, av ? TRUE : FALSE);
+			PurpleMediaCaps caps =
+					purple_prpl_get_media_caps(account,
+					purple_conversation_get_name(conv));
+
+			gtk_widget_set_sensitive(win->menu.audio_call,
+					caps & PURPLE_MEDIA_CAPS_AUDIO
+					? TRUE : FALSE);
+			gtk_widget_set_sensitive(win->menu.video_call,
+					caps & PURPLE_MEDIA_CAPS_VIDEO
+					? TRUE : FALSE);
+			gtk_widget_set_sensitive(win->menu.audio_video_call, 
+					caps & PURPLE_MEDIA_CAPS_AUDIO_VIDEO
+					? TRUE : FALSE);
 		} else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
 			/* for now, don't care about chats... */
 			gtk_widget_set_sensitive(win->menu.audio_call, FALSE);