changeset 23789:128f6cb57829

Some media support in finch. This needs to be updated for the got-accept signal.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Sat, 22 Mar 2008 04:51:58 +0000
parents 9f36ed35615e
children a8a26b4d8458
files finch/Makefile.am finch/gntdebug.c finch/gntmedia.c finch/gntmedia.h finch/gntui.c po/POTFILES.in
diffstat 6 files changed, 515 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/finch/Makefile.am	Sat Mar 22 04:48:36 2008 +0000
+++ b/finch/Makefile.am	Sat Mar 22 04:51:58 2008 +0000
@@ -26,6 +26,7 @@
 	finch.c \
 	gntidle.c \
 	gntlog.c \
+	gntmedia.c \
 	gntnotify.c \
 	gntplugin.c \
 	gntpounce.c \
@@ -47,6 +48,7 @@
 	finch.h \
 	gntidle.h \
 	gntlog.h \
+	gntmedia.h \
 	gntnotify.h \
 	gntplugin.h \
 	gntpounce.h \
--- a/finch/gntdebug.c	Sat Mar 22 04:48:36 2008 +0000
+++ b/finch/gntdebug.c	Sat Mar 22 04:51:58 2008 +0000
@@ -348,6 +348,11 @@
 #ifdef USE_GSTREAMER
 	REGISTER_G_LOG_HANDLER("GStreamer");
 #endif
+#ifdef USE_FARSIGHT
+	REGISTER_G_LOG_HANDLER("farsight");
+	REGISTER_G_LOG_HANDLER("farsight-transmitter");
+	REGISTER_G_LOG_HANDLER("farsight-rtp");
+#endif
 
 	g_set_print_handler(print_stderr);   /* Redirect the debug messages to stderr */
 	if (!purple_debug_is_enabled())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/gntmedia.c	Sat Mar 22 04:51:58 2008 +0000
