pidgin: c840feed: This patch adds to Pidgin's vvconfig plu...
rekkanoryo at pidgin.im
rekkanoryo at pidgin.im
Thu Mar 24 20:12:04 EDT 2011
----------------------------------------------------------------------
Revision: c840feed2f7f2bdae47fc679712e4b5504e5acf4
Parent: 85ee677a7a1e46ebcec15d4ab5f674051318928e
Author: jakub.adam at ktknet.cz
Date: 03/24/11 20:01:43
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/c840feed2f7f2bdae47fc679712e4b5504e5acf4
Changelog:
This patch adds to Pidgin's vvconfig plugin a simple dialog, where user can test
if the audio input and output that he selected are actually working.
Two parameters can be also adjusted here:
* Output volume (also changeable during call)
* Threshold of silence for silence suppression (see ticket #13180)
I developed this feature in conjunction with #13180, but the dialog can also be
useful on its own, as there is now no way to try the voice configuration prior
the call. If requested, I can split the path.
Fixes #13182.
Changes against parent 85ee677a7a1e46ebcec15d4ab5f674051318928e
patched pidgin/plugins/vvconfig.c
-------------- next part --------------
============================================================
--- pidgin/plugins/vvconfig.c 9749f4a04fc225ace70d52e601361e35e813c037
+++ pidgin/plugins/vvconfig.c cf4a6f996cd8e75db00f2e14c81d72408654f315
@@ -505,19 +505,22 @@ 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 = get_plugin_config_frame(NULL);
+ 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(_("Voice/Video Settings"),
- PIDGIN_HIG_BORDER, NULL, TRUE);
+ 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",
@@ -531,17 +534,197 @@ show_config(PurplePluginAction *action)
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);
+ value = gst_value_list_get_value(list, 0);
+ 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(msg->structure, "level")) {
+
+ GstElement *src = GST_ELEMENT(GST_MESSAGE_SRC(msg));
+ gchar *name = gst_element_get_name(src);
+
+ if (!strcmp(name, "level")) {
+ gdouble percent;
+ gdouble threshold;
+ GstElement *valve;
+
+ percent = gst_msg_db_to_percent(msg, "rms");
+ gtk_progress_bar_set_fraction(ctx->level, percent * 5);
+
+ 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(_("Voice and Video Settings"),
+ 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;
}
More information about the Commits
mailing list