pidgin/pidgin

Install our appdata file to $(datadir)/metainfo as that change was made a long time ago

This patch originates from Lars Wendler from Gentoo

https://gitweb.gentoo.org/repo/gentoo.git/commit/net-im/pidgin/files/pidgin-2.13.0-metainfo.patch?id=2dd6c1852251b5b67c3045badf173be9535b97a9

Testing Done:
Installed to a prefix and verified the file ended up in `$prefix/share/metainfo`

Reviewed at https://reviews.imfreedom.org/r/607/
/*
* Configures microphones and webcams for voice and video
* Copyright (C) 2009 Mike Ruprecht <cmaiku@gmail.com>
*
* 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 "internal.h"
#include "debug.h"
#include "mediamanager.h"
#include "media-gst.h"
#include "version.h"
#include "gtkplugin.h"
#include "gtkutils.h"
#include "gtkprefs.h"
#if GST_CHECK_VERSION(1,0,0)
#include <gst/video/videooverlay.h>
#else
#include <gst/interfaces/propertyprobe.h>
#endif
/* container window for showing a stand-alone configurator */
static GtkWidget *window = NULL;
static PurpleMediaElementInfo *old_video_src = NULL, *old_video_sink = NULL,
*old_audio_src = NULL, *old_audio_sink = NULL;
static const gchar *AUDIO_SRC_PLUGINS[] = {
"alsasrc", N_("ALSA"),
/* "esdmon", "ESD", ? */
"osssrc", N_("OSS"),
"pulsesrc", N_("PulseAudio"),
"sndiosrc", N_("sndio"),
/* "audiotestsrc wave=silence", "Silence", */
"audiotestsrc", N_("Test Sound"),
NULL
};
static const gchar *AUDIO_SINK_PLUGINS[] = {
"alsasink", N_("ALSA"),
"artsdsink", N_("aRts"),
"esdsink", N_("ESD"),
"osssink", N_("OSS"),
"pulsesink", N_("PulseAudio"),
"sndiosink", N_("sndio"),
NULL
};
static const gchar *VIDEO_SRC_PLUGINS[] = {
"videotestsrc", N_("Test Input"),
"dshowvideosrc", N_("DirectDraw"),
"ksvideosrc", N_("KS Video"),
"qcamsrc", N_("Quickcam"),
"v4lsrc", N_("Video4Linux"),
"v4l2src", N_("Video4Linux2"),
"v4lmjpegsrc", N_("Video4Linux MJPEG"),
NULL
};
static const gchar *VIDEO_SINK_PLUGINS[] = {
/* "aasink", "AALib", Didn't work for me */
"directdrawsink", N_("DirectDraw"),
"glimagesink", N_("OpenGL"),
"ximagesink", N_("X Window System"),
"xvimagesink", N_("X Window System (Xv)"),
NULL
};
static GList *
get_element_devices(const gchar *element_name)
{
GList *ret = NULL;
GstElement *element;
GObjectClass *klass;
#if !GST_CHECK_VERSION(1,0,0)
GstPropertyProbe *probe;
const GParamSpec *pspec;
#endif
ret = g_list_prepend(ret, (gpointer)_("Default"));
ret = g_list_prepend(ret, "");
if (purple_strequal(element_name, "<custom>") || (*element_name == '\0')) {
return g_list_reverse(ret);
}
element = gst_element_factory_make(element_name, "test");
if(!element) {
purple_debug_info("vvconfig", "'%s' - unable to find element\n", element_name);
return g_list_reverse(ret);
}
klass = G_OBJECT_GET_CLASS (element);
if(!klass) {
purple_debug_info("vvconfig", "'%s' - unable to find G_Object Class\n", element_name);
return g_list_reverse(ret);
}
#if GST_CHECK_VERSION(1,0,0)
purple_debug_info("vvconfig", "'%s' - gstreamer-1.0 doesn't support "
"property probing\n", element_name);
#else
if (!g_object_class_find_property(klass, "device") ||
!GST_IS_PROPERTY_PROBE(element) ||
!(probe = GST_PROPERTY_PROBE(element)) ||
!(pspec = gst_property_probe_get_property(probe, "device"))) {
purple_debug_info("vvconfig", "'%s' - no device\n", element_name);
} else {
gsize n;
GValueArray *array;
/* Set autoprobe[-fps] to FALSE to avoid delays when probing. */
if (g_object_class_find_property (klass, "autoprobe")) {
g_object_set (G_OBJECT (element), "autoprobe", FALSE, NULL);
if (g_object_class_find_property (klass, "autoprobe-fps")) {
g_object_set (G_OBJECT (element), "autoprobe-fps", FALSE, NULL);
}
}
array = gst_property_probe_probe_and_get_values (probe, pspec);
if (array == NULL) {
purple_debug_info("vvconfig", "'%s' has no devices\n", element_name);
return g_list_reverse(ret);
}
for (n=0; n < array->n_values; ++n) {
GValue *device;
const gchar *name;
const gchar *device_name;
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* GValueArray is in gstreamer-0.10 API */
device = g_value_array_get_nth(array, n);
G_GNUC_END_IGNORE_DEPRECATIONS
g_object_set_property(G_OBJECT(element), "device", device);
if (gst_element_set_state(element, GST_STATE_READY)
!= GST_STATE_CHANGE_SUCCESS) {
purple_debug_warning("vvconfig",
"Error changing state of %s\n",
element_name);
continue;
}
g_object_get(G_OBJECT(element), "device-name", &name, NULL);
device_name = g_value_get_string(device);
if (name == NULL)
name = _("Unknown");
purple_debug_info("vvconfig", "Found device %s : %s for %s\n",
device_name, name, element_name);
ret = g_list_prepend(ret, (gpointer)name);
ret = g_list_prepend(ret, (gpointer)device_name);
gst_element_set_state(element, GST_STATE_NULL);
}
}
#endif
gst_object_unref(element);
return g_list_reverse(ret);
}
static GList *
get_element_plugins(const gchar **plugins)
{
GList *ret = NULL;
ret = g_list_prepend(ret, "Default");
ret = g_list_prepend(ret, "");
for (; plugins[0] && plugins[1]; plugins += 2) {
#if GST_CHECK_VERSION(1,0,0)
if (gst_registry_check_feature_version(gst_registry_get(),
plugins[0], 0, 0, 0)) {
#else
if (gst_default_registry_check_feature_version(
plugins[0], 0, 0, 0)) {
#endif
ret = g_list_prepend(ret, (gpointer)plugins[1]);
ret = g_list_prepend(ret, (gpointer)plugins[0]);
}
}
ret = g_list_reverse(ret);
return ret;
}
static void
device_changed_cb(const gchar *name, PurplePrefType type,
gconstpointer value, gpointer data)
{
GtkSizeGroup *sg = data;
GtkWidget *parent, *widget;
GSList *widgets;
GList *devices;
GValue gvalue;
gint position;
gchar *label, *pref;
widgets = gtk_size_group_get_widgets(GTK_SIZE_GROUP(sg));
for (; widgets; widgets = g_slist_next(widgets)) {
const gchar *widget_name =
gtk_widget_get_name(GTK_WIDGET(widgets->data));
if (purple_strequal(widget_name, name)) {
gchar *temp_str;
gchar delimiters[3] = {0, 0, 0};
const gchar *text;
gint keyval, pos;
widget = widgets->data;
/* Get label with _ from the GtkLabel */
text = gtk_label_get_text(GTK_LABEL(widget));
keyval = gtk_label_get_mnemonic_keyval(GTK_LABEL(widget));
delimiters[0] = g_ascii_tolower(keyval);
delimiters[1] = g_ascii_toupper(keyval);
pos = strcspn(text, delimiters);
if (pos != -1) {
temp_str = g_strndup(text, pos);
label = g_strconcat(temp_str, "_",
text + pos, NULL);
g_free(temp_str);
} else {
label = g_strdup(text);
}
break;
}
}
if (widgets == NULL)
return;
parent = gtk_widget_get_parent(widget);
widget = parent;
parent = gtk_widget_get_parent(GTK_WIDGET(widget));
gvalue.g_type = 0;
g_value_init(&gvalue, G_TYPE_INT);
gtk_container_child_get_property(GTK_CONTAINER(parent),
GTK_WIDGET(widget), "position", &gvalue);
position = g_value_get_int(&gvalue);
g_value_unset(&gvalue);
gtk_widget_destroy(widget);
pref = g_strdup(name);
strcpy(pref + strlen(pref) - strlen("plugin"), "device");
devices = get_element_devices(value);
if (g_list_find_custom(devices, purple_prefs_get_string(pref),
(GCompareFunc)strcmp) == NULL)
purple_prefs_set_string(pref, g_list_next(devices)->data);
widget = pidgin_prefs_dropdown_from_list(parent,
label, PURPLE_PREF_STRING,
pref, devices);
g_list_free(devices);
g_signal_connect_swapped(widget, "destroy",
G_CALLBACK(g_free), pref);
g_free(label);
gtk_misc_set_alignment(GTK_MISC(widget), 0, 0.5);
gtk_widget_set_name(widget, name);
gtk_size_group_add_widget(sg, widget);
gtk_box_reorder_child(GTK_BOX(parent),
gtk_widget_get_parent(GTK_WIDGET(widget)), position);
}
static void
get_plugin_frame(GtkWidget *parent, GtkSizeGroup *sg,
const gchar *name, const gchar *plugin_label,
const gchar **plugin_strs, const gchar *plugin_pref,
const gchar *device_label, const gchar *device_pref)
{
GtkWidget *vbox, *widget;
GList *plugins, *devices;
vbox = pidgin_make_frame(parent, name);
/* Setup plugin preference */
plugins = get_element_plugins(plugin_strs);
widget = pidgin_prefs_dropdown_from_list(vbox, plugin_label,
PURPLE_PREF_STRING, plugin_pref, plugins);
g_list_free(plugins);
gtk_size_group_add_widget(sg, widget);
gtk_misc_set_alignment(GTK_MISC(widget), 0, 0.5);
/* Setup device preference */
devices = get_element_devices(purple_prefs_get_string(plugin_pref));
if (g_list_find_custom(devices, purple_prefs_get_string(device_pref),
(GCompareFunc) strcmp) == NULL)
purple_prefs_set_string(device_pref, g_list_next(devices)->data);
widget = pidgin_prefs_dropdown_from_list(vbox, device_label,
PURPLE_PREF_STRING, device_pref, devices);
g_list_free(devices);
gtk_widget_set_name(widget, plugin_pref);
gtk_size_group_add_widget(sg, widget);
gtk_misc_set_alignment(GTK_MISC(widget), 0, 0.5);
purple_prefs_connect_callback(vbox, plugin_pref,
device_changed_cb, sg);
g_signal_connect_swapped(vbox, "destroy",
G_CALLBACK(purple_prefs_disconnect_by_handle), vbox);
}
static GtkWidget *
get_plugin_config_frame(PurplePlugin *plugin) {
GtkWidget *notebook, *vbox_audio, *vbox_video;
GtkSizeGroup *sg;
notebook = gtk_notebook_new();
gtk_container_set_border_width(GTK_CONTAINER(notebook),
PIDGIN_HIG_BORDER);
gtk_widget_show(notebook);
vbox_audio = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
vbox_video = gtk_vbox_new(FALSE, PIDGIN_HIG_CAT_SPACE);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
vbox_audio, gtk_label_new(_("Audio")));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
vbox_video, gtk_label_new(_("Video")));
gtk_container_set_border_width(GTK_CONTAINER (vbox_audio),
PIDGIN_HIG_BORDER);
gtk_container_set_border_width(GTK_CONTAINER (vbox_video),
PIDGIN_HIG_BORDER);
gtk_widget_show(vbox_audio);
gtk_widget_show(vbox_video);
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
get_plugin_frame(vbox_audio, sg, _("Output"), _("_Plugin"), AUDIO_SINK_PLUGINS,
"/plugins/core/vvconfig/audio/sink/plugin", _("_Device"),
"/plugins/core/vvconfig/audio/sink/device");
get_plugin_frame(vbox_audio, sg, _("Input"), _("P_lugin"), AUDIO_SRC_PLUGINS,
"/plugins/core/vvconfig/audio/src/plugin", _("D_evice"),
"/plugins/core/vvconfig/audio/src/device");
get_plugin_frame(vbox_video, sg, _("Output"), _("_Plugin"), VIDEO_SINK_PLUGINS,
"/plugins/gtk/vvconfig/video/sink/plugin", _("_Device"),
"/plugins/gtk/vvconfig/video/sink/device");
get_plugin_frame(vbox_video, sg, _("Input"), _("P_lugin"), VIDEO_SRC_PLUGINS,
"/plugins/core/vvconfig/video/src/plugin", _("D_evice"),
"/plugins/core/vvconfig/video/src/device");
return notebook;
}
static GstElement *
create_video_src(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
const gchar *plugin = purple_prefs_get_string(
"/plugins/core/vvconfig/video/src/plugin");
const gchar *device = purple_prefs_get_string(
"/plugins/core/vvconfig/video/src/device");
GstElement *ret;
if (plugin[0] == '\0')
return purple_media_element_info_call_create(old_video_src,
media, session_id, participant);
ret = gst_element_factory_make(plugin, "vvconfig-videosrc");
if (device[0] != '\0')
g_object_set(G_OBJECT(ret), "device", device, NULL);
if (purple_strequal(plugin, "videotestsrc"))
g_object_set(G_OBJECT(ret), "is-live", 1, NULL);
return ret;
}
static void
videosink_disable_last_sample(GstElement *sink)
{
GObjectClass *klass = G_OBJECT_GET_CLASS(sink);
if (g_object_class_find_property(klass, "enable-last-sample")) {
g_object_set(sink, "enable-last-sample", FALSE, NULL);
}
}
static void
autovideosink_child_added_cb(GstChildProxy *child_proxy, GObject *object,
#if GST_CHECK_VERSION(1,0,0)
gchar *name,
#endif
gpointer user_data)
{
videosink_disable_last_sample(GST_ELEMENT(object));
}
static GstElement *
create_video_sink(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
const gchar *plugin = purple_prefs_get_string(
"/plugins/gtk/vvconfig/video/sink/plugin");
const gchar *device = purple_prefs_get_string(
"/plugins/gtk/vvconfig/video/sink/device");
GstElement *ret;
if (plugin[0] == '\0')
return purple_media_element_info_call_create(old_video_sink,
media, session_id, participant);
ret = gst_element_factory_make(plugin, NULL);
if (device[0] != '\0')
g_object_set(G_OBJECT(ret), "device", device, NULL);
if (purple_strequal(plugin, "autovideosink")) {
g_signal_connect(ret, "child-added",
G_CALLBACK(autovideosink_child_added_cb), NULL);
} else {
videosink_disable_last_sample(ret);
}
return ret;
}
static GstElement *
create_audio_src(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
const gchar *plugin = purple_prefs_get_string(
"/plugins/core/vvconfig/audio/src/plugin");
const gchar *device = purple_prefs_get_string(
"/plugins/core/vvconfig/audio/src/device");
GstElement *ret;
if (plugin[0] == '\0')
return purple_media_element_info_call_create(old_audio_src,
media, session_id, participant);
ret = gst_element_factory_make(plugin, NULL);
if (device[0] != '\0')
g_object_set(G_OBJECT(ret), "device", device, NULL);
return ret;
}
static GstElement *
create_audio_sink(PurpleMedia *media,
const gchar *session_id, const gchar *participant)
{
const gchar *plugin = purple_prefs_get_string(
"/plugins/core/vvconfig/audio/sink/plugin");
const gchar *device = purple_prefs_get_string(
"/plugins/core/vvconfig/audio/sink/device");
GstElement *ret;
if (plugin[0] == '\0')
return purple_media_element_info_call_create(old_audio_sink,
media, session_id, participant);
ret = gst_element_factory_make(plugin, NULL);
if (device[0] != '\0')
g_object_set(G_OBJECT(ret), "device", device, NULL);
return ret;
}
static void
set_element_info_cond(PurpleMediaElementInfo *old_info,
PurpleMediaElementInfo *new_info, const gchar *id)
{
gchar *element_id = purple_media_element_info_get_id(old_info);
if (purple_strequal(element_id, id))
purple_media_manager_set_active_element(
purple_media_manager_get(), new_info);
g_free(element_id);
}
static gboolean
plugin_load(PurplePlugin *plugin)
{
PurpleMediaManager *manager;
PurpleMediaElementInfo *video_src, *video_sink,
*audio_src, *audio_sink;
/* Disable the plugin if the UI doesn't support VV */
if (purple_media_manager_get_ui_caps(purple_media_manager_get()) ==
PURPLE_MEDIA_CAPS_NONE)
return FALSE;
purple_prefs_add_none("/plugins/core/vvconfig");
purple_prefs_add_none("/plugins/core/vvconfig/audio");
purple_prefs_add_none("/plugins/core/vvconfig/audio/src");
purple_prefs_add_string("/plugins/core/vvconfig/audio/src/plugin", "");
purple_prefs_add_string("/plugins/core/vvconfig/audio/src/device", "");
purple_prefs_add_none("/plugins/core/vvconfig/audio/sink");
purple_prefs_add_string("/plugins/core/vvconfig/audio/sink/plugin", "");
purple_prefs_add_string("/plugins/core/vvconfig/audio/sink/device", "");
purple_prefs_add_none("/plugins/core/vvconfig/video");
purple_prefs_add_none("/plugins/core/vvconfig/video/src");
purple_prefs_add_string("/plugins/core/vvconfig/video/src/plugin", "");
purple_prefs_add_string("/plugins/core/vvconfig/video/src/device", "");
purple_prefs_add_none("/plugins/gtk/vvconfig");
purple_prefs_add_none("/plugins/gtk/vvconfig/video");
purple_prefs_add_none("/plugins/gtk/vvconfig/video/sink");
purple_prefs_add_string("/plugins/gtk/vvconfig/video/sink/plugin", "");
purple_prefs_add_string("/plugins/gtk/vvconfig/video/sink/device", "");
video_src = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
"id", "vvconfig-videosrc",
"name", "VV Conf Plugin Video Source",
"type", PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SRC
| PURPLE_MEDIA_ELEMENT_ONE_SRC
| PURPLE_MEDIA_ELEMENT_UNIQUE,
"create-cb", create_video_src, NULL);
video_sink = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
"id", "vvconfig-videosink",
"name", "VV Conf Plugin Video Sink",
"type", PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SINK
| PURPLE_MEDIA_ELEMENT_ONE_SINK,
"create-cb", create_video_sink, NULL);
audio_src = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
"id", "vvconfig-audiosrc",
"name", "VV Conf Plugin Audio Source",
"type", PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SRC
| PURPLE_MEDIA_ELEMENT_ONE_SRC
| PURPLE_MEDIA_ELEMENT_UNIQUE,
"create-cb", create_audio_src, NULL);
audio_sink = g_object_new(PURPLE_TYPE_MEDIA_ELEMENT_INFO,
"id", "vvconfig-audiosink",
"name", "VV Conf Plugin Audio Sink",
"type", PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SINK
| PURPLE_MEDIA_ELEMENT_ONE_SINK,
"create-cb", create_audio_sink, NULL);
purple_debug_info("gtkmedia", "Registering media element types\n");
manager = purple_media_manager_get();
old_video_src = purple_media_manager_get_active_element(manager,
PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SRC);
old_video_sink = purple_media_manager_get_active_element(manager,
PURPLE_MEDIA_ELEMENT_VIDEO | PURPLE_MEDIA_ELEMENT_SINK);
old_audio_src = purple_media_manager_get_active_element(manager,
PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SRC);
old_audio_sink = purple_media_manager_get_active_element(manager,
PURPLE_MEDIA_ELEMENT_AUDIO | PURPLE_MEDIA_ELEMENT_SINK);
set_element_info_cond(old_video_src, video_src, "pidgindefaultvideosrc");
set_element_info_cond(old_video_sink, video_sink, "pidgindefaultvideosink");
set_element_info_cond(old_audio_src, audio_src, "pidgindefaultaudiosrc");
set_element_info_cond(old_audio_sink, audio_sink, "pidgindefaultaudiosink");
return TRUE;
}
static void
config_destroy(GtkObject *w, gpointer nul)
{
purple_debug_info("vvconfig", "closing vv configuration window\n");
window = NULL;
}
static void
config_close(GtkObject *w, gpointer nul)
{
gtk_widget_destroy(GTK_WIDGET(window));
}
typedef GtkWidget *(*FrameCreateCb)(PurplePlugin *plugin);
static void
show_config(PurplePluginAction *action)
{
if (!window) {
FrameCreateCb create_frame = action->user_data;
GtkWidget *vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
GtkWidget *hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER);
GtkWidget *config_frame = create_frame(NULL);
GtkWidget *close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
gtk_container_add(GTK_CONTAINER(vbox), config_frame);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
window = pidgin_create_window(action->label,
PIDGIN_HIG_BORDER, NULL, FALSE);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(config_destroy), NULL);
g_signal_connect(G_OBJECT(close), "clicked",
G_CALLBACK(config_close), NULL);
gtk_box_pack_end(GTK_BOX(hbox), close, FALSE, FALSE, PIDGIN_HIG_BORDER);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(GTK_WIDGET(close));
gtk_widget_show(GTK_WIDGET(vbox));
gtk_widget_show(GTK_WIDGET(hbox));
}
gtk_window_present(GTK_WINDOW(window));
}
static GstElement *
create_pipeline()
{
GstElement *pipeline = gst_pipeline_new("voicetest");
GstElement *src = create_audio_src(NULL, NULL, NULL);
GstElement *sink = create_audio_sink(NULL, NULL, NULL);
GstElement *volume = gst_element_factory_make("volume", "volume");
GstElement *level = gst_element_factory_make("level", "level");
GstElement *valve = gst_element_factory_make("valve", "valve");
gst_bin_add_many(GST_BIN(pipeline), src, volume, level, valve, sink, NULL);
gst_element_link_many(src, volume, level, valve, sink, NULL);
gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PLAYING);
return pipeline;
}
static void
on_volume_change_cb(GtkRange *range, GstBin *pipeline)
{
GstElement *volume;
g_return_if_fail(pipeline != NULL);
volume = gst_bin_get_by_name(pipeline, "volume");
g_object_set(volume, "volume", gtk_range_get_value(range) / 10.0, NULL);
}
static gdouble
gst_msg_db_to_percent(GstMessage *msg, gchar *value_name)
{
const GValue *list;
const GValue *value;
gdouble value_db;
gdouble percent;
list = gst_structure_get_value(
gst_message_get_structure(msg), value_name);
#if GST_CHECK_VERSION(1,0,0)
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
value = g_value_array_get_nth(g_value_get_boxed(list), 0);
G_GNUC_END_IGNORE_DEPRECATIONS
#else
value = gst_value_list_get_value(list, 0);
#endif
value_db = g_value_get_double(value);
percent = pow(10, value_db / 20);
return (percent > 1.0) ? 1.0 : percent;
}
typedef struct
{
GtkProgressBar *level;
GtkRange *threshold;
} BusCbCtx;
static gboolean
gst_bus_cb(GstBus *bus, GstMessage *msg, BusCbCtx *ctx)
{
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ELEMENT &&
gst_structure_has_name(gst_message_get_structure(msg), "level")) {
GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
gchar *name = gst_element_get_name(src);
if (purple_strequal(name, "level")) {
gdouble percent;
gdouble threshold;
GstElement *valve;
percent = gst_msg_db_to_percent(msg, "rms");
percent *= 5;
if (percent > 1.0)
percent = 1.0;
gtk_progress_bar_set_fraction(ctx->level, percent);
percent = gst_msg_db_to_percent(msg, "decay");
threshold = gtk_range_get_value(ctx->threshold) / 100.0;
valve = gst_bin_get_by_name(GST_BIN(GST_ELEMENT_PARENT(src)), "valve");
g_object_set(valve, "drop", (percent < threshold), NULL);
g_object_set(ctx->level,
"text", (percent < threshold) ? _("DROP") : " ", NULL);
}
g_free(name);
}
return TRUE;
}
static void
voice_test_frame_destroy_cb(GtkObject *w, GstElement *pipeline)
{
g_return_if_fail(GST_IS_ELEMENT(pipeline));
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
}
static void
volume_scale_destroy_cb(GtkRange *volume, gpointer nul)
{
purple_prefs_set_int("/purple/media/audio/volume/input",
gtk_range_get_value(volume));
}
static gchar*
threshold_value_format_cb(GtkScale *scale, gdouble value)
{
return g_strdup_printf ("%.*f%%", gtk_scale_get_digits(scale), value);
}
static void
threshold_scale_destroy_cb(GtkRange *threshold, gpointer nul)
{
purple_prefs_set_int("/purple/media/audio/silence_threshold",
gtk_range_get_value(threshold));
}
static GtkWidget *
get_voice_test_frame(PurplePlugin *plugin)
{
GtkWidget *vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER);
GtkWidget *level = gtk_progress_bar_new();
GtkWidget *volume = gtk_hscale_new_with_range(0, 100, 1);
GtkWidget *threshold = gtk_hscale_new_with_range(0, 100, 1);
GtkWidget *label;
GtkTable *table = GTK_TABLE(gtk_table_new(2, 2, FALSE));
GstElement *pipeline;
GstBus *bus;
BusCbCtx *ctx;
g_object_set(vbox, "width-request", 500, NULL);
gtk_table_set_row_spacings(table, PIDGIN_HIG_BOX_SPACE);
gtk_table_set_col_spacings(table, PIDGIN_HIG_BOX_SPACE);
label = gtk_label_new(_("Volume:"));
g_object_set(label, "xalign", 0.0, NULL);
gtk_table_attach(table, label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
gtk_table_attach_defaults(table, volume, 1, 2, 0, 1);
label = gtk_label_new(_("Silence threshold:"));
g_object_set(label, "xalign", 0.0, "yalign", 1.0, NULL);
gtk_table_attach(table, label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
gtk_table_attach_defaults(table, threshold, 1, 2, 1, 2);
gtk_container_add(GTK_CONTAINER(vbox), level);
gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(table));
gtk_widget_show_all(vbox);
pipeline = create_pipeline();
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
gst_bus_add_signal_watch(bus);
ctx = g_new(BusCbCtx, 1);
ctx->level = GTK_PROGRESS_BAR(level);
ctx->threshold = GTK_RANGE(threshold);
g_signal_connect_data(bus, "message", G_CALLBACK(gst_bus_cb),
ctx, (GClosureNotify)g_free, 0);
gst_object_unref(bus);
g_signal_connect(volume, "value-changed",
(GCallback)on_volume_change_cb, pipeline);
gtk_range_set_value(GTK_RANGE(volume),
purple_prefs_get_int("/purple/media/audio/volume/input"));
gtk_widget_set(volume, "draw-value", FALSE, NULL);
gtk_range_set_value(GTK_RANGE(threshold),
purple_prefs_get_int("/purple/media/audio/silence_threshold"));
g_signal_connect(vbox, "destroy",
G_CALLBACK(voice_test_frame_destroy_cb), pipeline);
g_signal_connect(volume, "destroy",
G_CALLBACK(volume_scale_destroy_cb), NULL);
g_signal_connect(threshold, "format-value",
G_CALLBACK(threshold_value_format_cb), NULL);
g_signal_connect(threshold, "destroy",
G_CALLBACK(threshold_scale_destroy_cb), NULL);
return vbox;
}
static GList *
actions(PurplePlugin *plugin, gpointer context)
{
GList *l = NULL;
PurplePluginAction *act = NULL;
act = purple_plugin_action_new(_("Input and Output Settings"),
show_config);
act->user_data = get_plugin_config_frame;
l = g_list_append(l, act);
act = purple_plugin_action_new(_("Microphone Test"),
show_config);
act->user_data = get_voice_test_frame;
l = g_list_append(l, act);
return l;
}
static gboolean
plugin_unload(PurplePlugin *plugin)
{
PurpleMediaManager *manager = purple_media_manager_get();
purple_media_manager_set_active_element(manager, old_video_src);
purple_media_manager_set_active_element(manager, old_video_sink);
purple_media_manager_set_active_element(manager, old_audio_src);
purple_media_manager_set_active_element(manager, old_audio_sink);
return TRUE;
}
static PidginPluginUiInfo ui_info = {
get_plugin_config_frame,
0, /* page_num (Reserved) */
/* Padding */
NULL,
NULL,
NULL,
NULL
};
static PurplePluginInfo info =
{
PURPLE_PLUGIN_MAGIC, /**< magic */
PURPLE_MAJOR_VERSION, /**< major version */
PURPLE_MINOR_VERSION, /**< minor version */
PURPLE_PLUGIN_STANDARD, /**< type */
PIDGIN_PLUGIN_TYPE, /**< ui_requirement */
0, /**< flags */
NULL, /**< dependencies */
PURPLE_PRIORITY_DEFAULT, /**< priority */
"gtk-maiku-vvconfig", /**< id */
N_("Voice/Video Settings"), /**< name */
DISPLAY_VERSION, /**< version */
N_("Configure your microphone and webcam."), /**< summary */
N_("Configure microphone and webcam "
"settings for voice/video calls."), /**< description */
"Mike Ruprecht <cmaiku@gmail.com>", /**< author */
PURPLE_WEBSITE, /**< homepage */
plugin_load, /**< load */
plugin_unload, /**< unload */
NULL, /**< destroy */
&ui_info, /**< ui_info */
NULL, /**< extra_info */
NULL, /**< prefs_info */
actions, /**< actions */
/* padding */
NULL,
NULL,
NULL,
NULL
};
static void
init_plugin(PurplePlugin *plugin) {
}
PURPLE_INIT_PLUGIN(vvconfig, init_plugin, info)