diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/about.c audacious-plugins-fedora-1.5.1/src/alsa/about.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/about.c 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/about.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,49 +0,0 @@
-/* XMMS - ALSA output plugin
- * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>
- *
- * 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 02110-1301, USA.
- */
-
-#include "alsa.h"
-
-void alsa_about(void)
-{
- static GtkWidget *dialog;
-
- if (dialog != NULL)
- return;
-
- dialog = audacious_info_dialog(
- _("About ALSA Driver"),
- _("Audacious ALSA Driver\n\n "
- "This program is free software; you can redistribute it and/or modify\n"
- "it under the terms of the GNU General Public License as published by\n"
- "the Free Software Foundation; either version 2 of the License, or\n"
- "(at your option) any later version.\n"
- "\n"
- "This program is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "GNU General Public License for more details.\n"
- "\n"
- "You should have received a copy of the GNU General Public License\n"
- "along with this program; if not, write to the Free Software\n"
- "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,\n"
- "USA.\n"
- "Author: Matthieu Sozeau (mattam@altern.org)"), _("OK"), FALSE, NULL, NULL);
- gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
- GTK_SIGNAL_FUNC(gtk_widget_destroyed),
- &dialog);
-}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa.c audacious-plugins-fedora-1.5.1/src/alsa/alsa.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa.c 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,100 +0,0 @@
-/* XMMS - ALSA output plugin
- * Copyright (C) 2001 Matthieu Sozeau
- *
- * 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 02110-1301, USA.
- */
-
-#include "alsa.h"
-#include <glib.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <ctype.h>
-
-struct alsa_config alsa_cfg;
-
-
-static void alsa_cleanup(void)
-{
- if (alsa_cfg.pcm_device) {
- free(alsa_cfg.pcm_device);
- alsa_cfg.pcm_device = NULL;
- }
-
- if (alsa_cfg.mixer_device) {
- free(alsa_cfg.mixer_device);
- alsa_cfg.mixer_device = NULL;
- }
-}
-
-
-static void alsa_init(void)
-{
- mcs_handle_t *cfgfile;
-
- memset(&alsa_cfg, 0, sizeof (alsa_cfg));
-
- alsa_cfg.buffer_time = 500;
- alsa_cfg.period_time = 100;
- alsa_cfg.debug = 0;
- alsa_cfg.vol.left = 100;
- alsa_cfg.vol.right = 100;
-
- cfgfile = aud_cfg_db_open();
- if (!aud_cfg_db_get_string(cfgfile, ALSA_CFGID, "pcm_device",
- &alsa_cfg.pcm_device))
- alsa_cfg.pcm_device = g_strdup("default");
- g_message("device: %s", alsa_cfg.pcm_device);
- if (!aud_cfg_db_get_string(cfgfile, ALSA_CFGID, "mixer_device",
- &alsa_cfg.mixer_device))
- alsa_cfg.mixer_device = g_strdup("PCM");
- aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "mixer_card", &alsa_cfg.mixer_card);
- aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "buffer_time", &alsa_cfg.buffer_time);
- aud_cfg_db_get_int(cfgfile, ALSA_CFGID, "period_time", &alsa_cfg.period_time);
-
- aud_cfg_db_get_bool(cfgfile, ALSA_CFGID, "debug", &alsa_cfg.debug);
- aud_cfg_db_close(cfgfile);
-
- if (dlopen("libasound.so.2", RTLD_NOW | RTLD_GLOBAL) == NULL)
- {
- g_message("Cannot load alsa library: %s", dlerror());
- /* FIXME, this plugin wont work... */
- }
-}
-
-
-static OutputPlugin alsa_op =
-{
- .description = "ALSA Output Plugin",
- .init = alsa_init,
- .cleanup = alsa_cleanup,
- .about = alsa_about,
- .configure = alsa_configure,
- .get_volume = alsa_get_volume,
- .set_volume = alsa_set_volume,
- .open_audio = alsa_open,
- .write_audio = alsa_write,
- .close_audio = alsa_close,
- .flush = alsa_flush,
- .pause = alsa_pause,
- .buffer_free = alsa_free,
- .buffer_playing = alsa_playing,
- .output_time = alsa_get_output_time,
- .written_time = alsa_get_written_time,
- .tell_audio = alsa_tell
-};
-
-OutputPlugin *alsa_oplist[] = { &alsa_op, NULL };
-
-DECLARE_PLUGIN(alsa, NULL, NULL, NULL, alsa_oplist, NULL, NULL, NULL, NULL)
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-configure.c audacious-plugins-fedora-1.5.1/src/alsa/alsa-configure.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-configure.c 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-configure.c 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,355 @@
+/*
+ * Audacious ALSA Plugin (-ng)
+ * Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
+ * Portions copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>
+ * Portions copyright (C) 2003-2005 Haavard Kvaalen
+ *
+ * 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 02110-1301, USA.
+ */
+
+#include "alsa-stdinc.h"
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+static GtkWidget *configure_win = NULL;
+static GtkWidget *devices_combo, *mixer_devices_combo;
+
+static gint current_mixer_card;
+
+gint alsaplug_mixer_new_for_card(snd_mixer_t **mixer, const gchar *card);
+
+#define GET_TOGGLE(tb) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb))
+#define GET_CHARS(edit) gtk_editable_get_chars(GTK_EDITABLE(edit), 0, -1)
+
+static void configure_win_ok_cb(GtkWidget * w, gpointer data)
+{
+ g_free(alsaplug_cfg.pcm_device);
+ alsaplug_cfg.pcm_device = GET_CHARS(GTK_COMBO(devices_combo)->entry);
+ alsaplug_cfg.mixer_card = g_strdup_printf("hw:%d", current_mixer_card);
+ alsaplug_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
+
+ gtk_widget_destroy(configure_win);
+
+ /* Save configuration */
+ mcs_handle_t *cfgfile = aud_cfg_db_open();
+ aud_cfg_db_set_string(cfgfile, "alsaplug", "pcm_device", alsaplug_cfg.pcm_device);
+ aud_cfg_db_set_string(cfgfile, "alsaplug", "mixer_card", alsaplug_cfg.mixer_card);
+ aud_cfg_db_set_string(cfgfile, "alsaplug","mixer_device", alsaplug_cfg.mixer_device);
+ aud_cfg_db_close(cfgfile);
+}
+
+void alsaplug_get_config(void)
+{
+ mcs_handle_t *cfgfile = aud_cfg_db_open();
+ aud_cfg_db_get_string(cfgfile, "alsaplug", "pcm_device", &alsaplug_cfg.pcm_device);
+ aud_cfg_db_get_string(cfgfile, "alsaplug", "mixer_card", &alsaplug_cfg.mixer_card);
+ aud_cfg_db_get_string(cfgfile, "alsaplug","mixer_device", &alsaplug_cfg.mixer_device);
+ aud_cfg_db_close(cfgfile);
+}
+
+static gint get_cards(GtkOptionMenu *omenu, GtkSignalFunc cb)
+{
+ GtkWidget *menu, *item;
+ gint card = -1, err, set = 0, curr = -1;
+
+ menu = gtk_menu_new();
+ if ((err = snd_card_next(&card)) != 0)
+ g_warning("snd_next_card() failed: %s", snd_strerror(err));
+
+ while (card > -1)
+ {
+ gchar *label;
+
+ curr++;
+ if ((err = snd_card_get_name(card, &label)) != 0)
+ {
+ g_warning("snd_carg_get_name() failed: %s",
+ snd_strerror(err));
+ break;
+ }
+
+ item = gtk_menu_item_new_with_label(label);
+ gtk_signal_connect(GTK_OBJECT(item), "activate", cb,
+ GINT_TO_POINTER(card));
+ gtk_widget_show(item);
+ gtk_menu_append(GTK_MENU(menu), item);
+ if ((err = snd_card_next(&card)) != 0)
+ {
+ g_warning("snd_next_card() failed: %s",
+ snd_strerror(err));
+ break;
+ }
+ }
+
+ gtk_option_menu_set_menu(omenu, menu);
+ return set;
+}
+
+static gint get_mixer_devices(GtkCombo *combo, const gchar *card)
+{
+ GList *items = NULL;
+ gint err;
+ snd_mixer_t *mixer;
+ snd_mixer_elem_t *current;
+
+ if ((err = alsaplug_mixer_new_for_card(&mixer, card)) < 0)
+ return err;
+
+ current = snd_mixer_first_elem(mixer);
+
+ while (current)
+ {
+ if (snd_mixer_selem_is_active(current) &&
+ snd_mixer_selem_has_playback_volume(current))
+ {
+ const gchar *sname = snd_mixer_selem_get_name(current);
+ gint index = snd_mixer_selem_get_index(current);
+ if (index)
+ items = g_list_append(items, g_strdup_printf("%s,%d", sname, index));
+ else
+ items = g_list_append(items, g_strdup(sname));
+ }
+ current = snd_mixer_elem_next(current);
+ }
+
+ gtk_combo_set_popdown_strings(combo, items);
+
+ return 0;
+}
+
+static void get_devices_for_card(GtkCombo *combo, gint card)
+{
+ GtkWidget *item;
+ gint pcm_device = -1, err;
+ snd_pcm_info_t *pcm_info = NULL;
+ snd_ctl_t *ctl;
+ gchar dev[64], *card_name;
+
+ sprintf(dev, "hw:%i", card);
+
+ if ((err = snd_ctl_open(&ctl, dev, 0)) < 0)
+ {
+ printf("snd_ctl_open() failed: %s", snd_strerror(err));
+ return;
+ }
+
+ if ((err = snd_card_get_name(card, &card_name)) != 0)
+ {
+ g_warning("snd_card_get_name() failed: %s", snd_strerror(err));
+ card_name = _("Unknown soundcard");
+ }
+
+ snd_pcm_info_alloca(&pcm_info);
+
+ for (;;)
+ {
+ char *device, *descr;
+ if ((err = snd_ctl_pcm_next_device(ctl, &pcm_device)) < 0)
+ {
+ g_warning("snd_ctl_pcm_next_device() failed: %s",
+ snd_strerror(err));
+ pcm_device = -1;
+ }
+ if (pcm_device < 0)
+ break;
+
+ snd_pcm_info_set_device(pcm_info, pcm_device);
+ snd_pcm_info_set_subdevice(pcm_info, 0);
+ snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK);
+
+ if ((err = snd_ctl_pcm_info(ctl, pcm_info)) < 0)
+ {
+ if (err != -ENOENT)
+ g_warning("get_devices_for_card(): "
+ "snd_ctl_pcm_info() "
+ "failed (%d:%d): %s.", card,
+ pcm_device, snd_strerror(err));
+ continue;
+ }
+
+ device = g_strdup_printf("hw:%d,%d", card, pcm_device);
+ descr = g_strconcat(card_name, ": ",
+ snd_pcm_info_get_name(pcm_info),
+ " (", device, ")", NULL);
+ item = gtk_list_item_new_with_label(descr);
+ gtk_widget_show(item);
+ g_free(descr);
+ gtk_combo_set_item_string(combo, GTK_ITEM(item), device);
+ g_free(device);
+ gtk_container_add(GTK_CONTAINER(combo->list), item);
+ }
+
+ snd_ctl_close(ctl);
+}
+
+
+
+static void get_devices(GtkCombo *combo)
+{
+ GtkWidget *item;
+ gint card = -1;
+ gint err = 0;
+ gchar *descr;
+
+ descr = g_strdup_printf(_("Default PCM device (%s)"), "default");
+ item = gtk_list_item_new_with_label(descr);
+ gtk_widget_show(item);
+ g_free(descr);
+ gtk_combo_set_item_string(combo, GTK_ITEM(item), "default");
+ gtk_container_add(GTK_CONTAINER(combo->list), item);
+
+ if ((err = snd_card_next(&card)) != 0)
+ {
+ g_warning("snd_next_card() failed: %s", snd_strerror(err));
+ return;
+ }
+
+ while (card > -1)
+ {
+ get_devices_for_card(combo, card);
+ if ((err = snd_card_next(&card)) != 0)
+ {
+ g_warning("snd_next_card() failed: %s",
+ snd_strerror(err));
+ break;
+ }
+ }
+}
+
+static void mixer_card_cb(GtkWidget * widget, gpointer card)
+{
+ gchar scratch[128];
+
+ if (current_mixer_card == GPOINTER_TO_INT(card))
+ return;
+ current_mixer_card = GPOINTER_TO_INT(card);
+
+ snprintf(scratch, 128, "hw:%d", current_mixer_card);
+ get_mixer_devices(GTK_COMBO(mixer_devices_combo),
+ scratch);
+}
+
+void alsaplug_configure(void)
+{
+ GtkWidget *vbox, *notebook;
+ GtkWidget *dev_vbox, *adevice_frame, *adevice_box;
+ GtkWidget *mixer_frame, *mixer_box, *mixer_table, *mixer_card_om;
+ GtkWidget *mixer_card_label, *mixer_device_label;
+ GtkWidget *bbox, *ok, *cancel;
+
+ gint mset;
+
+ if (configure_win)
+ {
+ gtk_window_present(GTK_WINDOW(configure_win));
+ return;
+ }
+
+ configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &configure_win);
+ gtk_window_set_title(GTK_WINDOW(configure_win),
+ _("ALSA Driver configuration"));
+ gtk_window_set_policy(GTK_WINDOW(configure_win),
+ FALSE, TRUE, FALSE);
+ gtk_container_border_width(GTK_CONTAINER(configure_win), 10);
+
+ vbox = gtk_vbox_new(FALSE, 10);
+ gtk_container_add(GTK_CONTAINER(configure_win), vbox);
+
+ notebook = gtk_notebook_new();
+ gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+ dev_vbox = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(dev_vbox), 5);
+
+ adevice_frame = gtk_frame_new(_("Audio device:"));
+ gtk_box_pack_start(GTK_BOX(dev_vbox), adevice_frame, FALSE, FALSE, 0);
+
+ adevice_box = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(adevice_box), 5);
+ gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_box);
+
+ devices_combo = gtk_combo_new();
+ gtk_box_pack_start(GTK_BOX(adevice_box), devices_combo,
+ FALSE, FALSE, 0);
+ get_devices(GTK_COMBO(devices_combo));
+ gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(devices_combo)->entry),
+ alsaplug_cfg.pcm_device);
+
+ mixer_frame = gtk_frame_new(_("Mixer:"));
+ gtk_box_pack_start(GTK_BOX(dev_vbox), mixer_frame, FALSE, FALSE, 0);
+
+ mixer_box = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(mixer_box), 5);
+ gtk_container_add(GTK_CONTAINER(mixer_frame), mixer_box);
+
+ mixer_table = gtk_table_new(2, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(mixer_table), 5);
+ gtk_table_set_col_spacings(GTK_TABLE(mixer_table), 5);
+ gtk_box_pack_start(GTK_BOX(mixer_box), mixer_table, FALSE, FALSE, 0);
+
+ mixer_card_label = gtk_label_new(_("Mixer card:"));
+ gtk_label_set_justify(GTK_LABEL(mixer_card_label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment(GTK_MISC(mixer_card_label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(mixer_table), mixer_card_label,
+ 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
+
+ mixer_card_om = gtk_option_menu_new();
+ mset = get_cards(GTK_OPTION_MENU(mixer_card_om),
+ (GtkSignalFunc)mixer_card_cb);
+
+ gtk_table_attach(GTK_TABLE(mixer_table), mixer_card_om,
+ 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+
+ mixer_device_label = gtk_label_new(_("Mixer device:"));
+ gtk_label_set_justify(GTK_LABEL(mixer_device_label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment(GTK_MISC(mixer_device_label), 0, 0.5);
+ gtk_table_attach(GTK_TABLE(mixer_table), mixer_device_label,
+ 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ mixer_devices_combo = gtk_combo_new();
+ gtk_option_menu_set_history(GTK_OPTION_MENU(mixer_card_om), mset);
+ get_mixer_devices(GTK_COMBO(mixer_devices_combo), alsaplug_cfg.mixer_card);
+ gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(mixer_devices_combo)->entry),
+ alsaplug_cfg.mixer_device);
+
+ gtk_table_attach(GTK_TABLE(mixer_table), mixer_devices_combo,
+ 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dev_vbox,
+ gtk_label_new(_("Device settings")));
+
+ bbox = gtk_hbutton_box_new();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+ gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+ gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+ ok = gtk_button_new_with_label(_("OK"));
+ gtk_signal_connect(GTK_OBJECT(ok), "clicked", (GCallback)configure_win_ok_cb, NULL);
+ GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+ gtk_widget_grab_default(ok);
+
+ cancel = gtk_button_new_with_label(_("Cancel"));
+ gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
+ (GCallback)gtk_widget_destroy, GTK_OBJECT(configure_win));
+ GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+ gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+ gtk_widget_show_all(configure_win);
+}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-core.c audacious-plugins-fedora-1.5.1/src/alsa/alsa-core.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-core.c 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-core.c 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,511 @@
+/*
+ * Audacious ALSA Plugin (-ng)
+ * Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
+ *
+ * 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 02110-1301, USA.
+ */
+
+#define ALSA_DEBUG
+#include "alsa-stdinc.h"
+
+alsaplug_cfg_t alsaplug_cfg;
+
+static snd_pcm_t *pcm_handle = NULL;
+static alsaplug_ringbuf_t pcm_ringbuf;
+static gboolean pcm_going = FALSE;
+static GThread *audio_thread = NULL;
+static gint bps;
+
+static gsize wr_total = 0;
+static gsize wr_hwframes = 0;
+
+static gint flush_request, paused;
+
+static GMutex * pcm_state_mutex;
+static GCond * pcm_state_cond, * pcm_flush_cond;
+
+extern void alsaplug_configure(void);
+extern void alsaplug_get_config(void);
+
+/********************************************************************************
+ * ALSA Mixer setting functions. *
+ ********************************************************************************/
+
+static snd_mixer_t *amixer = NULL;
+static gboolean mixer_ready = FALSE;
+
+static snd_mixer_elem_t *
+alsaplug_get_mixer_elem_by_name(snd_mixer_t *mixer, gchar *name)
+{
+ snd_mixer_selem_id_t *selem_id;
+ snd_mixer_elem_t *elem;
+
+ g_return_val_if_fail(mixer != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ snd_mixer_selem_id_alloca(&selem_id);
+ snd_mixer_selem_id_set_name(selem_id, name);
+
+ elem = snd_mixer_find_selem(mixer, selem_id);
+ if (elem == NULL)
+ return NULL;
+
+ snd_mixer_selem_set_playback_volume_range(elem, 0, 100);
+
+ return elem;
+}
+
+/* try to determine the best choice... may need tweaking. --nenolod */
+static snd_mixer_elem_t *
+alsaplug_guess_mixer_elem(snd_mixer_t *mixer)
+{
+ gchar *elem_names[] = { "Wave", "PCM", "Front", "Master" };
+ gint i;
+ snd_mixer_elem_t *elem;
+
+ if (alsaplug_cfg.mixer_device != NULL)
+ return alsaplug_get_mixer_elem_by_name(mixer, alsaplug_cfg.mixer_device);
+
+ for (i = 0; i < G_N_ELEMENTS(elem_names); i++)
+ {
+ elem = alsaplug_get_mixer_elem_by_name(mixer, elem_names[i]);
+ if (elem != NULL)
+ return elem;
+ }
+
+ return NULL;
+}
+
+gint
+alsaplug_mixer_new_for_card(snd_mixer_t **mixer, const gchar *card)
+{
+ gint ret;
+
+ ret = snd_mixer_open(mixer, 0);
+ if (ret < 0)
+ {
+ _ERROR("mixer initialization failed: %s", snd_strerror(ret));
+ return ret;
+ }
+
+ ret = snd_mixer_attach(*mixer, card);
+ if (ret < 0)
+ {
+ snd_mixer_close(*mixer);
+ _ERROR("failed to attach to hardware mixer: %s", snd_strerror(ret));
+ return ret;
+ }
+
+ ret = snd_mixer_selem_register(*mixer, NULL, NULL);
+ if (ret < 0)
+ {
+ snd_mixer_detach(*mixer, card);
+ snd_mixer_close(*mixer);
+ _ERROR("failed to register hardware mixer: %s", snd_strerror(ret));
+ return ret;
+ }
+
+ ret = snd_mixer_load(*mixer);
+ if (ret < 0)
+ {
+ snd_mixer_detach(*mixer, card);
+ snd_mixer_close(*mixer);
+ _ERROR("failed to load hardware mixer controls: %s", snd_strerror(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+gint
+alsaplug_mixer_new(snd_mixer_t **mixer)
+{
+ return alsaplug_mixer_new_for_card(mixer, alsaplug_cfg.mixer_card);
+}
+
+static void
+alsaplug_set_volume(gint l, gint r)
+{
+ snd_mixer_elem_t *elem = alsaplug_guess_mixer_elem(amixer);
+
+ if (elem == NULL)
+ return;
+
+ if (snd_mixer_selem_is_playback_mono(elem))
+ {
+ gint vol = (l > r) ? l : r;
+
+ snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_MONO, vol);
+
+ if (snd_mixer_selem_has_playback_switch(elem))
+ snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_MONO, vol != 0);
+ }
+ else
+ {
+ snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, l);
+ snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, r);
+
+ if (snd_mixer_selem_has_playback_switch(elem) && !snd_mixer_selem_has_playback_switch_joined(elem))
+ {
+ snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, l != 0);
+ snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, r != 0);
+ }
+ }
+
+ snd_mixer_handle_events(amixer);
+}
+
+static void
+alsaplug_get_volume(gint *l, gint *r)
+{
+ snd_mixer_elem_t *elem = alsaplug_guess_mixer_elem(amixer);
+
+ if (elem == NULL)
+ return;
+
+ snd_mixer_handle_events(amixer);
+
+ *l = 0;
+ *r = 0;
+
+ if (snd_mixer_selem_is_playback_mono(elem))
+ {
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, (glong *) l);
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, (glong *) r);
+ }
+ else
+ {
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, (glong *) l);
+ snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, (glong *) r);
+ }
+}
+
+/********************************************************************************
+ * ALSA PCM I/O functions. *
+ ********************************************************************************/
+
+static void
+alsaplug_write_buffer(gpointer data, gint length)
+{
+ snd_pcm_sframes_t wr_frames;
+
+ while (length > 0)
+ {
+ gint frames = snd_pcm_bytes_to_frames(pcm_handle, length);
+ wr_frames = snd_pcm_writei(pcm_handle, data, frames);
+
+ if (wr_frames > 0)
+ {
+ gint written = snd_pcm_frames_to_bytes(pcm_handle, wr_frames);
+ length -= written;
+ data += written;
+ }
+ else
+ {
+ gint err = snd_pcm_recover(pcm_handle, wr_frames, 1);
+ if (err < 0)
+ _ERROR("(write) snd_pcm_recover: %s", snd_strerror(err));
+
+ return;
+ }
+ }
+}
+
+static gpointer
+alsaplug_loop(gpointer unused)
+{
+ guchar buf[2048];
+ int size;
+
+ while (pcm_going)
+ {
+ g_mutex_lock (pcm_state_mutex);
+
+ if (flush_request != -1)
+ {
+ alsaplug_ringbuffer_reset (& pcm_ringbuf);
+ snd_pcm_drop(pcm_handle);
+ snd_pcm_prepare(pcm_handle);
+ wr_total = flush_request * (long long) bps / 1000;
+ flush_request = -1;
+
+ g_cond_broadcast(pcm_flush_cond);
+ }
+
+ size = alsaplug_ringbuffer_used (& pcm_ringbuf);
+
+ if (size == 0 || paused)
+ {
+ g_cond_wait (pcm_state_cond, pcm_state_mutex);
+ g_mutex_unlock (pcm_state_mutex);
+ continue;
+ }
+
+ if (size > sizeof buf)
+ size = sizeof buf;
+
+ alsaplug_ringbuffer_read (& pcm_ringbuf, buf, size);
+ g_mutex_unlock (pcm_state_mutex);
+ alsaplug_write_buffer (buf, size);
+ }
+
+ snd_pcm_drain(pcm_handle);
+ snd_pcm_close(pcm_handle);
+ pcm_handle = NULL;
+ audio_thread = NULL;
+ alsaplug_ringbuffer_destroy(&pcm_ringbuf);
+
+ return NULL;
+}
+
+/********************************************************************************
+ * Output Plugin API implementation. *
+ ********************************************************************************/
+
+/*static OutputPluginInitStatus*/
+void alsaplug_init(void)
+{
+ gint card = -1;
+
+ pcm_state_mutex = g_mutex_new();
+ pcm_state_cond = g_cond_new();
+ pcm_flush_cond = g_cond_new();
+
+ /* if (snd_card_next(&card) != 0)
+ return OUTPUT_PLUGIN_INIT_NO_DEVICES;*/
+
+ alsaplug_get_config();
+ if (alsaplug_cfg.pcm_device == NULL)
+ alsaplug_cfg.pcm_device = g_strdup("default");
+ if (alsaplug_cfg.mixer_card == NULL)
+ alsaplug_cfg.mixer_card = g_strdup("default");
+
+ /* return OUTPUT_PLUGIN_INIT_FOUND_DEVICES;*/
+}
+
+static gint
+alsaplug_open_audio(AFormat fmt, gint rate, gint nch)
+{
+ gint err, bitwidth, ringbuf_size;
+ snd_pcm_format_t afmt;
+ snd_pcm_hw_params_t *hwparams = NULL;
+
+ afmt = alsaplug_format_convert(fmt);
+ if (afmt == SND_PCM_FORMAT_UNKNOWN)
+ {
+ _ERROR("unsupported format requested: %d -> %d", fmt, afmt);
+ return -1;
+ }
+
+ if (!alsaplug_mixer_new(&amixer))
+ mixer_ready = TRUE;
+
+ if ((err = snd_pcm_open(&pcm_handle, alsaplug_cfg.pcm_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+ {
+ _ERROR("snd_pcm_open: %s", snd_strerror(err));
+ pcm_handle = NULL;
+ return -1;
+ }
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_hw_params_any(pcm_handle, hwparams);
+ snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
+ snd_pcm_hw_params_set_format(pcm_handle, hwparams, afmt);
+ snd_pcm_hw_params_set_channels(pcm_handle, hwparams, nch);
+ snd_pcm_hw_params_set_rate(pcm_handle, hwparams, rate, 0);
+
+ err = snd_pcm_hw_params(pcm_handle, hwparams);
+ if (err < 0)
+ {
+ _ERROR("snd_pcm_hw_params failed: %s", snd_strerror(err));
+ return -1;
+ }
+
+ bitwidth = snd_pcm_format_physical_width(afmt);
+ bps = (rate * bitwidth * nch) >> 3;
+ ringbuf_size = aud_cfg->output_buffer_size * bps / 1000;
+ if (alsaplug_ringbuffer_init(&pcm_ringbuf, ringbuf_size) == -1) {
+ _ERROR("alsaplug_ringbuffer_init failed");
+ return -1;
+ }
+ pcm_going = TRUE;
+ flush_request = -1;
+
+ audio_thread = g_thread_create(alsaplug_loop, NULL, TRUE, NULL);
+ return 1;
+}
+
+static void
+alsaplug_close_audio(void)
+{
+ g_mutex_lock(pcm_state_mutex);
+
+ pcm_going = FALSE;
+ wr_total = 0;
+ wr_hwframes = 0;
+ bps = 0;
+
+ g_cond_broadcast (pcm_state_cond);
+ g_mutex_unlock(pcm_state_mutex);
+
+ if (audio_thread != NULL)
+ g_thread_join(audio_thread);
+
+ audio_thread = NULL;
+
+ if (mixer_ready == TRUE)
+ {
+ snd_mixer_detach(amixer, alsaplug_cfg.mixer_card);
+ snd_mixer_close(amixer);
+
+ amixer = NULL;
+ mixer_ready = FALSE;
+ }
+}
+
+static void
+alsaplug_write_audio(gpointer data, gint length)
+{
+ g_mutex_lock(pcm_state_mutex);
+ wr_total += length;
+ alsaplug_ringbuffer_write(&pcm_ringbuf, data, length);
+ g_cond_broadcast (pcm_state_cond);
+ g_mutex_unlock(pcm_state_mutex);
+}
+
+static gint
+alsaplug_output_time(void)
+{
+ gint ret = 0;
+ snd_pcm_sframes_t delay;
+ gsize bytes = wr_total;
+
+ g_mutex_lock(pcm_state_mutex);
+
+ if (pcm_going && pcm_handle != NULL)
+ {
+ guint d = alsaplug_ringbuffer_used(&pcm_ringbuf);
+
+ if (!snd_pcm_delay(pcm_handle, &delay))
+ d += snd_pcm_frames_to_bytes(pcm_handle, delay);
+
+ if (bytes < d)
+ bytes = 0;
+ else
+ bytes -= d;
+
+ ret = bytes * (long long) 1000 / bps;
+ }
+
+ g_mutex_unlock(pcm_state_mutex);
+
+ return ret;
+}
+
+static gint
+alsaplug_written_time(void)
+{
+ gint ret = 0;
+
+ g_mutex_lock(pcm_state_mutex);
+
+ if (pcm_going)
+ ret = wr_total * (long long) 1000 / bps;
+
+ g_mutex_unlock(pcm_state_mutex);
+
+ return ret;
+}
+
+static gint
+alsaplug_buffer_free(void)
+{
+ gint ret;
+
+ g_mutex_lock(pcm_state_mutex);
+
+ if (pcm_going == FALSE)
+ ret = 0;
+ else
+ ret = alsaplug_ringbuffer_free(&pcm_ringbuf);
+
+ g_mutex_unlock(pcm_state_mutex);
+
+ return ret;
+}
+
+static void
+alsaplug_flush(gint time)
+{
+ /* make the request... */
+ g_mutex_lock(pcm_state_mutex);
+ flush_request = time;
+ g_cond_broadcast(pcm_state_cond);
+
+ /* ...then wait for the transaction to complete. */
+ g_cond_wait(pcm_flush_cond, pcm_state_mutex);
+ g_mutex_unlock(pcm_state_mutex);
+}
+
+static gint
+alsaplug_buffer_playing(void)
+{
+ gint ret;
+
+ g_mutex_lock(pcm_state_mutex);
+
+ if (pcm_going == FALSE)
+ ret = 0;
+ else
+ ret = alsaplug_ringbuffer_used(&pcm_ringbuf) != 0;
+
+ g_mutex_unlock(pcm_state_mutex);
+
+ return ret;
+}
+
+static void
+alsaplug_pause(short p)
+{
+ g_mutex_lock (pcm_state_mutex);
+ paused = p;
+ g_cond_broadcast (pcm_state_cond);
+ g_mutex_unlock (pcm_state_mutex);
+}
+
+/********************************************************************************
+ * Plugin glue. *
+ ********************************************************************************/
+
+static OutputPlugin alsa_op = {
+ .description = "ALSA Output Plugin (-ng)",
+ /* .probe_priority = 1,*/
+ .init = alsaplug_init,
+ .open_audio = alsaplug_open_audio,
+ .close_audio = alsaplug_close_audio,
+ .write_audio = alsaplug_write_audio,
+ .output_time = alsaplug_output_time,
+ .written_time = alsaplug_written_time,
+ .buffer_free = alsaplug_buffer_free,
+ .buffer_playing = alsaplug_buffer_playing,
+ .flush = alsaplug_flush,
+ .pause = alsaplug_pause,
+ .set_volume = alsaplug_set_volume,
+ .get_volume = alsaplug_get_volume,
+ .configure = alsaplug_configure,
+};
+
+OutputPlugin *alsa_oplist[] = { &alsa_op, NULL };
+SIMPLE_OUTPUT_PLUGIN(alsa, alsa_oplist);
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-debug.h audacious-plugins-fedora-1.5.1/src/alsa/alsa-debug.h
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-debug.h 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-debug.h 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2005 Ralf Ertzinger
+ *
+ * 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 02110-1301, USA.
+ */
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+#define _ENTER _DEBUG("enter")
+#define _LEAVE _DEBUG("leave"); return
+#define _MESSAGE(tag, string, ...) do { fprintf(stderr, "%s: ALSA: %s:%d (%s): " string "\n", \
+ tag, __FILE__, __LINE__, __func__, ##__VA_ARGS__); } while(0)
+
+#define _ERROR(...) _MESSAGE("ERROR", __VA_ARGS__)
+
+#ifdef ALSA_DEBUG
+#define _DEBUG(...) _MESSAGE("DEBUG", __VA_ARGS__)
+#else
+#define _DEBUG(...) {}
+#endif
+
+#endif
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa.h audacious-plugins-fedora-1.5.1/src/alsa/alsa.h
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa.h 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,79 +0,0 @@
-/* XMMS - ALSA output plugin
- * Copyright (C) 2001-2003 Matthieu Sozeau
- * Copyright (C) 1998-2003 Peter Alm, Mikael Alm, Olle Hallnas,
- * Thomas Nilsson and 4Front Technologies
- * Copyright (C) 1999-2004 Håvard Kvålen
- *
- * 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 02110-1301, USA.
- */
-#ifndef ALSA_H
-#define ALSA_H
-
-#define NDEBUG
-
-#include "config.h"
-
-#include <audacious/plugin.h>
-#include <audacious/i18n.h>
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-#include <alsa/asoundlib.h>
-#include <alsa/pcm_plugin.h>
-
-#include <gtk/gtk.h>
-
-#define ALSA_CFGID "ALSA"
-
-extern OutputPlugin op;
-
-struct alsa_config
-{
- char *pcm_device;
- int mixer_card;
- char *mixer_device;
- int buffer_time;
- int period_time;
- gboolean debug;
- struct
- {
- int left, right;
- } vol;
-};
-
-extern struct alsa_config alsa_cfg;
-
-void alsa_about(void);
-void alsa_configure(void);
-int alsa_get_mixer(snd_mixer_t **mixer, int card);
-void alsa_save_config(void);
-
-void alsa_get_volume(int *l, int *r);
-void alsa_set_volume(int l, int r);
-
-int alsa_playing(void);
-int alsa_free(void);
-void alsa_write(void *ptr, int length);
-void alsa_close(void);
-void alsa_flush(int time);
-void alsa_pause(short p);
-int alsa_open(AFormat fmt, int rate, int nch);
-int alsa_get_output_time(void);
-int alsa_get_written_time(void);
-void alsa_tell(AFormat * fmt, gint * rate, gint * nch);
-
-extern GStaticMutex alsa_mutex;
-
-#endif
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-ringbuffer.c audacious-plugins-fedora-1.5.1/src/alsa/alsa-ringbuffer.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-ringbuffer.c 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-ringbuffer.c 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,366 @@
+/*
+ * 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 02110-1301, USA.
+ */
+
+/*
+ * Ringbuffer implementation
+ *
+ * GPL
+ */
+#include <string.h>
+#include "alsa-ringbuffer.h"
+#include "alsa-debug.h"
+
+#ifdef ALSAPLUG_RINGBUFFER_DEBUG
+/*
+ * An internal assertion function to make sure that the
+ * ringbuffer structure is consistient.
+ *
+ * WARNING: This function will call abort() if the ringbuffer
+ * is found to be inconsistient.
+ */
+static void _alsaplug_ringbuffer_assert(alsaplug_ringbuf_t* rb) {
+
+ unsigned int realused;
+
+ _ENTER;
+
+ _DEBUG("rb->buf=%p, rb->end=%p, rb->wp=%p, rb->rp=%p, rb->free=%u, rb->used=%u, rb->size=%u",
+ rb->buf, rb->end, rb->wp, rb->rp, rb->free, rb->used, rb->size);
+
+ if (0 == rb->size) {
+ _ERROR("Buffer size is 0");
+ abort();
+ }
+
+ if (NULL == rb->buf) {
+ _ERROR("Buffer start is NULL");
+ abort();
+ }
+
+ if (rb->used+rb->free != rb->size) {
+ _ERROR("rb->free and rb->used do not add up to rb->size");
+ abort();
+ }
+
+ if (rb->buf+(rb->size-1) != rb->end) {
+ _ERROR("rb->buf and rb->end not rb->size bytes apart");
+ abort();
+ }
+
+ if ((rb->wp < rb->buf) || (rb->wp > rb->end)) {
+ _ERROR("Write pointer outside buffer space");
+ abort();
+ }
+
+ if ((rb->rp < rb->buf) || (rb->rp > rb->end)) {
+ _ERROR("Read pointer outside buffer space");
+ abort();
+ }
+
+ if (rb->rp <= rb->wp) {
+ realused = rb->wp - rb->rp;
+ } else {
+ realused = (rb->end - rb->rp) + 1 + (rb->wp-rb->buf);
+ }
+
+ if (rb->used != realused) {
+ _ERROR("Usage count is inconsistient (is %d, should be %d)", rb->used, realused);
+ abort();
+ }
+
+ _LEAVE;
+}
+#endif
+
+/*
+ * Reset a ringbuffer structure (i.e. discard
+ * all data inside of it)
+ */
+void alsaplug_ringbuffer_reset(alsaplug_ringbuf_t* rb) {
+
+ _ENTER;
+
+ _ALSAPLUG_RINGBUFFER_LOCK(rb->lock);
+
+ rb->wp = rb->buf;
+ rb->rp = rb->buf;
+ rb->free = rb->size;
+ rb->used = 0;
+ rb->end = rb->buf+(rb->size-1);
+
+ _ALSAPLUG_RINGBUFFER_UNLOCK(rb->lock);
+
+ _LEAVE;
+}
+
+/*
+ * Initialize a ringbuffer structure (including
+ * memory allocation.
+ *
+ * Return -1 on error
+ */
+int alsaplug_ringbuffer_init(alsaplug_ringbuf_t* rb, unsigned int size) {
+
+ _ENTER;
+
+ if (0 == size) {
+ _LEAVE -1;
+ }
+
+ if (NULL == (rb->buf = malloc(size))) {
+ _LEAVE -1;
+ }
+ rb->size = size;
+
+ if (NULL == (rb->lock = g_mutex_new())) {
+ _LEAVE -1;
+ }
+
+ rb->_free_lock = 1;
+
+ alsaplug_ringbuffer_reset(rb);
+
+ ASSERT_RB(rb);
+
+ _LEAVE 0;
+}
+
+/*
+ * Initialize a ringbuffer structure (including
+ * memory allocation.
+ * The mutex to be used is passed in the function call.
+ * The mutex must not be held while calling this function.
+ *
+ * Return -1 on error
+ */
+int alsaplug_ringbuffer_init_with_lock(alsaplug_ringbuf_t* rb, unsigned int size, alsaplug_ringbuffer_mutex_t* lock) {
+
+ _ENTER;
+
+ if (0 == size) {
+ _LEAVE -1;
+ }
+
+ rb->lock = lock;
+ rb->_free_lock = 0;
+
+ if (NULL == (rb->buf = malloc(size))) {
+ _LEAVE -1;
+ }
+ rb->size = size;
+ alsaplug_ringbuffer_reset(rb);
+
+ ASSERT_RB(rb);
+
+ _LEAVE 0;
+}
+
+/*
+ * Write size bytes at buf into the ringbuffer.
+ * Return -1 on error (not enough space in buffer)
+ */
+int alsaplug_ringbuffer_write(alsaplug_ringbuf_t* rb, void* buf, unsigned int size) {
+
+ int ret = -1;
+ int endfree;
+
+ _ENTER;
+
+ _ALSAPLUG_RINGBUFFER_LOCK(rb->lock);
+
+ ASSERT_RB(rb);
+
+ if (rb->free < size) {
+ ret = -1;
+ goto out;
+ }
+
+ endfree = (rb->end - rb->wp)+1;
+ if (endfree < size) {
+ /*
+ * There is enough space in the buffer, but not in
+ * one piece. We need to split the copy into two parts.
+ */
+ memcpy(rb->wp, buf, endfree);
+ memcpy(rb->buf, buf+endfree, size-endfree);
+ rb->wp = rb->buf + (size-endfree);
+ } else if (endfree > size) {
+ /*
+ * There is more space than needed at the end
+ */
+ memcpy(rb->wp, buf, size);
+ rb->wp += size;
+ } else {
+ /*
+ * There is exactly the space needed at the end.
+ * We need to wrap around the read pointer.
+ */
+ memcpy(rb->wp, buf, size);
+ rb->wp = rb->buf;
+ }
+
+ rb->free -= size;
+ rb->used += size;
+
+ ret = 0;
+
+out:
+ ASSERT_RB(rb);
+ _ALSAPLUG_RINGBUFFER_UNLOCK(rb->lock);
+
+ _LEAVE ret;
+}
+
+/*
+ * Read size byes from buffer into buf.
+ * Return -1 on error (not enough data in buffer)
+ */
+int alsaplug_ringbuffer_read(alsaplug_ringbuf_t* rb, void* buf, unsigned int size) {
+
+ int ret;
+
+ _ENTER;
+
+ _ALSAPLUG_RINGBUFFER_LOCK(rb->lock);
+ ret = alsaplug_ringbuffer_read_locked(rb, buf, size);
+ _ALSAPLUG_RINGBUFFER_UNLOCK(rb->lock);
+
+ _LEAVE ret;
+}
+
+/*
+ * Read size bytes from buffer into buf, assuming the buffer lock
+ * is already held.
+ * Return -1 on error (not enough data in buffer)
+ */
+int alsaplug_ringbuffer_read_locked(alsaplug_ringbuf_t* rb, void* buf, unsigned int size) {
+
+ int endused;
+
+ _ENTER;
+
+ ASSERT_RB(rb);
+
+ if (rb->used < size) {
+ /* Not enough bytes in buffer */
+ _LEAVE -1;
+ }
+
+ if (rb->rp < rb->wp) {
+ /*
+ Read pointer is behind write pointer, all the data is available in one chunk
+ */
+ memcpy(buf, rb->rp, size);
+ rb->rp += size;
+ } else {
+ /*
+ * Read pointer is before write pointer
+ */
+ endused = (rb->end - rb->rp)+1;
+
+ if (size < endused) {
+ /*
+ * Data is available in one chunk
+ */
+ memcpy(buf, rb->rp, size);
+ rb->rp += size;
+ } else {
+ /*
+ * There is enough data in the buffer, but it is fragmented.
+ */
+ memcpy(buf, rb->rp, endused);
+ memcpy(buf+endused, rb->buf, size-endused);
+ rb->rp = rb->buf + (size-endused);
+ }
+ }
+
+ rb->free += size;
+ rb->used -= size;
+
+ ASSERT_RB(rb);
+
+ _LEAVE 0;
+}
+
+/*
+ * Return the amount of free space currently in the rb
+ */
+unsigned int alsaplug_ringbuffer_free(alsaplug_ringbuf_t* rb) {
+
+ unsigned int f;
+
+ _ENTER;
+
+ _ALSAPLUG_RINGBUFFER_LOCK(rb->lock);
+ f = alsaplug_ringbuffer_free_locked(rb);
+ _ALSAPLUG_RINGBUFFER_UNLOCK(rb->lock);
+
+ _LEAVE f;
+}
+
+/*
+ * Return the amount of free space currently in the rb.
+ * Assume the rb lock is already being held.
+ */
+unsigned int alsaplug_ringbuffer_free_locked(alsaplug_ringbuf_t* rb) {
+
+ _ENTER;
+
+ _LEAVE rb->free;
+}
+
+
+/*
+ * Return the amount of used space currently in the rb
+ */
+unsigned int alsaplug_ringbuffer_used(alsaplug_ringbuf_t* rb) {
+
+ unsigned int u;
+
+ _ENTER;
+
+ _ALSAPLUG_RINGBUFFER_LOCK(rb->lock);
+ u = alsaplug_ringbuffer_used_locked(rb);
+ _ALSAPLUG_RINGBUFFER_UNLOCK(rb->lock);
+
+ _LEAVE u;
+}
+
+/*
+ * Return the amount of used space currently in the rb.
+ * Assume the rb lock is already being held.
+ */
+unsigned int alsaplug_ringbuffer_used_locked(alsaplug_ringbuf_t* rb) {
+
+ _ENTER;
+
+ _LEAVE rb->used;
+}
+
+
+/*
+ * destroy a ringbuffer
+ */
+void alsaplug_ringbuffer_destroy(alsaplug_ringbuf_t* rb) {
+
+ _ENTER;
+ free(rb->buf);
+ if (rb->_free_lock) {
+ g_mutex_free(rb->lock);
+ }
+
+ _LEAVE;
+}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-ringbuffer.h audacious-plugins-fedora-1.5.1/src/alsa/alsa-ringbuffer.h
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-ringbuffer.h 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-ringbuffer.h 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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 02110-1301, USA.
+ */
+
+#ifndef _ALSAPLUG_RINGBUFFER_H
+#define _ALSAPLUG_RINGBUFFER_H
+
+#include <glib.h>
+
+typedef GMutex alsaplug_ringbuffer_mutex_t;
+#define _ALSAPLUG_RINGBUFFER_LOCK(L) g_mutex_lock(L)
+#define _ALSAPLUG_RINGBUFFER_UNLOCK(L) g_mutex_unlock(L)
+
+#include <stdlib.h>
+
+#ifdef ALSAPLUG_RINGBUFFER_DEBUG
+#define ASSERT_RB(buf) _alsaplug_ringbuffer_assert(buf)
+#else
+#define ASSERT_RB(buf)
+#endif
+
+typedef struct {
+ alsaplug_ringbuffer_mutex_t* lock;
+ char _free_lock;
+ char* buf;
+ char* end;
+ char* wp;
+ char* rp;
+ unsigned int free;
+ unsigned int used;
+ unsigned int size;
+} alsaplug_ringbuf_t;
+
+int alsaplug_ringbuffer_init(alsaplug_ringbuf_t* rb, unsigned int size);
+int alsaplug_ringbuffer_init_with_lock(alsaplug_ringbuf_t* rb, unsigned int size, alsaplug_ringbuffer_mutex_t* lock);
+int alsaplug_ringbuffer_write(alsaplug_ringbuf_t* rb, void* buf, unsigned int size);
+int alsaplug_ringbuffer_read(alsaplug_ringbuf_t* rb, void* buf, unsigned int size);
+int alsaplug_ringbuffer_read_locked(alsaplug_ringbuf_t* rb, void* buf, unsigned int size);
+void alsaplug_ringbuffer_reset(alsaplug_ringbuf_t* rb);
+unsigned int alsaplug_ringbuffer_free(alsaplug_ringbuf_t* rb);
+unsigned int alsaplug_ringbuffer_free_locked(alsaplug_ringbuf_t* rb);
+unsigned int alsaplug_ringbuffer_used(alsaplug_ringbuf_t* rb);
+unsigned int alsaplug_ringbuffer_used_locked(alsaplug_ringbuf_t* rb);
+void alsaplug_ringbuffer_destroy(alsaplug_ringbuf_t* rb);
+
+#endif
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-stdinc.h audacious-plugins-fedora-1.5.1/src/alsa/alsa-stdinc.h
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-stdinc.h 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-stdinc.h 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,36 @@
+/*
+ * Audacious ALSA Plugin (-ng)
+ * Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
+ *
+ * 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 02110-1301, USA.
+ */
+
+#ifndef _ALSA_STDINC_H_GUARD
+#define _ALSA_STDINC_H_GUARD
+
+#include <audacious/plugin.h>
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#define ALSA_PCM_NEW_SW_PARAMS_API
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_plugin.h>
+
+#include <gtk/gtk.h>
+
+#include "alsa-debug.h"
+#include "alsa-types.h"
+#include "alsa-ringbuffer.h"
+
+#endif
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-types.h audacious-plugins-fedora-1.5.1/src/alsa/alsa-types.h
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-types.h 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-types.h 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,40 @@
+/*
+ * Audacious ALSA Plugin (-ng)
+ * Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
+ *
+ * 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 02110-1301, USA.
+ */
+
+#ifndef _ALSA_TYPES_H_GUARD
+#define _ALSA_TYPES_H_GUARD
+
+#include "alsa-stdinc.h"
+
+typedef struct {
+ AFormat aud_fmt;
+ snd_pcm_format_t alsa_fmt;
+} alsaplug_format_mapping_t;
+
+extern snd_pcm_format_t alsaplug_format_convert(AFormat aud_fmt);
+
+typedef struct {
+ gchar *pcm_device;
+ gchar *mixer_card;
+ gchar *mixer_device;
+} alsaplug_cfg_t;
+
+extern alsaplug_cfg_t alsaplug_cfg;
+
+#endif
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-util.c audacious-plugins-fedora-1.5.1/src/alsa/alsa-util.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/alsa-util.c 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/alsa-util.c 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,55 @@
+/*
+ * Audacious ALSA Plugin (-ng)
+ * Copyright (c) 2009 William Pitcock <nenolod@dereferenced.org>
+ *
+ * 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 02110-1301, USA.
+ */
+
+#include "alsa-stdinc.h"
+
+static alsaplug_format_mapping_t alsaplug_format_conv_tbl[] = {
+ {FMT_FLOAT, SND_PCM_FORMAT_FLOAT},
+ {FMT_S32_LE, SND_PCM_FORMAT_S32_LE},
+ {FMT_S32_BE, SND_PCM_FORMAT_S32_BE},
+ {FMT_S32_NE, SND_PCM_FORMAT_S32},
+ {FMT_S24_LE, SND_PCM_FORMAT_S24_LE},
+ {FMT_S24_BE, SND_PCM_FORMAT_S24_BE},
+ {FMT_S24_NE, SND_PCM_FORMAT_S24},
+ {FMT_U24_LE, SND_PCM_FORMAT_U24_LE},
+ {FMT_U24_BE, SND_PCM_FORMAT_U24_BE},
+ {FMT_U24_NE, SND_PCM_FORMAT_U24},
+ {FMT_S16_LE, SND_PCM_FORMAT_S16_LE},
+ {FMT_S16_BE, SND_PCM_FORMAT_S16_BE},
+ {FMT_S16_NE, SND_PCM_FORMAT_S16},
+ {FMT_U16_LE, SND_PCM_FORMAT_U16_LE},
+ {FMT_U16_BE, SND_PCM_FORMAT_U16_BE},
+ {FMT_U16_NE, SND_PCM_FORMAT_U16},
+ {FMT_U8, SND_PCM_FORMAT_U8},
+ {FMT_S8, SND_PCM_FORMAT_S8},
+};
+
+snd_pcm_format_t
+alsaplug_format_convert(AFormat fmt)
+{
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS(alsaplug_format_conv_tbl); i++)
+ {
+ if (alsaplug_format_conv_tbl[i].aud_fmt == fmt)
+ return alsaplug_format_conv_tbl[i].alsa_fmt;
+ }
+
+ return SND_PCM_FORMAT_UNKNOWN;
+}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/audio.c audacious-plugins-fedora-1.5.1/src/alsa/audio.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/audio.c 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/audio.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,978 +0,0 @@
-/* XMMS - ALSA output plugin
- * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>
- * Copyright (C) 1998-2003 Peter Alm, Mikael Alm, Olle Hallnas,
- * Thomas Nilsson and 4Front Technologies
- * Copyright (C) 1999-2006 Haavard Kvaalen
- * Copyright (C) 2005 Takashi Iwai
- * Copyright (C) 2007-2008 William Pitcock
- *
- * 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 02110-1301, USA.
- */
-
-/*
- * CHANGES
- *
- * 2005.01.05 Takashi Iwai <tiwai@suse.de>
- * Impelemented the multi-threaded mode with an audio-thread.
- * Many fixes and cleanups.
- */
-
-/*#define AUD_DEBUG*/
-
-#include "alsa.h"
-#include <ctype.h>
-#include <math.h>
-
-static snd_pcm_t *alsa_pcm;
-static snd_output_t *logs;
-
-
-/* Number of bytes that we have received from the input plugin */
-static guint64 alsa_total_written;
-/* Number of bytes that we have sent to the sound card */
-static guint64 alsa_hw_written;
-static guint64 output_time_offset;
-
-/* device buffer/period sizes in bytes */
-static int hw_buffer_size, hw_period_size; /* in output bytes */
-static int hw_buffer_size_in, hw_period_size_in; /* in input bytes */
-
-/* Set/Get volume */
-static snd_mixer_elem_t *pcm_element;
-static snd_mixer_t *mixer;
-
-static gboolean going, paused, mixer_start = TRUE;
-static gboolean prebuffer, remove_prebuffer;
-
-static gboolean alsa_can_pause;
-
-/* for audio thread */
-static GThread *audio_thread; /* audio loop thread */
-static int thread_buffer_size; /* size of intermediate buffer in bytes */
-static char *thread_buffer; /* audio intermediate buffer */
-static int rd_index, wr_index; /* current read/write position in int-buffer */
-static gboolean pause_request; /* pause status currently requested */
-static int flush_request; /* flush status (time) currently requested */
-static int prebuffer_size;
-GStaticMutex alsa_mutex = G_STATIC_MUTEX_INIT;
-
-struct snd_format {
- unsigned int rate;
- unsigned int channels;
- snd_pcm_format_t format;
- AFormat xmms_format;
- int sample_bits;
- int bps;
-};
-
-static struct snd_format *inputf = NULL;
-static struct snd_format *outputf = NULL;
-
-static int alsa_setup(struct snd_format *f);
-static void alsa_write_audio(char *data, int length);
-static void alsa_cleanup_mixer(void);
-static int get_thread_buffer_filled(void);
-
-static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels);
-
-static const struct {
- AFormat xmms;
- snd_pcm_format_t alsa;
-} format_table[] =
-{
-#if 0
-/* i don't know if we will ever do this --nenolod */
- {FMT_S32_LE, SND_PCM_FORMAT_S32_LE},
- {FMT_S32_BE, SND_PCM_FORMAT_S32_BE},
- {FMT_S32_NE, SND_PCM_FORMAT_S32},
-#endif
- {FMT_S24_LE, SND_PCM_FORMAT_S24_LE},
- {FMT_S24_BE, SND_PCM_FORMAT_S24_BE},
- {FMT_S24_NE, SND_PCM_FORMAT_S24},
- {FMT_U24_LE, SND_PCM_FORMAT_U24_LE},
- {FMT_U24_BE, SND_PCM_FORMAT_U24_BE},
- {FMT_U24_NE, SND_PCM_FORMAT_U24},
- {FMT_S16_LE, SND_PCM_FORMAT_S16_LE},
- {FMT_S16_BE, SND_PCM_FORMAT_S16_BE},
- {FMT_S16_NE, SND_PCM_FORMAT_S16},
- {FMT_U16_LE, SND_PCM_FORMAT_U16_LE},
- {FMT_U16_BE, SND_PCM_FORMAT_U16_BE},
- {FMT_U16_NE, SND_PCM_FORMAT_U16},
- {FMT_U8, SND_PCM_FORMAT_U8},
- {FMT_S8, SND_PCM_FORMAT_S8},
-};
-
-
-static void debug(char *str, ...) G_GNUC_PRINTF(1, 2);
-
-static void debug(char *str, ...)
-{
- va_list args;
-
- if (alsa_cfg.debug)
- {
- va_start(args, str);
- g_logv(NULL, G_LOG_LEVEL_MESSAGE, str, args);
- va_end(args);
- }
-}
-
-int alsa_playing(void)
-{
- if (!going || paused || alsa_pcm == NULL)
- return FALSE;
-
- return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING &&
- !paused &&
- !prebuffer &&
- get_thread_buffer_filled() > hw_period_size_in;
-}
-
-static int
-alsa_recovery(int err)
-{
- int err2;
-
- /* if debug mode is enabled, dump ALSA state to console */
- if (alsa_cfg.debug)
- {
- snd_pcm_status_t *alsa_status = NULL;
- snd_pcm_status_alloca(&alsa_status);
- if (snd_pcm_status(alsa_pcm, alsa_status) < 0)
- g_warning("xrun_recover(): snd_pcm_status() failed");
- else
- {
- printf("Status:\n");
- snd_pcm_status_dump(alsa_status, logs);
- }
- }
-
- /*
- * specifically handle -EPIPE and -ESTRPIPE to recover
- * PCM fragment periods without losing data.
- */
- switch (err)
- {
- case -ESTRPIPE:
- case ESTRPIPE: /* "suspend": wait until ALSA is "running" again. */
- while ((err2 = snd_pcm_resume(alsa_pcm)) == -EAGAIN)
- g_usleep(100000);
-
- if (err2 < 0)
- return snd_pcm_prepare(alsa_pcm);
-
- break;
-
- case -EPIPE:
- case EPIPE: /* under-run and the I/O pipe closed on us */
- return snd_pcm_prepare(alsa_pcm);
- break;
-
- case EINTR:
- case -EINTR:
- break;
-
- default:
- g_warning("Unhandled ALSA exception code %d (%s), trying hard restart.", err, snd_strerror(err));
- return snd_pcm_prepare(alsa_pcm);
- break;
- }
-
- return 0;
-}
-
-/* update and get the available space on h/w buffer (in frames) */
-static snd_pcm_sframes_t alsa_get_avail(void)
-{
- snd_pcm_sframes_t ret;
-
- if (alsa_pcm == NULL)
- return 0;
-
- while ((ret = snd_pcm_avail_update(alsa_pcm)) < 0)
- {
- ret = alsa_recovery(ret);
- if (ret < 0)
- {
- g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",
- snd_strerror(ret));
- return 0;
- }
- }
- return ret;
-}
-
-/* get the free space on buffer */
-int alsa_free(void)
-{
- if (remove_prebuffer && prebuffer)
- {
- prebuffer = FALSE;
- remove_prebuffer = FALSE;
- }
- if (prebuffer)
- remove_prebuffer = TRUE;
-
- return thread_buffer_size - get_thread_buffer_filled() - 1;
-}
-
-/* do pause operation */
-static void alsa_do_pause(gboolean p)
-{
- if (paused == p)
- return;
-
- if (alsa_pcm)
- {
- if (alsa_can_pause)
- snd_pcm_pause(alsa_pcm, p);
- else if (p)
- {
- snd_pcm_drop(alsa_pcm);
- snd_pcm_prepare(alsa_pcm);
- }
- }
- paused = p;
-}
-
-void alsa_pause(short p)
-{
- debug("alsa_pause");
- pause_request = p;
-}
-
-/* close PCM and release associated resources */
-static void alsa_close_pcm(void)
-{
- if (alsa_pcm)
- {
- int err;
- snd_pcm_drop(alsa_pcm);
- if ((err = snd_pcm_close(alsa_pcm)) < 0)
- g_warning("alsa_pcm_close() failed: %s",
- snd_strerror(err));
- alsa_pcm = NULL;
- }
-}
-
-void alsa_close(void)
-{
- if (!going)
- return;
-
- debug("Closing device");
-
- going = 0;
-
- g_thread_join(audio_thread);
-
- g_static_mutex_lock(&alsa_mutex); /* alsa_loop locks alsa_mutex! */
-
- alsa_cleanup_mixer();
-
- g_free(inputf);
- inputf = NULL;
- g_free(outputf);
- outputf = NULL;
-
- alsa_save_config();
-
- if (alsa_cfg.debug)
- snd_output_close(logs);
- debug("Device closed");
-
- g_static_mutex_unlock(&alsa_mutex);
-}
-
-/* reopen ALSA PCM */
-#if 0
-static int alsa_reopen(struct snd_format *f)
-{
- /* remember the current position */
- output_time_offset += (alsa_hw_written * 1000) / outputf->bps;
- alsa_hw_written = 0;
-
- alsa_close_pcm();
-
- return alsa_setup(f);
-}
-#endif
-
-/* do flush (drop) operation */
-static void alsa_do_flush(int time)
-{
- if (alsa_pcm)
- {
- snd_pcm_drop(alsa_pcm);
- snd_pcm_prepare(alsa_pcm);
- }
- /* correct the offset */
- output_time_offset = time;
- alsa_total_written = (guint64) time * inputf->bps / 1000;
- rd_index = wr_index = alsa_hw_written = 0;
-}
-
-void alsa_flush(int time)
-{
- flush_request = time;
- while ((flush_request != -1) && (going))
- g_usleep(10000);
-}
-
-static void parse_mixer_name(char *str, char **name, int *index)
-{
- char *end;
-
- while (isspace(*str))
- str++;
-
- if ((end = strchr(str, ',')) != NULL)
- {
- *name = g_strndup(str, end - str);
- end++;
- *index = atoi(end);
- }
- else
- {
- *name = g_strdup(str);
- *index = 0;
- }
-}
-
-int alsa_get_mixer(snd_mixer_t **mixer, int card)
-{
- char *dev;
- int err;
-
- debug("alsa_get_mixer");
-
- if ((err = snd_mixer_open(mixer, 0)) < 0)
- {
- g_warning("alsa_get_mixer(): Failed to open empty mixer: %s",
- snd_strerror(err));
- mixer = NULL;
- return -1;
- }
-
- dev = g_strdup_printf("hw:%i", card);
- if ((err = snd_mixer_attach(*mixer, dev)) < 0)
- {
- g_warning("alsa_get_mixer(): Attaching to mixer %s failed: %s",
- dev, snd_strerror(err));
- g_free(dev);
- return -1;
- }
- g_free(dev);
-
- if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0)
- {
- g_warning("alsa_get_mixer(): Failed to register mixer: %s",
- snd_strerror(err));
- return -1;
- }
- if ((err = snd_mixer_load(*mixer)) < 0)
- {
- g_warning("alsa_get_mixer(): Failed to load mixer: %s",
- snd_strerror(err));
- return -1;
- }
-
- return (*mixer != NULL);
-}
-
-
-static snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, char *name, int index)
-{
- snd_mixer_selem_id_t *selem_id;
- snd_mixer_elem_t* elem;
- snd_mixer_selem_id_alloca(&selem_id);
-
- if (index != -1)
- snd_mixer_selem_id_set_index(selem_id, index);
- if (name != NULL)
- snd_mixer_selem_id_set_name(selem_id, name);
-
- elem = snd_mixer_find_selem(mixer, selem_id);
-
- return elem;
-}
-
-static int alsa_setup_mixer(void)
-{
- char *name;
- long int a, b;
- long alsa_min_vol, alsa_max_vol;
- int err, index;
-
- debug("alsa_setup_mixer");
-
- if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0)
- return err;
-
- parse_mixer_name(alsa_cfg.mixer_device, &name, &index);
-
- pcm_element = alsa_get_mixer_elem(mixer, name, index);
-
- g_free(name);
-
- if (!pcm_element)
- {
- g_warning("alsa_setup_mixer(): Failed to find mixer element: %s",
- alsa_cfg.mixer_device);
- return -1;
- }
-
- /*
- * Work around a bug in alsa-lib up to 1.0.0rc2 where the
- * new range don't take effect until the volume is changed.
- * This hack should be removed once we depend on Alsa 1.0.0.
- */
- snd_mixer_selem_get_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_LEFT, &a);
- snd_mixer_selem_get_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_RIGHT, &b);
-
- snd_mixer_selem_get_playback_volume_range(pcm_element,
- &alsa_min_vol, &alsa_max_vol);
- snd_mixer_selem_set_playback_volume_range(pcm_element, 0, 100);
-
- if (alsa_max_vol == 0)
- {
- pcm_element = NULL;
- return -1;
- }
-
- alsa_set_volume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol);
-
- debug("alsa_setup_mixer: end");
-
- return 0;
-}
-
-static void alsa_cleanup_mixer(void)
-{
- pcm_element = NULL;
- if (mixer)
- {
- snd_mixer_close(mixer);
- mixer = NULL;
- }
-}
-
-void alsa_get_volume(int *l, int *r)
-{
- long ll = *l, lr = *r;
-
- if (mixer_start)
- {
- alsa_setup_mixer();
- mixer_start = FALSE;
- }
-
- if (!pcm_element)
- return;
-
- snd_mixer_handle_events(mixer);
-
- snd_mixer_selem_get_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_LEFT,
- &ll);
- snd_mixer_selem_get_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_RIGHT,
- &lr);
- *l = ll;
- *r = lr;
-}
-
-
-void alsa_set_volume(int l, int r)
-{
- if (!pcm_element)
- return;
-
- if (snd_mixer_selem_is_playback_mono(pcm_element))
- {
- if (l > r)
- snd_mixer_selem_set_playback_volume(pcm_element,
- SND_MIXER_SCHN_MONO, l);
- else
- snd_mixer_selem_set_playback_volume(pcm_element,
- SND_MIXER_SCHN_MONO, r);
- }
- else
- {
- snd_mixer_selem_set_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_LEFT, l);
- snd_mixer_selem_set_playback_volume(pcm_element,
- SND_MIXER_SCHN_FRONT_RIGHT, r);
- }
-
- if (snd_mixer_selem_has_playback_switch(pcm_element) && !snd_mixer_selem_has_playback_switch_joined(pcm_element))
- {
- snd_mixer_selem_set_playback_switch(pcm_element,
- SND_MIXER_SCHN_FRONT_LEFT, l != 0);
- snd_mixer_selem_set_playback_switch(pcm_element,
- SND_MIXER_SCHN_FRONT_RIGHT, r != 0);
- }
-}
-
-
-/*
- * audio stuff
- */
-
-/* return the size of audio data filled in the audio thread buffer */
-static int get_thread_buffer_filled(void)
-{
- if (wr_index >= rd_index)
- return wr_index - rd_index;
- return thread_buffer_size - (rd_index - wr_index);
-}
-
-int alsa_get_output_time(void)
-{
- snd_pcm_sframes_t delay;
- guint64 bytes = alsa_hw_written;
-
- if (!going || alsa_pcm == NULL)
- return 0;
-
- if (!snd_pcm_delay(alsa_pcm, &delay))
- {
- unsigned int d = snd_pcm_frames_to_bytes(alsa_pcm, delay);
- if (bytes < d)
- bytes = 0;
- else
- bytes -= d;
- }
- return output_time_offset + (bytes * 1000) / outputf->bps;
-}
-
-int alsa_get_written_time(void)
-{
- if (!going)
- return 0;
- return (alsa_total_written * 1000) / inputf->bps;
-}
-
-/* transfer data to audio h/w; length is given in bytes
- *
- * data can be modified via effect plugin, rate conversion or
- * software volume before passed to audio h/w
- */
-static void alsa_do_write(gpointer data, int length)
-{
- if (paused)
- return;
-
- alsa_write_audio(data, length);
-}
-
-/* write callback */
-void alsa_write(gpointer data, int length)
-{
- int cnt;
- char *src = (char *)data;
-
- remove_prebuffer = FALSE;
-
- alsa_total_written += length;
- while (length > 0)
- {
- int wr;
- cnt = MIN(length, thread_buffer_size - wr_index);
- memcpy(thread_buffer + wr_index, src, cnt);
- wr = (wr_index + cnt) % thread_buffer_size;
- wr_index = wr;
- length -= cnt;
- src += cnt;
- }
-}
-
-/* transfer data to audio h/w via normal write */
-static void alsa_write_audio(char *data, int length)
-{
- snd_pcm_sframes_t written_frames;
-
- while (length > 0)
- {
- int frames = snd_pcm_bytes_to_frames(alsa_pcm, length);
- written_frames = snd_pcm_writei(alsa_pcm, data, frames);
-
- if (written_frames > 0)
- {
- int written = snd_pcm_frames_to_bytes(alsa_pcm,
- written_frames);
- length -= written;
- data += written;
- alsa_hw_written += written;
- }
- else
- {
- int err = alsa_recovery((int)written_frames);
- if (err < 0)
- {
- g_warning("alsa_write_audio(): write error: %s",
- snd_strerror(err));
- break;
- }
- }
- }
-}
-
-/* transfer audio data from thread buffer to h/w */
-static void alsa_write_out_thread_data(void)
-{
- gint length, cnt, avail;
-
- length = MIN(hw_period_size_in, get_thread_buffer_filled());
- avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
- length = MIN(length, avail);
- while (length > 0)
- {
- int rd;
- cnt = MIN(length, thread_buffer_size - rd_index);
- alsa_do_write(thread_buffer + rd_index, cnt);
- rd = (rd_index + cnt) % thread_buffer_size;
- rd_index = rd;
- length -= cnt;
- }
-}
-
-/* audio thread loop */
-/* FIXME: proper lock? */
-static void *alsa_loop(void *arg)
-{
- int npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
- int wr = 0;
-
- g_static_mutex_lock(&alsa_mutex);
-
- if (npfds <= 0)
- goto _error;
-
- while (going && alsa_pcm)
- {
- if (get_thread_buffer_filled() > prebuffer_size)
- prebuffer = FALSE;
- if (!paused && !prebuffer &&
- get_thread_buffer_filled() > hw_period_size_in)
- {
- wr = snd_pcm_wait(alsa_pcm, 10);
- if (wr > 0)
- {
- alsa_write_out_thread_data();
- }
- else if (wr < 0)
- {
- alsa_recovery(wr);
- }
- }
- else /* XXX: why is this here? --nenolod */
- g_usleep(10000);
-
- if (pause_request != paused)
- alsa_do_pause(pause_request);
-
- if (flush_request != -1)
- {
- alsa_do_flush(flush_request);
- flush_request = -1;
- prebuffer = TRUE;
- }
- }
-
- _error:
- g_static_mutex_unlock(&alsa_mutex);
- alsa_close_pcm();
- g_free(thread_buffer);
- thread_buffer = NULL;
- g_thread_exit(NULL);
- return(NULL);
-}
-
-/* open callback */
-int alsa_open(AFormat fmt, int rate, int nch)
-{
- debug("Opening device");
- if((inputf = snd_format_from_xmms(fmt, rate, nch)) == NULL) return 0;
-
- if (alsa_cfg.debug)
- snd_output_stdio_attach(&logs, stdout, 0);
-
- if (alsa_setup(inputf) < 0)
- {
- alsa_close();
- return 0;
- }
-
- g_static_mutex_lock(&alsa_mutex);
-
- if (!mixer)
- alsa_setup_mixer();
-
- output_time_offset = 0;
- alsa_total_written = alsa_hw_written = 0;
- going = TRUE;
- paused = FALSE;
- prebuffer = TRUE;
- remove_prebuffer = FALSE;
-
- thread_buffer_size = (guint64)aud_cfg->output_buffer_size * inputf->bps / 1000;
- if (thread_buffer_size < hw_buffer_size)
- thread_buffer_size = hw_buffer_size * 2;
- if (thread_buffer_size < 8192)
- thread_buffer_size = 8192;
- prebuffer_size = thread_buffer_size / 2;
- if (prebuffer_size < 8192)
- prebuffer_size = 8192;
- thread_buffer_size += hw_buffer_size;
- thread_buffer_size -= thread_buffer_size % hw_period_size;
- thread_buffer = g_malloc0(thread_buffer_size);
- wr_index = rd_index = 0;
- pause_request = FALSE;
- flush_request = -1;
-
- g_static_mutex_unlock(&alsa_mutex);
-
- audio_thread = g_thread_create((GThreadFunc)alsa_loop, NULL, TRUE, NULL);
- return 1;
-}
-
-static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels)
-{
- struct snd_format *f = g_malloc(sizeof(struct snd_format));
- size_t i;
- int found = 0;
-
- f->xmms_format = fmt;
- f->format = SND_PCM_FORMAT_UNKNOWN;
-
- for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++)
- if (format_table[i].xmms == fmt)
- {
- f->format = format_table[i].alsa;
- found = 1;
- break;
- }
-
- if(!found) {
- g_free(f);
- return NULL;
- }
-
- /* Get rid of _NE */
- for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++)
- if (format_table[i].alsa == f->format)
- {
- f->xmms_format = format_table[i].xmms;
- break;
- }
-
-
- f->rate = rate;
- f->channels = channels;
- f->sample_bits = snd_pcm_format_physical_width(f->format);
- f->bps = (rate * f->sample_bits * channels) >> 3;
-
- return f;
-}
-
-static int alsa_setup(struct snd_format *f)
-{
- int err;
- snd_pcm_hw_params_t *hwparams = NULL;
- snd_pcm_sw_params_t *swparams = NULL;
- unsigned int alsa_buffer_time, alsa_period_time;
- snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;
-
- debug("alsa_setup");
-
- g_free(outputf);
- outputf = snd_format_from_xmms(f->xmms_format, f->rate, f->channels);
- if(outputf == NULL) return -1;
-
- debug("Opening device: %s", alsa_cfg.pcm_device);
- /* FIXME: Can snd_pcm_open() return EAGAIN? */
- if ((err = snd_pcm_open(&alsa_pcm, alsa_cfg.pcm_device,
- SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK)) < 0)
- {
- g_warning("alsa_setup(): Failed to open pcm device (%s): %s",
- alsa_cfg.pcm_device, snd_strerror(err));
- alsa_pcm = NULL;
- g_free(outputf);
- outputf = NULL;
- return -1;
- }
-
- /* doesn't care about non-blocking */
- /* snd_pcm_nonblock(alsa_pcm, 0); */
-
- if (alsa_cfg.debug)
- {
- snd_pcm_info_t *info = NULL;
- int alsa_card, alsa_device, alsa_subdevice;
-
- snd_pcm_info_alloca(&info);
- snd_pcm_info(alsa_pcm, info);
- alsa_card = snd_pcm_info_get_card(info);
- alsa_device = snd_pcm_info_get_device(info);
- alsa_subdevice = snd_pcm_info_get_subdevice(info);
- printf("Card %i, Device %i, Subdevice %i\n",
- alsa_card, alsa_device, alsa_subdevice);
- }
-
- snd_pcm_hw_params_alloca(&hwparams);
-
- if ((err = snd_pcm_hw_params_any(alsa_pcm, hwparams)) < 0)
- {
- g_warning("alsa_setup(): No configuration available for "
- "playback: %s", snd_strerror(err));
- return -1;
- }
-
- if ((err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
- {
- g_warning("alsa_setup(): Cannot set direct write mode: %s",
- snd_strerror(err));
- return -1;
- }
-
- /* XXX: there is no down-dithering for 24bit yet --nenolod */
- if ((err = snd_pcm_hw_params_set_format(alsa_pcm, hwparams, outputf->format)) < 0)
- {
- g_warning("alsa_setup(): Sample format not "
- "available for playback: %s",
- snd_strerror(err));
- return -1;
- }
-
- snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &outputf->channels);
- if (outputf->channels != f->channels)
- return -1;
-
- snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &outputf->rate, 0);
- if (outputf->rate == 0)
- {
- g_warning("alsa_setup(): No usable samplerate available.");
- return -1;
- }
- if (outputf->rate != f->rate)
- return -1;
-
- outputf->sample_bits = snd_pcm_format_physical_width(outputf->format);
- outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3;
-
- alsa_buffer_time = alsa_cfg.buffer_time * 1000;
- if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams,
- &alsa_buffer_time, 0)) < 0)
- {
- g_warning("alsa_setup(): Set buffer time failed: %s.",
- snd_strerror(err));
- return -1;
- }
-
- alsa_period_time = alsa_cfg.period_time * 1000;
- if ((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams,
- &alsa_period_time, 0)) < 0)
- {
- g_warning("alsa_setup(): Set period time failed: %s.",
- snd_strerror(err));
- return -1;
- }
-
- if (snd_pcm_hw_params(alsa_pcm, hwparams) < 0)
- {
- if (alsa_cfg.debug)
- snd_pcm_hw_params_dump(hwparams, logs);
- g_warning("alsa_setup(): Unable to install hw params");
- return -1;
- }
-
- if ((err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size)) < 0)
- {
- g_warning("alsa_setup(): snd_pcm_hw_params_get_buffer_size() "
- "failed: %s",
- snd_strerror(err));
- return -1;
- }
-
- if ((err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size, 0)) < 0)
- {
- g_warning("alsa_setup(): snd_pcm_hw_params_get_period_size() "
- "failed: %s",
- snd_strerror(err));
- return -1;
- }
-
- alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams);
- debug("can pause: %d", alsa_can_pause);
-
- snd_pcm_sw_params_alloca(&swparams);
- snd_pcm_sw_params_current(alsa_pcm, swparams);
-
- if ((err = snd_pcm_sw_params_set_start_threshold(alsa_pcm,
- swparams, alsa_buffer_size - alsa_period_size) < 0))
- g_warning("alsa_setup(): setting start "
- "threshold failed: %s", snd_strerror(err));
- if (snd_pcm_sw_params(alsa_pcm, swparams) < 0)
- {
- g_warning("alsa_setup(): Unable to install sw params");
- return -1;
- }
-
- if (alsa_cfg.debug)
- {
- snd_pcm_sw_params_dump(swparams, logs);
- snd_pcm_dump(alsa_pcm, logs);
- }
-
- hw_buffer_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_buffer_size);
- hw_period_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_period_size);
- if (inputf->bps != outputf->bps)
- {
- int align = (inputf->sample_bits * inputf->channels) / 8;
- hw_buffer_size_in = ((guint64)hw_buffer_size * inputf->bps +
- outputf->bps/2) / outputf->bps;
- hw_period_size_in = ((guint64)hw_period_size * inputf->bps +
- outputf->bps/2) / outputf->bps;
- hw_buffer_size_in -= hw_buffer_size_in % align;
- hw_period_size_in -= hw_period_size_in % align;
- }
- else
- {
- hw_buffer_size_in = hw_buffer_size;
- hw_period_size_in = hw_period_size;
- }
-
- debug("Device setup: buffer time: %i, size: %i.", alsa_buffer_time,
- hw_buffer_size);
- debug("Device setup: period time: %i, size: %i.", alsa_period_time,
- hw_period_size);
- debug("bits per sample: %i; frame size: %i; Bps: %i",
- snd_pcm_format_physical_width(outputf->format),
- (int)snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps);
-
- return 0;
-}
-
-void alsa_tell(AFormat * fmt, gint * rate, gint * nch)
-{
- (*fmt) = inputf->xmms_format;
- (*rate) = inputf->rate;
- (*nch) = inputf->channels;
-}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/configure.c audacious-plugins-fedora-1.5.1/src/alsa/configure.c
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/configure.c 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/configure.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,396 +0,0 @@
-/* XMMS - ALSA output plugin
- * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org>
- * Copyright (C) 2003-2005 Haavard Kvaalen
- *
- * 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 02110-1301, USA.
- */
-#include "alsa.h"
-#include <stdio.h>
-
-static GtkWidget *configure_win = NULL;
-static GtkWidget *buffer_time_spin, *period_time_spin;
-
-static GtkWidget *devices_combo, *mixer_devices_combo;
-
-static int current_mixer_card;
-
-#define GET_SPIN_INT(spin) \
- gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin))
-#define GET_TOGGLE(tb) gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb))
-#define GET_CHARS(edit) gtk_editable_get_chars(GTK_EDITABLE(edit), 0, -1)
-
-static void configure_win_ok_cb(GtkWidget * w, gpointer data)
-{
- g_free(alsa_cfg.pcm_device);
- alsa_cfg.pcm_device = GET_CHARS(GTK_COMBO(devices_combo)->entry);
- alsa_cfg.buffer_time = GET_SPIN_INT(buffer_time_spin);
- alsa_cfg.period_time = GET_SPIN_INT(period_time_spin);
- alsa_cfg.mixer_card = current_mixer_card;
- alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
-
- alsa_save_config();
- gtk_widget_destroy(configure_win);
-}
-
-void alsa_save_config(void)
-{
- mcs_handle_t *cfgfile = aud_cfg_db_open();
-
- aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "buffer_time", alsa_cfg.buffer_time);
- aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "period_time", alsa_cfg.period_time);
- aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"pcm_device", alsa_cfg.pcm_device);
- aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "mixer_card", alsa_cfg.mixer_card);
- aud_cfg_db_set_string(cfgfile,ALSA_CFGID,"mixer_device", alsa_cfg.mixer_device);
- aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_left", alsa_cfg.vol.left);
- aud_cfg_db_set_int(cfgfile, ALSA_CFGID, "volume_right", alsa_cfg.vol.right);
- aud_cfg_db_close(cfgfile);
-}
-
-static int get_cards(GtkOptionMenu *omenu, GtkSignalFunc cb, int active)
-{
- GtkWidget *menu, *item;
- int card = -1, err, set = 0, curr = -1;
-
- menu = gtk_menu_new();
- if ((err = snd_card_next(&card)) != 0)
- g_warning("snd_next_card() failed: %s", snd_strerror(err));
-
- while (card > -1)
- {
- char *label;
-
- curr++;
- if (card == active)
- set = curr;
- if ((err = snd_card_get_name(card, &label)) != 0)
- {
- g_warning("snd_carg_get_name() failed: %s",
- snd_strerror(err));
- break;
- }
-
- item = gtk_menu_item_new_with_label(label);
- gtk_signal_connect(GTK_OBJECT(item), "activate", cb,
- GINT_TO_POINTER(card));
- gtk_widget_show(item);
- gtk_menu_append(GTK_MENU(menu), item);
- if ((err = snd_card_next(&card)) != 0)
- {
- g_warning("snd_next_card() failed: %s",
- snd_strerror(err));
- break;
- }
- }
-
- gtk_option_menu_set_menu(omenu, menu);
- return set;
-}
-
-static int get_mixer_devices(GtkCombo *combo, int card)
-{
- GList *items = NULL;
- int err;
- snd_mixer_t *mixer;
- snd_mixer_elem_t *current;
-
- if ((err = alsa_get_mixer(&mixer, card)) < 0)
- return err;
-
- current = snd_mixer_first_elem(mixer);
-
- while (current)
- {
- const char *sname = snd_mixer_selem_get_name(current);
- if (snd_mixer_selem_is_active(current) &&
- snd_mixer_selem_has_playback_volume(current))
- items = g_list_append(items, g_strdup(sname));
- current = snd_mixer_elem_next(current);
- }
-
- gtk_combo_set_popdown_strings(combo, items);
-
- return 0;
-}
-
-static void get_devices_for_card(GtkCombo *combo, int card)
-{
- GtkWidget *item;
- int pcm_device = -1, err;
- snd_pcm_info_t *pcm_info = NULL;
- snd_ctl_t *ctl;
- char dev[64], *card_name;
-
- sprintf(dev, "hw:%i", card);
-
- if ((err = snd_ctl_open(&ctl, dev, 0)) < 0)
- {
- printf("snd_ctl_open() failed: %s", snd_strerror(err));
- return;
- }
-
- if ((err = snd_card_get_name(card, &card_name)) != 0)
- {
- g_warning("snd_card_get_name() failed: %s", snd_strerror(err));
- card_name = _("Unknown soundcard");
- }
-
- snd_pcm_info_alloca(&pcm_info);
-
- for (;;)
- {
- char *device, *descr;
- if ((err = snd_ctl_pcm_next_device(ctl, &pcm_device)) < 0)
- {
- g_warning("snd_ctl_pcm_next_device() failed: %s",
- snd_strerror(err));
- pcm_device = -1;
- }
- if (pcm_device < 0)
- break;
-
- snd_pcm_info_set_device(pcm_info, pcm_device);
- snd_pcm_info_set_subdevice(pcm_info, 0);
- snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK);
-
- if ((err = snd_ctl_pcm_info(ctl, pcm_info)) < 0)
- {
- if (err != -ENOENT)
- g_warning("get_devices_for_card(): "
- "snd_ctl_pcm_info() "
- "failed (%d:%d): %s.", card,
- pcm_device, snd_strerror(err));
- continue;
- }
-
- device = g_strdup_printf("hw:%d,%d", card, pcm_device);
- descr = g_strconcat(card_name, ": ",
- snd_pcm_info_get_name(pcm_info),
- " (", device, ")", NULL);
- item = gtk_list_item_new_with_label(descr);
- gtk_widget_show(item);
- g_free(descr);
- gtk_combo_set_item_string(combo, GTK_ITEM(item), device);
- g_free(device);
- gtk_container_add(GTK_CONTAINER(combo->list), item);
- }
-
- snd_ctl_close(ctl);
-}
-
-
-
-static void get_devices(GtkCombo *combo)
-{
- GtkWidget *item;
- int card = -1;
- int err = 0;
- char *descr;
-
- descr = g_strdup_printf(_("Default PCM device (%s)"), "default");
- item = gtk_list_item_new_with_label(descr);
- gtk_widget_show(item);
- g_free(descr);
- gtk_combo_set_item_string(combo, GTK_ITEM(item), "default");
- gtk_container_add(GTK_CONTAINER(combo->list), item);
-
- if ((err = snd_card_next(&card)) != 0)
- {
- g_warning("snd_next_card() failed: %s", snd_strerror(err));
- return;
- }
-
- while (card > -1)
- {
- get_devices_for_card(combo, card);
- if ((err = snd_card_next(&card)) != 0)
- {
- g_warning("snd_next_card() failed: %s",
- snd_strerror(err));
- break;
- }
- }
-}
-
-static void mixer_card_cb(GtkWidget * widget, gpointer card)
-{
- if (current_mixer_card == GPOINTER_TO_INT(card))
- return;
- current_mixer_card = GPOINTER_TO_INT(card);
- get_mixer_devices(GTK_COMBO(mixer_devices_combo),
- current_mixer_card);
-}
-
-void alsa_configure(void)
-{
- GtkWidget *vbox, *notebook;
- GtkWidget *dev_vbox, *adevice_frame, *adevice_box;
- GtkWidget *mixer_frame, *mixer_box, *mixer_table, *mixer_card_om;
- GtkWidget *mixer_card_label, *mixer_device_label;
- GtkWidget *advanced_vbox, *card_vbox;
- GtkWidget *buffer_table;
- GtkWidget *card_frame, *buffer_time_label, *period_time_label;
- GtkObject *buffer_time_adj, *period_time_adj;
- GtkWidget *bbox, *ok, *cancel;
-
- int mset;
-
- if (configure_win)
- {
- gtk_window_present(GTK_WINDOW(configure_win));
- return;
- }
-
- configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
- GTK_SIGNAL_FUNC(gtk_widget_destroyed),
- &configure_win);
- gtk_window_set_title(GTK_WINDOW(configure_win),
- _("ALSA Driver configuration"));
- gtk_window_set_policy(GTK_WINDOW(configure_win),
- FALSE, TRUE, FALSE);
- gtk_container_border_width(GTK_CONTAINER(configure_win), 10);
-
- vbox = gtk_vbox_new(FALSE, 10);
- gtk_container_add(GTK_CONTAINER(configure_win), vbox);
-
- notebook = gtk_notebook_new();
- gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
- dev_vbox = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(dev_vbox), 5);
-
- adevice_frame = gtk_frame_new(_("Audio device:"));
- gtk_box_pack_start(GTK_BOX(dev_vbox), adevice_frame, FALSE, FALSE, 0);
-
- adevice_box = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(adevice_box), 5);
- gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_box);
-
- devices_combo = gtk_combo_new();
- gtk_box_pack_start(GTK_BOX(adevice_box), devices_combo,
- FALSE, FALSE, 0);
- get_devices(GTK_COMBO(devices_combo));
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(devices_combo)->entry),
- alsa_cfg.pcm_device);
-
- mixer_frame = gtk_frame_new(_("Mixer:"));
- gtk_box_pack_start(GTK_BOX(dev_vbox), mixer_frame, FALSE, FALSE, 0);
-
- mixer_box = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(mixer_box), 5);
- gtk_container_add(GTK_CONTAINER(mixer_frame), mixer_box);
-
- mixer_table = gtk_table_new(2, 2, FALSE);
- gtk_table_set_row_spacings(GTK_TABLE(mixer_table), 5);
- gtk_table_set_col_spacings(GTK_TABLE(mixer_table), 5);
- gtk_box_pack_start(GTK_BOX(mixer_box), mixer_table, FALSE, FALSE, 0);
-
- mixer_card_label = gtk_label_new(_("Mixer card:"));
- gtk_label_set_justify(GTK_LABEL(mixer_card_label), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment(GTK_MISC(mixer_card_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(mixer_table), mixer_card_label,
- 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
- mixer_card_om = gtk_option_menu_new();
- mset = get_cards(GTK_OPTION_MENU(mixer_card_om),
- (GtkSignalFunc)mixer_card_cb, alsa_cfg.mixer_card);
-
- gtk_table_attach(GTK_TABLE(mixer_table), mixer_card_om,
- 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
-
- mixer_device_label = gtk_label_new(_("Mixer device:"));
- gtk_label_set_justify(GTK_LABEL(mixer_device_label), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment(GTK_MISC(mixer_device_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(mixer_table), mixer_device_label,
- 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
- mixer_devices_combo = gtk_combo_new();
- gtk_option_menu_set_history(GTK_OPTION_MENU(mixer_card_om), mset);
- get_mixer_devices(GTK_COMBO(mixer_devices_combo), alsa_cfg.mixer_card);
- gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(mixer_devices_combo)->entry),
- alsa_cfg.mixer_device);
-
- gtk_table_attach(GTK_TABLE(mixer_table), mixer_devices_combo,
- 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
-
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dev_vbox,
- gtk_label_new(_("Device settings")));
-
-
- advanced_vbox = gtk_vbox_new(FALSE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(advanced_vbox), 5);
-
- card_frame = gtk_frame_new(_("Soundcard:"));
- gtk_box_pack_start_defaults(GTK_BOX(advanced_vbox), card_frame);
-
- card_vbox = gtk_vbox_new(FALSE, 0);
- gtk_container_add(GTK_CONTAINER(card_frame), card_vbox);
-
- gtk_container_set_border_width(GTK_CONTAINER(card_vbox), 5);
-
- buffer_table = gtk_table_new(2, 2, TRUE);
- gtk_table_set_row_spacings(GTK_TABLE(buffer_table), 5);
- gtk_table_set_col_spacings(GTK_TABLE(buffer_table), 5);
- gtk_box_pack_start_defaults(GTK_BOX(card_vbox), buffer_table);
-
- buffer_time_label = gtk_label_new(_("Buffer time (ms):"));
- gtk_label_set_justify(GTK_LABEL(buffer_time_label), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment(GTK_MISC(buffer_time_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(buffer_table), buffer_time_label,
- 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
-
- buffer_time_adj = gtk_adjustment_new(alsa_cfg.buffer_time,
- 200, 10000, 100, 100, 100);
- buffer_time_spin = gtk_spin_button_new(GTK_ADJUSTMENT(buffer_time_adj),
- 8, 0);
- gtk_widget_set_usize(buffer_time_spin, 60, -1);
- gtk_table_attach(GTK_TABLE(buffer_table), buffer_time_spin,
- 1, 2, 0, 1, 0, 0, 0, 0);
-
- period_time_label = gtk_label_new(_("Period time (ms):"));
- gtk_label_set_justify(GTK_LABEL(period_time_label), GTK_JUSTIFY_LEFT);
- gtk_misc_set_alignment(GTK_MISC(period_time_label), 0, 0.5);
- gtk_table_attach(GTK_TABLE(buffer_table), period_time_label,
- 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
- period_time_adj = gtk_adjustment_new(alsa_cfg.period_time,
- 1, 500, 1, 100, 100);
- period_time_spin = gtk_spin_button_new(GTK_ADJUSTMENT(period_time_adj),
- 8, 0);
-
- gtk_widget_set_usize(period_time_spin, 60, -1);
- gtk_table_attach(GTK_TABLE(buffer_table), period_time_spin,
- 1, 2, 1, 2, 0, 0, 0, 0);
-
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), advanced_vbox,
- gtk_label_new(_("Advanced settings")));
-
- bbox = gtk_hbutton_box_new();
- gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
- gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
- gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
-
- ok = gtk_button_new_with_label(_("OK"));
- gtk_signal_connect(GTK_OBJECT(ok), "clicked", (GCallback)configure_win_ok_cb, NULL);
- GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
- gtk_widget_grab_default(ok);
-
- cancel = gtk_button_new_with_label(_("Cancel"));
- gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
- (GCallback)gtk_widget_destroy, GTK_OBJECT(configure_win));
- GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
- gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
-
- gtk_widget_show_all(configure_win);
-}
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/Makefile audacious-plugins-fedora-1.5.1/src/alsa/Makefile
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/Makefile 2008-06-08 10:37:44.000000000 +0200
+++ audacious-plugins-fedora-1.5.1/src/alsa/Makefile 2009-06-29 18:01:20.000000000 +0200
@@ -1,9 +1,9 @@
PLUGIN = ALSA${PLUGIN_SUFFIX}
-SRCS = alsa.c \
- about.c \
- audio.c \
- configure.c
+SRCS = alsa-core.c \
+ alsa-configure.c \
+ alsa-ringbuffer.c \
+ alsa-util.c
include ../../buildsys.mk
include ../../extra.mk
diff -Nur audacious-plugins-fedora-1.5.1-orig/src/alsa/TODO audacious-plugins-fedora-1.5.1/src/alsa/TODO
--- audacious-plugins-fedora-1.5.1-orig/src/alsa/TODO 1970-01-01 01:00:00.000000000 +0100
+++ audacious-plugins-fedora-1.5.1/src/alsa/TODO 2009-06-29 18:01:20.000000000 +0200
@@ -0,0 +1,30 @@
+The following things are not implemented yet:
+
+- prerolling: this means that it is possible for buffer underruns occasionally.
+ we want to preroll at least 50% of buffer_size before actually writing anything
+ to the soundcard.
+
+The following things would be nice:
+
+- use HAL (or DeviceKit) to match up devices and mixer settings. The old way sucks
+ majorly, I want to be able to just choose a soundcard and have it set up the mixer
+ the right way on it's own. This is 2009, and this should be possible.
+
+(right now we don't use HAL/DeviceKit, but have a trivial function to determine what
+ mixer settings we use. pcm:default seems like a good choice for finding the system
+ default soundcard/mixer, which we use already...)
+
+Things that won't be reimplemented:
+
+- support for custom period sizes and buffer sizes. we want to use the ALSA defaults
+ since they provide the optimal values for each card. this means that specifying
+ period/buffer sizes is retarded.
+
+Notable differences between the old ALSA plugin and the new one:
+
+- tickless design:
+ The old ALSA plugin basically did a lot of polling. This does not, instead using
+ an event-driven tickless design using conditionals.
+
+- uses ALSA "safe" API subset:
+ Plugin should work correctly with all userspace plugins.