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 - * - * 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 -#include -#include -#include - -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 + * Portions copyright (C) 2001-2003 Matthieu Sozeau + * 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 + +#include +#include + +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 + * + * 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 + +#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 -#include - -#define ALSA_PCM_NEW_HW_PARAMS_API -#define ALSA_PCM_NEW_SW_PARAMS_API -#include -#include - -#include - -#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 +#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 + +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 + +#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 + * + * 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 + +#define ALSA_PCM_NEW_HW_PARAMS_API +#define ALSA_PCM_NEW_SW_PARAMS_API +#include +#include + +#include + +#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 + * + * 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 + * + * 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 - * 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 - * Impelemented the multi-threaded mode with an audio-thread. - * Many fixes and cleanups. - */ - -/*#define AUD_DEBUG*/ - -#include "alsa.h" -#include -#include - -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 - * 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 - -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.