@@ -0,0 +1,423 @@
+/**
+ * @file gntmedia.c GNT Media API
+ * @ingroup finch
+ */
+
+/* finch
+ *
+ * Finch is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#include "finch.h"
+#include "mediamanager.h"
+
+#include "gntconv.h"
+#include "gntmedia.h"
+
+#include "gnt.h"
+#include "gntbutton.h"
+#include "gntbox.h"
+
+#include "cmds.h"
+#include "conversation.h"
+#include "debug.h"
+
+/* An incredibly large part of the following is from gtkmedia.c */
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+
+#undef hangup
+
+struct _FinchMediaPrivate
+{
+	PurpleMedia *media;
+	GstElement *send_level;
+	GstElement *recv_level;
+
+	GntWidget *accept;
+	GntWidget *reject;
+	GntWidget *hangup;
+
+	PurpleConversation *conv;
+};
+
+#define FINCH_MEDIA_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), FINCH_TYPE_MEDIA, FinchMediaPrivate))
+
+static void finch_media_class_init (FinchMediaClass *klass);
+static void finch_media_init (FinchMedia *media);
+static void finch_media_finalize (GObject *object);
+static void finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static GntBoxClass *parent_class = NULL;
+
+enum {
+	MESSAGE,
+	LAST_SIGNAL
+};
+static guint finch_media_signals[LAST_SIGNAL] = {0};
+
+enum {
+	PROP_0,
+	PROP_MEDIA,
+	PROP_SEND_LEVEL,
+	PROP_RECV_LEVEL
+};
+
+GType
+finch_media_get_type(void)
+{
+	static GType type = 0;
+
+	if (type == 0) {
+		static const GTypeInfo info = {
+			sizeof(FinchMediaClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) finch_media_class_init,
+			NULL,
+			NULL,
+			sizeof(FinchMedia),
+			0,
+			(GInstanceInitFunc) finch_media_init,
+			NULL
+		};
+		type = g_type_register_static(GNT_TYPE_BOX, "FinchMedia", &info, 0);
+	}
+	return type;
+}
+
+
+static void
+finch_media_class_init (FinchMediaClass *klass)
+{
+	GObjectClass *gobject_class = (GObjectClass*)klass;
+	parent_class = g_type_class_peek_parent(klass);
+
+	gobject_class->finalize = finch_media_finalize;
+	gobject_class->set_property = finch_media_set_property;
+	gobject_class->get_property = finch_media_get_property;
+
+	g_object_class_install_property(gobject_class, PROP_MEDIA,
+			g_param_spec_object("media",
+			"PurpleMedia",
+			"The PurpleMedia associated with this media.",
+			PURPLE_TYPE_MEDIA,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_class_install_property(gobject_class, PROP_SEND_LEVEL,
+			g_param_spec_object("send-level",
+			"Send level",
+			"The GstElement of this media's send 'level'",
+			GST_TYPE_ELEMENT,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+	g_object_class_install_property(gobject_class, PROP_RECV_LEVEL,
+			g_param_spec_object("recv-level",
+			"Receive level",
+			"The GstElement of this media's recv 'level'",
+			GST_TYPE_ELEMENT,
+			G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+	finch_media_signals[MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass),
+					G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+					g_cclosure_marshal_VOID__STRING,
+					G_TYPE_NONE, 1, G_TYPE_STRING);
+
+	g_type_class_add_private(klass, sizeof(FinchMediaPrivate));
+}
+
+
+static void
+finch_media_init (FinchMedia *media)
+{
+	media->priv = FINCH_MEDIA_GET_PRIVATE(media);
+
+	media->priv->hangup = gnt_button_new("Hangup");
+	media->priv->accept = gnt_button_new("Accept");
+	media->priv->reject = gnt_button_new("Reject");
+
+	gnt_box_set_alignment(GNT_BOX(media), GNT_ALIGN_MID);
+
+	gnt_box_add_widget(GNT_BOX(media), media->priv->accept);
+	gnt_box_add_widget(GNT_BOX(media), media->priv->reject);
+}
+
+static void
+finch_media_finalize (GObject *media)
+{
+}
+
+static void
+finch_media_emit_message(FinchMedia *gntmedia, const char *msg)
+{
+	g_signal_emit(gntmedia, finch_media_signals[MESSAGE], 0, msg);
+}
+
+static gboolean
+level_message_cb(GstBus *bus, GstMessage *message, FinchMedia *gntmedia)
+{
+	/* XXX: I am hesitant to just remove this function altogether, because I don't
+	 * know how necessary it is to have a callback to 'message'. If it isn't essential,
+	 * I suppose this should be removed.
+	 */
+	return TRUE;
+#if 0
+	const GstStructure *s;
+	const gchar *name;
+
+	int channels;
+	gdouble rms_db, peak_db, decay_db;
+	gdouble rms;
+	const GValue *list;
+	const GValue *value;
+
+	GstElement *src = GST_ELEMENT(message);
+
+	if (message->type != GST_MESSAGE_ELEMENT)
+		return TRUE;
+
+	s = gst_message_get_structure(message);
+	name = gst_structure_get_name(s);
+
+	if (strcmp(name, "level"))
+		return TRUE;
+
+	list = gst_structure_get_value(s, "rms");
+
+	/* Only bother with the first channel. */
+	value = gst_value_list_get_value(list, 0);
+	rms_db = g_value_get_double(value);
+
+	if (!strcmp(gst_element_get_name(src), "sendlevel"))
+		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gntmedia->priv->send_progress), pow(10, rms_db / 20) * 5);
+	else
+		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gntmedia->priv->recv_progress), pow(10, rms_db / 20) * 5);
+
+	return TRUE;
+#endif
+}
+
+static void
+finch_media_ready_cb(PurpleMedia *media, FinchMedia *gntmedia)
+{
+	GstElement *element = purple_media_get_audio_pipeline(media);
+	gst_bus_add_signal_watch(GST_BUS(gst_pipeline_get_bus(GST_PIPELINE(element))));
+	g_signal_connect(G_OBJECT(gst_pipeline_get_bus(GST_PIPELINE(element))), "message", G_CALLBACK(level_message_cb), gntmedia);
+}
+
+static void
+finch_media_accept_cb(PurpleMedia *media, FinchMedia *gntmedia)
+{
+	GntWidget *parent;
+
+	finch_media_emit_message(gntmedia, _("Call in progress."));
+
+	gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->accept);
+	gnt_box_remove(GNT_BOX(gntmedia), gntmedia->priv->reject);
+	gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->priv->hangup);
+
+	gnt_widget_destroy(gntmedia->priv->accept);
+	gnt_widget_destroy(gntmedia->priv->reject);
+	gntmedia->priv->accept = NULL;
+	gntmedia->priv->reject = NULL;
+
+	parent = GNT_WIDGET(gntmedia);
+	while (parent->parent)
+		parent = parent->parent;
+	gnt_box_readjust(GNT_BOX(parent));
+	gnt_widget_draw(parent);
+}
+
+static void
+finch_media_hangup_cb(PurpleMedia *media, FinchMedia *gntmedia)
+{
+	finch_media_emit_message(gntmedia, _("You have ended the call."));
+	finch_conversation_set_info_widget(gntmedia->priv->conv, NULL);
+	gnt_widget_destroy(GNT_WIDGET(gntmedia));
+}
+
+static void
+finch_media_got_hangup_cb(PurpleMedia *media, FinchMedia *gntmedia)
+{
+	finch_media_emit_message(gntmedia, _("The call has been terminated."));
+	finch_conversation_set_info_widget(gntmedia->priv->conv, NULL);
+	gnt_widget_destroy(GNT_WIDGET(gntmedia));
+}
+
+static void
+finch_media_reject_cb(PurpleMedia *media, FinchMedia *gntmedia)
+{
+	finch_media_emit_message(gntmedia, _("You have rejected the call."));
+	finch_conversation_set_info_widget(gntmedia->priv->conv, NULL);
+	gnt_widget_destroy(GNT_WIDGET(gntmedia));
+}
+
+static void
+finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	FinchMedia *media;
+	g_return_if_fail(FINCH_IS_MEDIA(object));
+
+	media = FINCH_MEDIA(object);
+	switch (prop_id) {
+		case PROP_MEDIA:
+			if (media->priv->media)
+				g_object_unref(media->priv->media);
+			media->priv->media = g_value_get_object(value);
+			g_object_ref(media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->accept), "activate",
+				 G_CALLBACK(purple_media_accept), media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->reject), "activate",
+				 G_CALLBACK(purple_media_reject), media->priv->media);
+			g_signal_connect_swapped(G_OBJECT(media->priv->hangup), "activate",
+				 G_CALLBACK(purple_media_hangup), media->priv->media);
+
+			g_signal_connect(G_OBJECT(media->priv->media), "accepted",
+				G_CALLBACK(finch_media_accept_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media) ,"ready",
+				G_CALLBACK(finch_media_ready_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media), "hangup",
+				G_CALLBACK(finch_media_hangup_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media), "reject",
+				G_CALLBACK(finch_media_reject_cb), media);
+			g_signal_connect(G_OBJECT(media->priv->media), "got-hangup",
+				G_CALLBACK(finch_media_got_hangup_cb), media);
+			break;
+		case PROP_SEND_LEVEL:
+			if (media->priv->send_level)
+				gst_object_unref(media->priv->send_level);
+			media->priv->send_level = g_value_get_object(value);
+			g_object_ref(media->priv->send_level);
+			break;
+		case PROP_RECV_LEVEL:
+			if (media->priv->recv_level)
+				gst_object_unref(media->priv->recv_level);
+			media->priv->recv_level = g_value_get_object(value);
+			g_object_ref(media->priv->recv_level);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	FinchMedia *media;
+	g_return_if_fail(FINCH_IS_MEDIA(object));
+
+	media = FINCH_MEDIA(object);
+
+	switch (prop_id) {
+		case PROP_MEDIA:
+			g_value_set_object(value, media->priv->media);
+			break;
+		case PROP_SEND_LEVEL:
+			g_value_set_object(value, media->priv->send_level);
+			break;
+		case PROP_RECV_LEVEL:
+			g_value_set_object(value, media->priv->recv_level);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);	
+			break;
+	}
+}
+
+GntWidget *
+finch_media_new(PurpleMedia *media, GstElement *sendlevel, GstElement *recvlevel)
+{
+	return GNT_WIDGET(g_object_new(finch_media_get_type(),
+				"media", media,
+				"send-level", sendlevel,
+				"recv-level", recvlevel,
+				"vertical", FALSE,
+				"homogeneous", FALSE,
+				NULL));
+}
+
+#endif  /* USE_FARSIGHT */
+
+static void
+gntmedia_message_cb(FinchMedia *gntmedia, const char *msg, PurpleConversation *conv)
+{
+	if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) {
+		purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, msg, PURPLE_MESSAGE_SYSTEM, time(NULL));
+	}
+}
+
+static void
+finch_new_media(PurpleMediaManager *manager, PurpleMedia *media, gpointer null)
+{
+	GstElement *sendbin, *sendlevel;
+	GstElement *recvbin, *recvlevel;
+	GntWidget *gntmedia;
+	PurpleConversation *conv;
+
+	purple_media_audio_init_src(&sendbin, &sendlevel);
+	purple_media_audio_init_recv(&recvbin, &recvlevel);
+
+	purple_media_set_audio_src(media, sendbin);
+	purple_media_set_audio_sink(media, recvbin);
+
+	conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
+			purple_connection_get_account(purple_media_get_connection(media)),
+			purple_media_get_screenname(media));
+
+	gntmedia = finch_media_new(media, sendlevel, recvlevel);
+	g_signal_connect(G_OBJECT(gntmedia), "message", G_CALLBACK(gntmedia_message_cb), conv);
+	FINCH_MEDIA(gntmedia)->priv->conv = conv;
+	finch_conversation_set_info_widget(conv, gntmedia);
+}
+
+static PurpleCmdRet
+call_cmd_cb(PurpleConversation *conv, const char *cmd, char **args,
+		char **eror, gpointer data)
+{
+	PurpleConnection *gc = purple_conversation_get_gc(conv);
+
+	PurpleMedia *media =
+		serv_initiate_media(gc,
+							purple_conversation_get_name(conv),
+							PURPLE_MEDIA_RECV_AUDIO & PURPLE_MEDIA_SEND_AUDIO);
+
+	if (!media)
+		return PURPLE_CMD_STATUS_FAILED;
+
+	purple_media_accept(media);
+	return PURPLE_CMD_STATUS_OK;
+}
+
+void finch_media_manager_init(void)
+{
+	PurpleMediaManager *manager = purple_media_manager_get();
+	g_signal_connect(G_OBJECT(manager), "init-media", G_CALLBACK(finch_new_media), NULL);
+	purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT,
+			PURPLE_CMD_FLAG_IM, NULL,
+			call_cmd_cb, _("call: Make an audio call."), NULL);
+}
+
+void finch_media_manager_uninit(void)
+{
+	PurpleMediaManager *manager = purple_media_manager_get();
+	g_signal_handlers_disconnect_by_func(G_OBJECT(manager),
+			G_CALLBACK(finch_new_media), NULL);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/gntmedia.h	Sat Mar 22 04:51:58 2008 +0000
@@ -0,0 +1,78 @@
+/**
+ * @file gntmedia.h GNT Media API
+ * @ingroup finch
+ */
+
+/* finch
+ *
+ * Finch is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
+ */
+
+#ifndef GNT_MEDIA_H
+#define GNT_MEDIA_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_FARSIGHT
+
+#include <farsight/farsight.h>
+#include <glib-object.h>
+#include "gntbox.h"
+
+G_BEGIN_DECLS
+
+#define FINCH_TYPE_MEDIA            (finch_media_get_type())
+#define FINCH_MEDIA(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_MEDIA, FinchMedia))
+#define FINCH_MEDIA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_MEDIA, FinchMediaClass))
+#define FINCH_IS_MEDIA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_MEDIA))
+#define FINCH_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_MEDIA))
+#define FINCH_MEDIA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_MEDIA, FinchMediaClass))
+
+typedef struct _FinchMedia FinchMedia;
+typedef struct _FinchMediaClass FinchMediaClass;
+typedef struct _FinchMediaPrivate FinchMediaPrivate;
+typedef enum _FinchMediaState FinchMediaState;
+
+struct _FinchMediaClass
+{
+	GntBoxClass parent_class;
+};
+
+struct _FinchMedia
+{
+	GntBox parent;
+	FinchMediaPrivate *priv;
+};
+
+GType finch_media_get_type(void);
+
+GntWidget *finch_media_new(PurpleMedia *media, GstElement *send_level, GstElement *recv_level);
+
+void finch_media_manager_init(void);
+
+void finch_media_manager_uninit(void);
+
+G_END_DECLS
+
+#endif /* USE_FARSIGHT */
+
+#endif /* GNT_MEDIA_H */
+
--- a/finch/gntui.c	Sat Mar 22 04:48:36 2008 +0000
+++ b/finch/gntui.c	Sat Mar 22 04:51:58 2008 +0000
@@ -31,6 +31,7 @@
 #include "gntdebug.h"
 #include "gntft.h"
 #include "gntlog.h"
+#include "gntmedia.h"
 #include "gntnotify.h"
 #include "gntplugin.h"
 #include "gntpounce.h"
@@ -91,6 +92,9 @@
 	finch_roomlist_init();
 	purple_roomlist_set_ui_ops(finch_roomlist_get_ui_ops());
 
+	/* Media */
+	finch_media_manager_init();
+
 	gnt_register_action(_("Accounts"), finch_accounts_show_all);
 	gnt_register_action(_("Buddy List"), finch_blist_show);
 	gnt_register_action(_("Buddy Pounces"), finch_pounces_manager_show);
@@ -136,6 +140,8 @@
 	finch_roomlist_uninit();
 	purple_roomlist_set_ui_ops(NULL);
 
+	finch_media_manager_uninit();
+
 	gnt_quit();
 #endif
 }
--- a/po/POTFILES.in	Sat Mar 22 04:48:36 2008 +0000
+++ b/po/POTFILES.in	Sat Mar 22 04:51:58 2008 +0000
@@ -8,6 +8,7 @@
 finch/gntdebug.c
 finch/gntft.c
 finch/gntlog.c
+finch/gntmedia.c
 finch/gntnotify.c
 finch/gntplugin.c
 finch/gntpounce.c