Mercurial > pidgin
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 }