pidgin.vv.ticket34: 49c87e18: Some media support in finch. This needs ...
sadrul at pidgin.im
sadrul at pidgin.im
Sat Mar 22 00:50:51 EDT 2008
-----------------------------------------------------------------
Revision: 49c87e1875454a84f007720923563cf82dc8862b
Ancestor: 22fd8c15e7de1a417c862be0c73ba1959ad10a23
Author: sadrul at pidgin.im
Date: 2008-03-22T04:51:58
Branch: im.pidgin.pidgin.vv.ticket34
URL: http://d.pidgin.im/viewmtn/revision/info/49c87e1875454a84f007720923563cf82dc8862b
Added files:
finch/gntmedia.c finch/gntmedia.h
Modified files:
finch/Makefile.am finch/gntdebug.c finch/gntui.c
po/POTFILES.in
ChangeLog:
Some media support in finch. This needs to be updated for the got-accept signal.
-------------- next part --------------
============================================================
--- finch/gntmedia.c aafecb7c9022a1ce0c98703e93d1cf6048268c73
+++ finch/gntmedia.c aafecb7c9022a1ce0c98703e93d1cf6048268c73
@@ -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);
+}
+
============================================================
--- finch/gntmedia.h 107f86a0bc0ca7a3042a56f917f969e6a7556bc5
+++ finch/gntmedia.h 107f86a0bc0ca7a3042a56f917f969e6a7556bc5
@@ -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 */
+
============================================================
--- finch/Makefile.am 2660145ee425475a35c65f1b2c08daa0ee0d3ebc
+++ finch/Makefile.am ee6e3a99200401474c449b76590779f12c0fcb40
@@ -26,6 +26,7 @@ finch_SOURCES = \
finch.c \
gntidle.c \
gntlog.c \
+ gntmedia.c \
gntnotify.c \
gntplugin.c \
gntpounce.c \
@@ -47,6 +48,7 @@ finch_headers = \
finch.h \
gntidle.h \
gntlog.h \
+ gntmedia.h \
gntnotify.h \
gntplugin.h \
gntpounce.h \
============================================================
--- finch/gntdebug.c cee2ca762b160bc474cc609d540abce87c04ec81
+++ finch/gntdebug.c 6aa09ffb44a99193fa1d3a044654951ea5e64233
@@ -348,6 +348,11 @@ void finch_debug_init()
#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())
============================================================
--- finch/gntui.c d7d0b08bcd3a7421b1b872ed5d3f610b00bfecbf
+++ finch/gntui.c 8edaf0a4ba5410181fd490108962d4ab7584a5cb
@@ -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 @@ void gnt_ui_init()
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 @@ void gnt_ui_uninit()
finch_roomlist_uninit();
purple_roomlist_set_ui_ops(NULL);
+ finch_media_manager_uninit();
+
gnt_quit();
#endif
}
============================================================
--- po/POTFILES.in 7ecfbd719bde7e26808d2104fa52de3035f3b7d5
+++ po/POTFILES.in f1adf0d2fb76e621ec79ae895c0d51d72646993d
@@ -8,6 +8,7 @@ finch/gntlog.c
finch/gntdebug.c
finch/gntft.c
finch/gntlog.c
+finch/gntmedia.c
finch/gntnotify.c
finch/gntplugin.c
finch/gntpounce.c
More information about the Commits
mailing list