Mercurial > audlegacy
changeset 211:0b48662886e9 trunk
[svn] Sync ALSA plugin with enhancements/patches from Fatal (XMMS cvs)
author | nenolod |
---|---|
date | Sun, 20 Nov 2005 00:34:09 -0800 |
parents | 12004b385a96 |
children | 12b1fe51852e |
files | Plugins/Output/alsa/about.c Plugins/Output/alsa/alsa.c Plugins/Output/alsa/alsa.h Plugins/Output/alsa/audio.c Plugins/Output/alsa/configure.c Plugins/Output/alsa/init.c |
diffstat | 6 files changed, 1368 insertions(+), 1412 deletions(-) [+] |
line wrap: on
line diff
--- a/Plugins/Output/alsa/about.c Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/about.c Sun Nov 20 00:34:09 2005 -0800 @@ -17,40 +17,34 @@ */ #include "alsa.h" - -#include <glib.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include <libaudacious/util.h> - +#include <xmms/util.h> -void -alsa_about(void) +void alsa_about(void) { - static GtkWidget *dialog; - - if (dialog != NULL) - return; + static GtkWidget *dialog; - dialog = xmms_show_message(_("About ALSA Driver"), - _("XMMS 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\n" - "USA.\n" - "Author: Matthieu Sozeau (mattam@altern.org)"), - _("Ok"), FALSE, NULL, NULL); - g_signal_connect(dialog, "destroy", - G_CALLBACK(gtk_widget_destroyed), &dialog); + if (dialog != NULL) + return; + + dialog = xmms_show_message( + _("About ALSA Driver"), + _("XMMS 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\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); }
--- a/Plugins/Output/alsa/alsa.c Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/alsa.c Sun Nov 20 00:34:09 2005 -0800 @@ -17,32 +17,30 @@ */ #include "alsa.h" -#include <glib/gi18n.h> -OutputPlugin alsa_op = { - NULL, - NULL, - NULL, - alsa_init, - alsa_about, - alsa_configure, - alsa_get_volume, - alsa_set_volume, - alsa_open, - alsa_write, - alsa_close, - alsa_flush, - alsa_pause, - alsa_free, - alsa_playing, - alsa_get_output_time, - alsa_get_written_time, +OutputPlugin alsa_op = +{ + NULL, + NULL, + NULL, + alsa_init, + alsa_about, + alsa_configure, + alsa_get_volume, + alsa_set_volume, + alsa_open, + alsa_write, + alsa_close, + alsa_flush, + alsa_pause, + alsa_free, + alsa_playing, + alsa_get_output_time, + alsa_get_written_time, }; -OutputPlugin * -get_oplugin_info(void) +OutputPlugin *get_oplugin_info(void) { - alsa_op.description = - g_strdup_printf(_("ALSA %s output plugin"), VERSION); - return &alsa_op; + alsa_op.description = g_strdup_printf(_("ALSA %s output plugin"), VERSION); + return &alsa_op; }
--- a/Plugins/Output/alsa/alsa.h Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/alsa.h Sun Nov 20 00:34:09 2005 -0800 @@ -24,7 +24,9 @@ #include "config.h" #include <libaudacious/util.h> +#include <libaudacious/configdb.h> #include <audacious/plugin.h> +#include <glib/gi18n.h> #define ALSA_PCM_NEW_HW_PARAMS_API #define ALSA_PCM_NEW_SW_PARAMS_API @@ -50,8 +52,6 @@ int period_time; int thread_buffer_time; gboolean debug; - gboolean multi_thread; - gboolean mmap; struct { int left, right;
--- a/Plugins/Output/alsa/audio.c Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/audio.c Sun Nov 20 00:34:09 2005 -0800 @@ -2,7 +2,8 @@ * 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-2004 Haavard Kvaalen + * Copyright (C) 1999-2005 Haavard Kvaalen + * Copyright (C) 2005 Takashi Iwai * * 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 @@ -17,57 +18,63 @@ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * + */ + +/* * CHANGES * * 2005.01.05 Takashi Iwai <tiwai@suse.de> - * Impelemented the multi-threaded mode with an audio-thread. - * Many fixes and cleanups. + * Impelemented the multi-threaded mode with an audio-thread. + * Many fixes and cleanups. */ + #include "alsa.h" #include <ctype.h> -#include <glib.h> +#include <pthread.h> #include <libaudacious/xconvert.h> -static snd_pcm_t *alsa_pcm = NULL; +static snd_pcm_t *alsa_pcm; +static snd_output_t *logs; -static snd_output_t *logs = NULL; -static guint64 alsa_total_written = 0; /* input bytes */ -static guint64 alsa_hw_written = 0; /* output bytes */ -static gint output_time_offset = 0; +/* 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 */ +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 = NULL; -static snd_mixer_t *mixer = NULL; +static snd_mixer_elem_t *pcm_element; +static snd_mixer_t *mixer; -static gboolean mmap, going = FALSE, paused, multi_thread, mixer_start = TRUE;; +static gboolean going, paused, mixer_start = TRUE; +static gboolean prebuffer, remove_prebuffer; static gboolean alsa_can_pause; +/* for audio thread */ +static pthread_t 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; + static guint mixer_timeout; -/* 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 gint flush_request; /* flush status (time) currently requested */ - struct snd_format { - unsigned int rate; - unsigned int channels; - snd_pcm_format_t format; - AFormat xmms_format; - int sample_bits; - int bps; + 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; @@ -75,11 +82,11 @@ static struct snd_format *outputf = NULL; static int alsa_setup(struct snd_format *f); -static void alsa_mmap_audio(char *data, int length); 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 struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels); static struct xmms_convert_buffers *convertb; @@ -88,554 +95,574 @@ static convert_freq_func_t alsa_frequency_convert_func; static const struct { - AFormat xmms; - snd_pcm_format_t alsa; -} format_table[] = { - {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}, + AFormat xmms; + snd_pcm_format_t alsa; +} format_table[] = +{{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, ...) 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; +} - static void debug(char *str, ...) +static int xrun_recover(void) +{ + if (alsa_cfg.debug) + { + snd_pcm_status_t *alsa_status; + 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); + } + } + return snd_pcm_prepare(alsa_pcm); +} + +static int suspend_recover(void) +{ + int err; + + while ((err = snd_pcm_resume(alsa_pcm)) == -EAGAIN) + /* wait until suspend flag is released */ + sleep(1); + if (err < 0) + { + g_warning("alsa_handle_error(): " + "snd_pcm_resume() failed."); + return snd_pcm_prepare(alsa_pcm); + } + return err; +} + +/* handle generic errors */ +static int alsa_handle_error(int err) { - va_list args; + switch (err) + { + case -EPIPE: + return xrun_recover(); + case -ESTRPIPE: + return suspend_recover(); + } + + return err; +} + +/* 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_handle_error(ret); + if (ret < 0) + { + g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s", + snd_strerror(-ret)); + return 0; + } + } + return ret; +} - if (alsa_cfg.debug) { - va_start(args, str); - g_logv(NULL, G_LOG_LEVEL_MESSAGE, str, args); - va_end(args); - } +/* 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; } -/* - * mixer stuff - */ -static void -parse_mixer_name(char *str, char **name, int *index) +/* close PCM and release associated resources */ +static void alsa_close_pcm(void) { - char *end; + 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; + + pthread_join(audio_thread, NULL); + + alsa_cleanup_mixer(); - while (isspace(*str)) - str++; + xmms_convert_buffers_destroy(convertb); + convertb = NULL; + g_free(inputf); + inputf = NULL; + g_free(effectf); + effectf = NULL; + g_free(outputf); + outputf = NULL; + + alsa_save_config(); - if ((end = strchr(str, ',')) != NULL) { - *name = g_strndup(str, end - str); - end++; - *index = atoi(end); - } - else { - *name = g_strdup(str); - *index = 0; - } + if (alsa_cfg.debug) + snd_output_close(logs); + debug("Device closed"); +} + +/* reopen ALSA PCM */ +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); } -int -alsa_get_mixer(snd_mixer_t ** mixer, int card) +/* do flush (drop) operation */ +static void alsa_do_flush(int time) { - char *dev; - int err; + 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; +} - debug("alsa_get_mixer"); +void alsa_flush(int time) +{ + flush_request = time; + while (flush_request != -1) + xmms_usleep(10000); +} - dev = g_strdup_printf("hw:%i", card); +static void parse_mixer_name(char *str, char **name, int *index) +{ + char *end; + + while (isspace(*str)) + str++; - 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; - } - if ((err = snd_mixer_attach(*mixer, dev)) < 0) { - g_warning("alsa_get_mixer(): Attaching to mixer %s failed: %s", - dev, snd_strerror(-err)); - return -1; - } - 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; - } + 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"); + + dev = g_strdup_printf("hw:%i", card); - g_free(dev); + 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; + } + if ((err = snd_mixer_attach(*mixer, dev)) < 0) + { + g_warning("alsa_get_mixer(): Attaching to mixer %s failed: %s", + dev, snd_strerror(-err)); + return -1; + } + 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); + g_free(dev); + + 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); + 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); + 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); + elem = snd_mixer_find_selem(mixer, selem_id); - return elem; + return elem; } -static int -alsa_setup_mixer(void) +static int alsa_setup_mixer(void) { - char *name; - long int a, b; - long alsa_min_vol, alsa_max_vol; - int err, index; + char *name; + long int a, b; + long alsa_min_vol, alsa_max_vol; + int err, index; - debug("alsa_setup_mixer"); + debug("alsa_setup_mixer"); + + if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0) + return err; - if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0) - return err; + parse_mixer_name(alsa_cfg.mixer_device, &name, &index); - parse_mixer_name(alsa_cfg.mixer_device, &name, &index); + pcm_element = alsa_get_mixer_elem(mixer, name, index); - pcm_element = alsa_get_mixer_elem(mixer, name, index); + g_free(name); - g_free(name); - - if (!pcm_element) { - g_warning("alsa_setup_mixer(): Failed to find mixer element: %s", - alsa_cfg.mixer_device); - return -1; - } + 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); + /* + * 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); + 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; - } + if (alsa_max_vol == 0) + { + pcm_element = NULL; + return -1; + } - if (!alsa_cfg.soft_volume) - alsa_set_volume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol); + if (!alsa_cfg.soft_volume) + alsa_set_volume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol); - debug("alsa_setup_mixer: end"); + debug("alsa_setup_mixer: end"); - return 0; + return 0; } -static int -alsa_mixer_timeout(void *data) +static int alsa_mixer_timeout(void *data) +{ + if (mixer) + { + snd_mixer_close(mixer); + mixer = NULL; + pcm_element = NULL; + } + mixer_timeout = 0; + mixer_start = TRUE; + + g_message("alsa mixer timed out"); + return FALSE; +} + +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) { - if (mixer) { - snd_mixer_close(mixer); - mixer = NULL; - pcm_element = NULL; - } - mixer_timeout = 0; - mixer_start = TRUE; + long ll = *l, lr = *r; + + if (mixer_start) + { + alsa_setup_mixer(); + mixer_start = FALSE; + } + + if (alsa_cfg.soft_volume) + { + *l = alsa_cfg.vol.left; + *r = alsa_cfg.vol.right; + } + + if (!pcm_element) + return; - g_message("alsa mixer timed out"); - return FALSE; + snd_mixer_handle_events(mixer); + + if (!alsa_cfg.soft_volume) + { + 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; + } + if (mixer_timeout) + gtk_timeout_remove(mixer_timeout); + mixer_timeout = gtk_timeout_add(5000, alsa_mixer_timeout, NULL); } -static void alsa_cleanup_mixer(void) +void alsa_set_volume(int l, int r) { - pcm_element = NULL; - if (mixer) { - snd_mixer_close(mixer); - mixer = NULL; - } + if (alsa_cfg.soft_volume) + { + alsa_cfg.vol.left = l; + alsa_cfg.vol.right = r; + return; + } + + if (!pcm_element) + return; + + 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); } -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); - - if (alsa_cfg.soft_volume) { - *l = alsa_cfg.vol.left; - *r = alsa_cfg.vol.right; - } - else { - 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; - } - if (mixer_timeout) - gtk_timeout_remove(mixer_timeout); - mixer_timeout = gtk_timeout_add(5000, alsa_mixer_timeout, NULL); -} - - -void -alsa_set_volume(int l, int r) -{ - if (!pcm_element) - return; - - if (alsa_cfg.soft_volume) { - alsa_cfg.vol.left = l; - alsa_cfg.vol.right = 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); - } -} - /* * audio stuff */ -int alsa_playing(void) -{ - if (!going || paused || alsa_pcm == NULL) - return FALSE; - - return(snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING); -} - - -/* handle generic errors */ -static int alsa_handle_error(int err) -{ - switch (err) { - case -EPIPE: /* XRUN */ - if (alsa_cfg.debug) { - snd_pcm_status_t *alsa_status; - 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); - } - } - return snd_pcm_prepare(alsa_pcm); - - case -ESTRPIPE: /* suspend */ - while ((err = snd_pcm_resume(alsa_pcm)) == -EAGAIN) - sleep(1); /* wait until suspend flag is released */ - if (err < 0) { - g_warning("suspend_recover(): snd_pcm_resume() failed."); - return snd_pcm_prepare(alsa_pcm); - } - break; - } - - return err; -} - -/* 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_handle_error(ret); - if (ret < 0) { - g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s", - snd_strerror(-ret)); - return 0; - } - } - return ret; -} - -/* 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"); - if (multi_thread) - pause_request = p; - else - alsa_do_pause(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; - } -} - -/* reopen ALSA PCM */ -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); -} - -/* 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) -{ - if (multi_thread) { - flush_request = time; - while (flush_request != -1) - xmms_usleep(10000); - } else - alsa_do_flush(time); -} - -void alsa_close(void) -{ - if (! going) - return; - - debug("Closing device"); - - going = 0; - - if (multi_thread) - g_thread_join(audio_thread); - else - alsa_close_pcm(); - - alsa_cleanup_mixer(); - - xmms_convert_buffers_destroy(convertb); - convertb = NULL; - g_free(inputf); - inputf = NULL; - g_free(effectf); - effectf = NULL; - g_free(outputf); - outputf = NULL; - - alsa_save_config(); - - if (alsa_cfg.debug) - snd_output_close(logs); - debug("Device closed"); -} - /* 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); -} - -/* get the free space on buffer */ -int alsa_free(void) -{ - int result = 0; - if (multi_thread) - result = thread_buffer_size - get_thread_buffer_filled() - 1; - else if (! paused && alsa_pcm) - result = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail()); - return result; + 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; -int -alsa_get_output_time(void) -{ - snd_pcm_sframes_t delay; - guint64 bytes = 0; + if (!going || alsa_pcm == NULL) + return 0; - if (!going || alsa_pcm == NULL) - return 0; - - if (!snd_pcm_delay(alsa_pcm, &delay)) { - bytes = snd_pcm_frames_to_bytes(alsa_pcm, delay); - if (alsa_hw_written < bytes) - bytes = 0; - else - bytes = alsa_hw_written - bytes; - } - return output_time_offset + (bytes * 1000) / outputf->bps; + 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) +int alsa_get_written_time(void) { - if (!going) - return 0; - return (alsa_total_written * 1000) / inputf->bps; + if (!going) + return 0; + return (alsa_total_written * 1000) / inputf->bps; } -#define STEREO_ADJUST(type, type2, endian) \ -do { \ - type *ptr = data; \ - for (i = 0; i < length; i += 4) \ - { \ - *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \ - alsa_cfg.vol.left / 100); \ - ptr++; \ - *ptr = type2##_TO_##endian(type2##_FROM_##endian(*ptr) * \ - alsa_cfg.vol.right / 100); \ - ptr++; \ - } \ +#define STEREO_ADJUST(type, type2, endian) \ +do { \ + type *ptr = data; \ + for (i = 0; i < length; i += 4) \ + { \ + *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \ + alsa_cfg.vol.left / 100); \ + ptr++; \ + *ptr = type2##_TO_##endian(type2##_FROM_##endian(*ptr) * \ + alsa_cfg.vol.right / 100); \ + ptr++; \ + } \ } while (0) -#define MONO_ADJUST(type, type2, endian) \ -do { \ - type *ptr = data; \ - for (i = 0; i < length; i += 4) \ - { \ - *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \ - vol / 100); \ - ptr++; \ - } \ +#define MONO_ADJUST(type, type2, endian) \ +do { \ + type *ptr = data; \ + for (i = 0; i < length; i += 2) \ + { \ + *ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) * \ + vol / 100); \ + ptr++; \ + } \ } while (0) -#define VOLUME_ADJUST(type, type2, endian) \ -do { \ - if (channels == 2) \ - STEREO_ADJUST(type, type2, endian); \ - else \ - MONO_ADJUST(type, type2, endian); \ +#define VOLUME_ADJUST(type, type2, endian) \ +do { \ + if (channels == 2) \ + STEREO_ADJUST(type, type2, endian); \ + else \ + MONO_ADJUST(type, type2, endian); \ } while (0) -#define STEREO_ADJUST8(type) \ -do { \ - type *ptr = data; \ - for (i = 0; i < length; i += 2) \ - { \ - *ptr = *ptr * alsa_cfg.vol.left / 100; \ - ptr++; \ - *ptr = *ptr * alsa_cfg.vol.right / 100; \ - ptr++; \ - } \ +#define STEREO_ADJUST8(type) \ +do { \ + type *ptr = data; \ + for (i = 0; i < length; i += 2) \ + { \ + *ptr = *ptr * alsa_cfg.vol.left / 100; \ + ptr++; \ + *ptr = *ptr * alsa_cfg.vol.right / 100; \ + ptr++; \ + } \ } while (0) -#define MONO_ADJUST8(type) \ -do { \ - type *ptr = data; \ - for (i = 0; i < length; i += 4) \ - { \ - *ptr = *ptr * vol / 100; \ - ptr++; \ - } \ +#define MONO_ADJUST8(type) \ +do { \ + type *ptr = data; \ + for (i = 0; i < length; i++) \ + { \ + *ptr = *ptr * vol / 100; \ + ptr++; \ + } \ } while (0) -#define VOLUME_ADJUST8(type) \ -do { \ - if (channels == 2) \ - STEREO_ADJUST8(type); \ - else \ - MONO_ADJUST8(type); \ +#define VOLUME_ADJUST8(type) \ +do { \ + if (channels == 2) \ + STEREO_ADJUST8(type); \ + else \ + MONO_ADJUST8(type); \ } while (0) -static void -volume_adjust(void *data, int length, AFormat fmt, int channels) +static void volume_adjust(void* data, int length, AFormat fmt, int channels) { - int i, vol; + int i, vol; - if ((alsa_cfg.vol.left == 100 && alsa_cfg.vol.right == 100) || - (channels == 1 && - (alsa_cfg.vol.left == 100 || alsa_cfg.vol.right == 100))) - return; + if ((alsa_cfg.vol.left == 100 && alsa_cfg.vol.right == 100) || + (channels == 1 && + (alsa_cfg.vol.left == 100 || alsa_cfg.vol.right == 100))) + return; - vol = MAX(alsa_cfg.vol.left, alsa_cfg.vol.right); + vol = MAX(alsa_cfg.vol.left, alsa_cfg.vol.right); - switch (fmt) { - case FMT_S16_LE: - VOLUME_ADJUST(gint16, GINT16, LE); - break; - case FMT_U16_LE: - VOLUME_ADJUST(guint16, GUINT16, LE); - break; - case FMT_S16_BE: - VOLUME_ADJUST(gint16, GINT16, BE); - break; - case FMT_U16_BE: - VOLUME_ADJUST(guint16, GUINT16, BE); - break; - case FMT_S8: - VOLUME_ADJUST8(gint8); - break; - case FMT_U8: - VOLUME_ADJUST8(guint8); - break; - default: - g_warning("volume_adjust(): unhandled format: %d", fmt); - break; - } + switch (fmt) + { + case FMT_S16_LE: + VOLUME_ADJUST(gint16, GINT16, LE); + break; + case FMT_U16_LE: + VOLUME_ADJUST(guint16, GUINT16, LE); + break; + case FMT_S16_BE: + VOLUME_ADJUST(gint16, GINT16, BE); + break; + case FMT_U16_BE: + VOLUME_ADJUST(guint16, GUINT16, BE); + break; + case FMT_S8: + VOLUME_ADJUST8(gint8); + break; + case FMT_U8: + VOLUME_ADJUST8(guint8); + break; + default: + g_warning("volue_adjust(): unhandled format: %d", fmt); + break; + } } @@ -646,566 +673,507 @@ */ static void alsa_do_write(gpointer data, int length) { - EffectPlugin *ep = NULL; - int new_freq; - int new_chn; - AFormat f; + EffectPlugin *ep = NULL; + int new_freq; + int new_chn; + AFormat f; - if (paused) - return; + if (paused) + return; - new_freq = inputf->rate; - new_chn = inputf->channels; - f = inputf->xmms_format; + new_freq = inputf->rate; + new_chn = inputf->channels; + f = inputf->xmms_format; - if (effects_enabled() && (ep = get_current_effect_plugin()) && - ep->query_format) - ep->query_format(&f, &new_freq, &new_chn); + if (effects_enabled() && (ep = get_current_effect_plugin()) && + ep->query_format) + ep->query_format(&f, &new_freq, &new_chn); - if (f != effectf->xmms_format || new_freq != effectf->rate || - new_chn != effectf->channels) { - debug("Changing audio format for effect plugin"); - g_free(effectf); - effectf = snd_format_from_xmms(f, new_freq, new_chn); - if (alsa_reopen(effectf) < 0) { - /* fatal error... */ - alsa_close(); - return; - } - } + if (f != effectf->xmms_format || new_freq != effectf->rate || + new_chn != effectf->channels) + { + debug("Changing audio format for effect plugin"); + g_free(effectf); + effectf = snd_format_from_xmms(f, new_freq, new_chn); + if (alsa_reopen(effectf) < 0) + { + /* fatal error... */ + alsa_close(); + return; + } + } - if (ep) { - length = ep->mod_samples(&data, length, - inputf->xmms_format, - inputf->rate, inputf->channels); - } + if (ep) + length = ep->mod_samples(&data, length, + inputf->xmms_format, + inputf->rate, + inputf->channels); - if (alsa_convert_func != NULL) - length = alsa_convert_func(convertb, &data, length); - if (alsa_stereo_convert_func != NULL) - length = alsa_stereo_convert_func(convertb, &data, length); - if (alsa_frequency_convert_func != NULL) - length = alsa_frequency_convert_func(convertb, &data, length, - effectf->rate, outputf->rate); + if (alsa_convert_func != NULL) + length = alsa_convert_func(convertb, &data, length); + if (alsa_stereo_convert_func != NULL) + length = alsa_stereo_convert_func(convertb, &data, length); + if (alsa_frequency_convert_func != NULL) + length = alsa_frequency_convert_func(convertb, &data, length, + effectf->rate, + outputf->rate); - if (alsa_cfg.soft_volume) - volume_adjust(data, length, outputf->xmms_format, outputf->channels); + if (alsa_cfg.soft_volume) + volume_adjust(data, length, outputf->xmms_format, outputf->channels); - if (mmap) - alsa_mmap_audio(data, length); - else - alsa_write_audio(data, length); + alsa_write_audio(data, length); } /* write callback */ void alsa_write(gpointer data, int length) { - if (multi_thread) { - int cnt; - char *src = (char *)data; - - 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; - } - } else { - alsa_do_write(data, length); - alsa_total_written += 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); + snd_pcm_sframes_t written_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_handle_error((int)written_frames); - if (err < 0) { - g_warning("alsa_write_audio(): write error: %s", - snd_strerror(-err)); - break; - } - } - } -} - -/* transfer data to audio h/w via mmap - * - * basically, it makes sense only in the single thread mode. - * also, don't expect too much efficiency over mmap... - */ -static void -alsa_mmap_audio(char *data, int length) -{ - int cnt, err; - snd_pcm_uframes_t offset, frames; - const snd_pcm_channel_area_t *chan_areas; - snd_pcm_channel_area_t src_area; - int ch, channels, sample_bits; - - if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_XRUN) - alsa_handle_error(-EPIPE); - - /* need to call this before snd_pcm_mmap_begin() */ - alsa_get_avail(); + while (length > 0) + { + int frames = snd_pcm_bytes_to_frames(alsa_pcm, length); + written_frames = snd_pcm_writei(alsa_pcm, data, frames); - channels = outputf->channels; - sample_bits = outputf->sample_bits; - while (length > 0) { - frames = snd_pcm_bytes_to_frames(alsa_pcm, length); - if ((err = snd_pcm_mmap_begin(alsa_pcm, &chan_areas, &offset, &frames) < 0)) { - g_warning("alsa_mmap_audio(): snd_pcm_mmap_begin() " "failed: %s", - snd_strerror(-err)); - break; - } - - cnt = snd_pcm_frames_to_bytes(alsa_pcm, frames); - - src_area.addr = data; - src_area.first = 0; - src_area.step = channels * sample_bits; - for (ch = 0; ch < channels; ch++) { - snd_pcm_area_copy(&chan_areas[ch], offset, - &src_area, 0, frames, outputf->format); - src_area.first += sample_bits; - } - - err = snd_pcm_mmap_commit(alsa_pcm, offset, frames); - if (err < 0) { - err = alsa_handle_error(err); - if (err < 0) - g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit() " - "failed: %s", snd_strerror(-err)); - } - else { - if (err != frames) - g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit " - "returned %d, expected %d", err, (int)frames); - data += cnt; - length -= cnt; - alsa_hw_written += cnt; - } - } - - /* PCM isn't started automatically in the case of mmap mode, so - * we need to trigger manually - */ - if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED) { - if (alsa_hw_written >= hw_period_size) - snd_pcm_start(alsa_pcm); - } + 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_handle_error((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; - int err; + 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; - - if (length > 0 && snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED) { - if ((err = snd_pcm_start(alsa_pcm)) < 0) - g_warning("alsa_mmap_audio(): snd_pcm_start() " - "failed: %s", snd_strerror(-err)); - } - } + 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); - struct pollfd *pfds; - unsigned short *revents; + int npfds = snd_pcm_poll_descriptors_count(alsa_pcm); + struct pollfd *pfds; + unsigned short *revents; - if (npfds <= 0) - goto _error; - pfds = alloca(sizeof(*pfds) * npfds); - revents = alloca(sizeof(*revents) * npfds); - while (going && alsa_pcm) { - if (! paused && get_thread_buffer_filled() > hw_period_size_in) { - snd_pcm_poll_descriptors(alsa_pcm, pfds, npfds); - if (poll(pfds, npfds, 10) > 0) { - /* need to check revents. poll() with dmix returns - * a postive value even if no data is available - */ - int i; - snd_pcm_poll_descriptors_revents(alsa_pcm, pfds, npfds, revents); - for (i = 0; i < npfds; i++) - if (revents[i] & POLLOUT) { - alsa_write_out_thread_data(); - break; - } - } - } else - xmms_usleep(10000); + if (npfds <= 0) + goto _error; + pfds = alloca(sizeof(*pfds) * npfds); + revents = alloca(sizeof(*revents) * npfds); + while (going && alsa_pcm) + { + if (get_thread_buffer_filled() > prebuffer_size) + prebuffer = FALSE; + if (!paused && !prebuffer && + get_thread_buffer_filled() > hw_period_size_in) + { + snd_pcm_poll_descriptors(alsa_pcm, pfds, npfds); + if (poll(pfds, npfds, 10) > 0) + { + /* + * need to check revents. poll() with + * dmix returns a postive value even + * if no data is available + */ + int i; + snd_pcm_poll_descriptors_revents(alsa_pcm, pfds, + npfds, revents); + for (i = 0; i < npfds; i++) + if (revents[i] & POLLOUT) + { + alsa_write_out_thread_data(); + break; + } + } + } + else + xmms_usleep(10000); - if (pause_request != paused) - alsa_do_pause(pause_request); - - if (flush_request != -1) { - alsa_do_flush(flush_request); - flush_request = -1; - } - } + if (pause_request != paused) + alsa_do_pause(pause_request); - _error: - alsa_close_pcm(); - g_free(thread_buffer); - thread_buffer = NULL; + if (flush_request != -1) + { + alsa_do_flush(flush_request); + flush_request = -1; + prebuffer = TRUE; + } + } - g_thread_exit(NULL); - - /* shut GCC up */ - return NULL; + _error: + alsa_close_pcm(); + g_free(thread_buffer); + thread_buffer = NULL; + pthread_exit(NULL); } /* open callback */ -int -alsa_open(AFormat fmt, int rate, int nch) +int alsa_open(AFormat fmt, int rate, int nch) { - debug("Opening device"); - inputf = snd_format_from_xmms(fmt, rate, nch); - effectf = snd_format_from_xmms(fmt, rate, nch); + debug("Opening device"); + inputf = snd_format_from_xmms(fmt, rate, nch); + effectf = snd_format_from_xmms(fmt, rate, nch); - if (alsa_cfg.debug) - snd_output_stdio_attach(&logs, stdout, 0); + if (alsa_cfg.debug) + snd_output_stdio_attach(&logs, stdout, 0); - mmap = alsa_cfg.mmap; + if (alsa_setup(inputf) < 0) + { + alsa_close(); + return 0; + } - if (alsa_setup(inputf) < 0) { - alsa_close(); - return 0; - } + if (!mixer) + alsa_setup_mixer(); - if (!mixer) - alsa_setup_mixer(); - - convertb = xmms_convert_buffers_new(); + convertb = xmms_convert_buffers_new(); - output_time_offset = 0; - alsa_total_written = alsa_hw_written = 0; - going = TRUE; - paused = FALSE; - - multi_thread = alsa_cfg.multi_thread; - debug("ALSA: multi_thread = %d\n", multi_thread); + output_time_offset = 0; + alsa_total_written = alsa_hw_written = 0; + going = TRUE; + paused = FALSE; + prebuffer = TRUE; + remove_prebuffer = FALSE; - if (multi_thread) { - thread_buffer_size = (guint64)alsa_cfg.thread_buffer_time * 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; - 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; - - audio_thread = g_thread_create(alsa_loop, NULL, TRUE, NULL); - } - - return 1; + thread_buffer_size = (guint64)alsa_cfg.thread_buffer_time * 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; + + pthread_create(&audio_thread, NULL, alsa_loop, NULL); + return 1; } -static struct snd_format * -snd_format_from_xmms(AFormat fmt, int rate, int channels) +static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels) { - struct snd_format *f = g_malloc(sizeof(struct snd_format)); - int i; + struct snd_format *f = g_malloc(sizeof(struct snd_format)); + int i; - f->xmms_format = fmt; - f->format = SND_PCM_FORMAT_UNKNOWN; + 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; - break; - } + for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) + if (format_table[i].xmms == fmt) + { + f->format = format_table[i].alsa; + break; + } - /* 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; - } + /* 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; + 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; + return f; } -static int -format_from_alsa(snd_pcm_format_t fmt) +static int format_from_alsa(snd_pcm_format_t fmt) { - int i; - for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) - if (format_table[i].alsa == fmt) - return format_table[i].xmms; - g_warning("Unsupported format: %s", snd_pcm_format_name(fmt)); - return -1; + int i; + for (i = 0; i < sizeof(format_table) / sizeof(format_table[0]); i++) + if (format_table[i].alsa == fmt) + return format_table[i].xmms; + g_warning("Unsupported format: %s", snd_pcm_format_name(fmt)); + return -1; } -static int -alsa_setup(struct snd_format *f) +static int alsa_setup(struct snd_format *f) { - int err; - snd_pcm_hw_params_t *hwparams; - snd_pcm_sw_params_t *swparams; - int alsa_buffer_time; - unsigned int alsa_period_time; - snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; + int err; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + int alsa_buffer_time; + unsigned int alsa_period_time; + snd_pcm_uframes_t alsa_buffer_size, alsa_period_size; - debug("alsa_setup"); + debug("alsa_setup"); - alsa_convert_func = NULL; - alsa_stereo_convert_func = NULL; - alsa_frequency_convert_func = NULL; + alsa_convert_func = NULL; + alsa_stereo_convert_func = NULL; + alsa_frequency_convert_func = NULL; - g_free(outputf); - outputf = snd_format_from_xmms(f->xmms_format, f->rate, f->channels); + g_free(outputf); + outputf = snd_format_from_xmms(f->xmms_format, f->rate, f->channels); - 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); */ + 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; + } - if (alsa_cfg.debug) { - snd_pcm_info_t *info; - int alsa_card, alsa_device, alsa_subdevice; + /* doesn't care about non-blocking */ + /* snd_pcm_nonblock(alsa_pcm, 0); */ + + if (alsa_cfg.debug) + { + snd_pcm_info_t *info; + 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_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; - } + snd_pcm_hw_params_alloca(&hwparams); - if (mmap && - (err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams, - SND_PCM_ACCESS_MMAP_INTERLEAVED)) - < 0) { - g_message("alsa_setup(): Cannot set mmap'ed mode: %s. " - "falling back to direct write", snd_strerror(-err)); - mmap = 0; - } + 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 (!mmap && - (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; - } + 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; + } + + if ((err = snd_pcm_hw_params_set_format(alsa_pcm, hwparams, outputf->format)) < 0) + { + /* + * Try if one of these format work (one of them should work + * on almost all soundcards) + */ + snd_pcm_format_t formats[] = {SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_U8}; + int i; - if ((err = - snd_pcm_hw_params_set_format(alsa_pcm, hwparams, - outputf->format)) < 0) { - /* - * Try if one of these format work (one of them should work - * on almost all soundcards) - */ - snd_pcm_format_t formats[] = { SND_PCM_FORMAT_S16_LE, - SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U8 - }; - int i; - - for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { - if (snd_pcm_hw_params_set_format(alsa_pcm, hwparams, - formats[i]) == 0) { - outputf->format = formats[i]; - break; - } - } - if (outputf->format != f->format) { - outputf->xmms_format = format_from_alsa(outputf->format); - debug("Converting format from %d to %d", - f->xmms_format, outputf->xmms_format); - if (outputf->xmms_format < 0) - return -1; - alsa_convert_func = - xmms_convert_get_func(outputf->xmms_format, - f->xmms_format); - if (alsa_convert_func == NULL) - return -1; - } - else { - g_warning("alsa_setup(): Sample format not " - "available for playback: %s", snd_strerror(-err)); - return -1; - } - } + for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) + { + if (snd_pcm_hw_params_set_format(alsa_pcm, hwparams, + formats[i]) == 0) + { + outputf->format = formats[i]; + break; + } + } + if (outputf->format != f->format) + { + outputf->xmms_format = + format_from_alsa(outputf->format); + debug("Converting format from %d to %d", + f->xmms_format, outputf->xmms_format); + if (outputf->xmms_format < 0) + return -1; + alsa_convert_func = + xmms_convert_get_func(outputf->xmms_format, + f->xmms_format); + if (alsa_convert_func == NULL) + return -1; + } + else + { + 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) { - debug("Converting channels from %d to %d", - f->channels, outputf->channels); - alsa_stereo_convert_func = - xmms_convert_get_channel_func(outputf->xmms_format, - outputf->channels, - f->channels); - if (alsa_stereo_convert_func == NULL) - 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) { - debug("Converting samplerate from %d to %d", - f->rate, outputf->rate); - alsa_frequency_convert_func = - xmms_convert_get_frequency_func(outputf->xmms_format, - outputf->channels); - if (alsa_frequency_convert_func == NULL) - return -1; - } + snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &outputf->channels); + if (outputf->channels != f->channels) + { + debug("Converting channels from %d to %d", + f->channels, outputf->channels); + alsa_stereo_convert_func = + xmms_convert_get_channel_func(outputf->xmms_format, + outputf->channels, + f->channels); + if (alsa_stereo_convert_func == NULL) + return -1; + } - outputf->sample_bits = snd_pcm_format_physical_width(outputf->format); - outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3; + 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) + { + debug("Converting samplerate from %d to %d", + f->rate, outputf->rate); + alsa_frequency_convert_func = + xmms_convert_get_frequency_func(outputf->xmms_format, + outputf->channels); + if (alsa_frequency_convert_func == NULL) + return -1; + } - 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; - } + outputf->sample_bits = snd_pcm_format_physical_width(outputf->format); + outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3; - 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; - } + 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; + } - 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; - } + 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_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; + } - 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); + + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(alsa_pcm, swparams); - alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams); - - snd_pcm_sw_params_alloca(&swparams); - snd_pcm_sw_params_current(alsa_pcm, swparams); + /* This has effect for non-mmap only */ + 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; + } - /* This has effect for non-mmap only */ - 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); - } + 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) { - 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; - } else { - hw_buffer_size_in = hw_buffer_size; - hw_period_size_in = hw_period_size; - } + 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), - snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps); + 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), + snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps); - return 0; + return 0; }
--- a/Plugins/Output/alsa/configure.c Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/configure.c Sun Nov 20 00:34:09 2005 -0800 @@ -1,6 +1,6 @@ /* XMMS - ALSA output plugin * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org> - * Copyright (C) 2003-2004 Haavard Kvaalen + * 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 @@ -18,17 +18,10 @@ */ #include "alsa.h" #include <stdio.h> -#include <libaudacious/configdb.h> -#include <glib/gi18n.h> - static GtkWidget *configure_win = NULL; static GtkWidget *buffer_time_spin, *period_time_spin; -static GtkWidget *mmap_button, *softvolume_toggle_button; - -static GtkWidget *thread_buffer_time_spin; -static GtkWidget *mthread_button; - +static GtkWidget *softvolume_toggle_button, *thread_buffer_time_spin; static GtkWidget *devices_combo, *mixer_devices_combo; @@ -39,414 +32,418 @@ #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) +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); + 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.thread_buffer_time = GET_SPIN_INT(thread_buffer_time_spin); - alsa_cfg.multi_thread = GET_TOGGLE(mthread_button); - alsa_cfg.mmap = GET_TOGGLE(mmap_button); - alsa_cfg.soft_volume = GET_TOGGLE(softvolume_toggle_button); - alsa_cfg.mixer_card = current_mixer_card; - alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry); + alsa_cfg.soft_volume = GET_TOGGLE(softvolume_toggle_button); + 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) +{ + ConfigDb *cfgfile = bmp_cfg_db_open(); - alsa_save_config(); - gtk_widget_destroy(configure_win); + bmp_cfg_db_set_int(cfgfile, "ALSA", "buffer_time", alsa_cfg.buffer_time); + bmp_cfg_db_set_int(cfgfile, "ALSA", "period_time", alsa_cfg.period_time); + bmp_cfg_db_set_int(cfgfile, "ALSA", "thread_buffer_time", alsa_cfg.thread_buffer_time); + bmp_cfg_db_set_string(cfgfile,"ALSA","pcm_device", alsa_cfg.pcm_device); + bmp_cfg_db_set_int(cfgfile, "ALSA", "mixer_card", alsa_cfg.mixer_card); + bmp_cfg_db_set_string(cfgfile,"ALSA","mixer_device", alsa_cfg.mixer_device); + bmp_cfg_db_set_bool(cfgfile, "ALSA", "soft_volume", + alsa_cfg.soft_volume); + bmp_cfg_db_set_int(cfgfile, "ALSA", "volume_left", alsa_cfg.vol.left); + bmp_cfg_db_set_int(cfgfile, "ALSA", "volume_right", alsa_cfg.vol.right); + bmp_cfg_db_close(cfgfile); } -void -alsa_save_config(void) -{ - //ConfigFile *cfgfile = xmms_cfg_open_default_file(); - ConfigDb *cfgfile; - - cfgfile = bmp_cfg_db_open(); - bmp_cfg_db_set_int(cfgfile, "ALSA", "buffer_time", alsa_cfg.buffer_time); - bmp_cfg_db_set_int(cfgfile, "ALSA", "thread_buffer_time", alsa_cfg.thread_buffer_time); - bmp_cfg_db_set_int(cfgfile, "ALSA", "period_time", alsa_cfg.period_time); - bmp_cfg_db_set_bool(cfgfile, "ALSA", "multi_thread", alsa_cfg.multi_thread); - bmp_cfg_db_set_bool(cfgfile, "ALSA", "mmap", alsa_cfg.mmap); - bmp_cfg_db_set_string(cfgfile, "ALSA", "pcm_device", alsa_cfg.pcm_device); - bmp_cfg_db_set_int(cfgfile, "ALSA", "mixer_card", alsa_cfg.mixer_card); - bmp_cfg_db_set_string(cfgfile, "ALSA", "mixer_device", - alsa_cfg.mixer_device); - bmp_cfg_db_set_bool(cfgfile, "ALSA", "soft_volume", alsa_cfg.soft_volume); - bmp_cfg_db_set_int(cfgfile, "ALSA", "volume_left", alsa_cfg.vol.left); - bmp_cfg_db_set_int(cfgfile, "ALSA", "volume_right", alsa_cfg.vol.right); -// bmp_cfg_db_set_default_file(cfgfile); -// xmms_cfg_free(cfgfile); - bmp_cfg_db_close(cfgfile); -} - -static int -get_cards(GtkOptionMenu * omenu, GCallback cb, int active) +static int get_cards(GtkOptionMenu *omenu, GtkSignalFunc cb, int active) { - GtkWidget *menu, *item; - int card = -1, err, set = 0, curr = -1; + 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)); + 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; + 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; - } + 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); - g_signal_connect(item, "activate", G_CALLBACK(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; - } - } + 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; + gtk_option_menu_set_menu(omenu, menu); + return set; } -static int -get_mixer_devices(GtkCombo * combo, int card) +static int get_mixer_devices(GtkCombo *combo, int card) { - GList *items = NULL; - int err; - snd_mixer_t *mixer; - snd_mixer_elem_t *current; + GList *items = NULL; + int err; + snd_mixer_t *mixer; + snd_mixer_elem_t *current; - if ((err = alsa_get_mixer(&mixer, card)) < 0) - return err; + if ((err = alsa_get_mixer(&mixer, card)) < 0) + return err; + + current = snd_mixer_first_elem(mixer); - 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); + } - 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); - gtk_combo_set_popdown_strings(combo, items); - - return 0; + return 0; } -static void -get_devices_for_card(GtkCombo * combo, int card) +static void get_devices_for_card(GtkCombo *combo, int card) { - GtkWidget *item; - int pcm_device = -1, err; - snd_pcm_info_t *pcm_info; - snd_ctl_t *ctl; - char dev[64], *card_name; + GtkWidget *item; + int pcm_device = -1, err; + snd_pcm_info_t *pcm_info; + snd_ctl_t *ctl; + char dev[64], *card_name; - sprintf(dev, "hw:%i", card); + 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_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"); - } + 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); + 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; + 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); + 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; - } + 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); - } + 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); + snd_ctl_close(ctl); } -static void -get_devices(GtkCombo * combo) +static void get_devices(GtkCombo *combo) { - GtkWidget *item; - int card = -1; - int err = 0; - char *descr; + 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); - 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; + } - 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; - } - } + 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) +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); + 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); } -static void -softvolume_toggle_cb(GtkToggleButton * widget, gpointer data) +static void softvolume_toggle_cb(GtkToggleButton * widget, gpointer data) { - gboolean softvolume = gtk_toggle_button_get_active(widget); - gtk_widget_set_sensitive(GTK_WIDGET(data), !softvolume); - gtk_widget_set_sensitive(mixer_devices_combo, !softvolume); + gboolean softvolume = gtk_toggle_button_get_active(widget); + gtk_widget_set_sensitive(GTK_WIDGET(data), !softvolume); + gtk_widget_set_sensitive(mixer_devices_combo, !softvolume); } -void -alsa_configure(void) +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 *buffer_frame, *buffer_vbox, *buffer_table; - GtkWidget *buffer_time_label, *period_time_label; - GtkObject *buffer_time_adj, *period_time_adj; - GtkWidget *bbox, *ok, *cancel; + 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_frame, *buffer_vbox, *buffer_table; + GtkWidget *card_frame, *buffer_time_label, *period_time_label; GtkWidget *thread_buffer_time_label; - GtkObject *thread_buffer_time_adj; + GtkObject *buffer_time_adj, *period_time_adj, *thread_buffer_time_adj; + GtkWidget *bbox, *ok, *cancel; - int mset; + int mset; - if (configure_win) { - gtk_window_present(GTK_WINDOW(configure_win)); - return; - } + if (configure_win) + { + gdk_window_raise(configure_win->window); + return; + } - configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_signal_connect(configure_win, "destroy", - G_CALLBACK(gtk_widget_destroyed), &configure_win); - gtk_window_set_title(GTK_WINDOW(configure_win), - _("ALSA Driver configuration")); - gtk_window_set_type_hint(GTK_WINDOW(configure_win), - GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_resizable(GTK_WINDOW(configure_win), FALSE); - gtk_container_border_width(GTK_CONTAINER(configure_win), 10); + 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); + 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); - notebook = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + adevice_frame = gtk_frame_new(_("Audio device:")); + gtk_box_pack_start(GTK_BOX(dev_vbox), adevice_frame, FALSE, FALSE, 0); - dev_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(dev_vbox), 5); + 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); - adevice_frame = gtk_frame_new(_("Audio device:")); - gtk_box_pack_start(GTK_BOX(dev_vbox), adevice_frame, FALSE, FALSE, 0); + 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); - 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); + 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); - 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); + softvolume_toggle_button = gtk_check_button_new_with_label( + _("Use software volume control")); - mixer_frame = gtk_frame_new(_("Mixer:")); - gtk_box_pack_start(GTK_BOX(dev_vbox), mixer_frame, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(mixer_box), softvolume_toggle_button, + 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); - - softvolume_toggle_button = - gtk_check_button_new_with_label(_("Use software volume control")); + 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); - gtk_box_pack_start(GTK_BOX(mixer_box), softvolume_toggle_button, - 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_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_om = gtk_option_menu_new(); + mset = get_cards(GTK_OPTION_MENU(mixer_card_om), + mixer_card_cb, alsa_cfg.mixer_card); - 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); + gtk_table_attach(GTK_TABLE(mixer_table), mixer_card_om, + 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); - mixer_card_om = gtk_option_menu_new(); - mset = get_cards(GTK_OPTION_MENU(mixer_card_om), - G_CALLBACK(mixer_card_cb), alsa_cfg.mixer_card); + 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_card_om, - 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(mixer_table), mixer_devices_combo, + 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 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_signal_connect(GTK_OBJECT(softvolume_toggle_button), "toggled", + softvolume_toggle_cb, mixer_card_om); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(softvolume_toggle_button), + alsa_cfg.soft_volume); + + 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); - gtk_table_attach(GTK_TABLE(mixer_table), mixer_devices_combo, - 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); + 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); - g_signal_connect(softvolume_toggle_button, "toggled", - G_CALLBACK(softvolume_toggle_cb), mixer_card_om); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(softvolume_toggle_button), - alsa_cfg.soft_volume); + gtk_container_set_border_width(GTK_CONTAINER(card_vbox), 5); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dev_vbox, - gtk_label_new(_("Device settings"))); - - buffer_frame = gtk_frame_new(_("Advanced settings:")); - gtk_container_set_border_width(GTK_CONTAINER(buffer_frame), 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_vbox = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(buffer_frame), buffer_vbox); - - gtk_container_set_border_width(GTK_CONTAINER(buffer_vbox), 5); + 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_table = gtk_table_new(2, 3, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(buffer_table), 5); - gtk_table_set_col_spacings(GTK_TABLE(buffer_table), 5); - gtk_box_pack_start(GTK_BOX(buffer_vbox), buffer_table, FALSE, FALSE, 0); - - 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); - buffer_time_adj = gtk_adjustment_new(alsa_cfg.buffer_time, - 200, 1000000, 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); + - 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); + buffer_frame = gtk_frame_new(_("XMMS:")); + gtk_box_pack_start_defaults(GTK_BOX(advanced_vbox), buffer_frame); + + buffer_vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(buffer_frame), buffer_vbox); - 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_container_set_border_width(GTK_CONTAINER(buffer_vbox), 5); - thread_buffer_time_label = gtk_label_new(_("Thread buffer time (ms):")); + buffer_table = gtk_table_new(1, 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(buffer_vbox), buffer_table); + + thread_buffer_time_label = gtk_label_new(_("Buffer time (ms):")); gtk_label_set_justify(GTK_LABEL(thread_buffer_time_label), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment(GTK_MISC(thread_buffer_time_label), 0, 0.5); gtk_table_attach(GTK_TABLE(buffer_table), thread_buffer_time_label, - 0, 1, 2, 3, GTK_FILL, 0, 0, 0); + 0, 1, 0, 1, GTK_FILL, 0, 0, 0); thread_buffer_time_adj = gtk_adjustment_new(alsa_cfg.thread_buffer_time, - 1000, 1000000, 100, 100, 100); - thread_buffer_time_spin = gtk_spin_button_new(GTK_ADJUSTMENT(thread_buffer_time_adj), - 8, 0); - + 1000, 10000, 100, 100, 100); + thread_buffer_time_spin = + gtk_spin_button_new(GTK_ADJUSTMENT(thread_buffer_time_adj), 8, 0); + gtk_widget_set_usize(thread_buffer_time_spin, 60, -1); gtk_table_attach(GTK_TABLE(buffer_table), thread_buffer_time_spin, - 1, 2, 2, 3, 0, 0, 0, 0); - - mthread_button = gtk_check_button_new_with_label(_("Multi-thread mode")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mthread_button), - alsa_cfg.multi_thread); - gtk_box_pack_start(GTK_BOX(buffer_vbox), mthread_button, FALSE, FALSE, 0); - - mmap_button = gtk_check_button_new_with_label(_("Mmap mode")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmap_button), - alsa_cfg.mmap); - gtk_box_pack_start(GTK_BOX(buffer_vbox), mmap_button, FALSE, FALSE, 0); + 1, 2, 0, 1, 0, 0, 0, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), advanced_vbox, + gtk_label_new(_("Advanced settings"))); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buffer_frame, - 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); + 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); - cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); - - ok = gtk_button_new_from_stock(GTK_STOCK_OK); - gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); - - g_signal_connect(ok, "clicked", G_CALLBACK(configure_win_ok_cb), NULL); - GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); - gtk_widget_grab_default(ok); + ok = gtk_button_new_with_label(_("OK")); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", 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); - g_signal_connect_swapped(cancel, "clicked", - G_CALLBACK(gtk_widget_destroy), - configure_win); - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", + 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); + gtk_widget_show_all(configure_win); }
--- a/Plugins/Output/alsa/init.c Sat Nov 19 14:42:28 2005 -0800 +++ b/Plugins/Output/alsa/init.c Sun Nov 20 00:34:09 2005 -0800 @@ -1,6 +1,6 @@ /* XMMS - ALSA output plugin * Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org> - * Copyright (C) 2003-2004 Haavard Kvaalen + * 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 @@ -16,57 +16,56 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "libaudacious/configdb.h" #include "alsa.h" #include <dlfcn.h> #include <ctype.h> -#include <glib/gi18n.h> + +#define THREAD_BUFFER_TIME_MIN 1000 +#define THREAD_BUFFER_TIME_MAX 10000 struct alsa_config alsa_cfg; -void -alsa_init(void) +void alsa_init(void) { - ConfigDb *configdb; + ConfigDb *cfgfile; - memset(&alsa_cfg, 0, sizeof(alsa_cfg)); - alsa_cfg.buffer_time = 500; - alsa_cfg.period_time = 50; + memset(&alsa_cfg, 0, sizeof (alsa_cfg)); + alsa_cfg.buffer_time = 500; + alsa_cfg.period_time = 50; alsa_cfg.thread_buffer_time = 3000; - alsa_cfg.debug = 0; - alsa_cfg.multi_thread = 1; - alsa_cfg.mmap = 0; - alsa_cfg.vol.left = 100; - alsa_cfg.vol.right = 100; + alsa_cfg.debug = 0; + alsa_cfg.vol.left = 100; + alsa_cfg.vol.right = 100; - configdb = bmp_cfg_db_open(); - if (!bmp_cfg_db_get_string(configdb, "ALSA", "pcm_device", - &alsa_cfg.pcm_device)) - alsa_cfg.pcm_device = g_strdup("default"); - if (!bmp_cfg_db_get_string(configdb, "ALSA", "mixer_device", - &alsa_cfg.mixer_device)) - alsa_cfg.mixer_device = g_strdup("PCM"); - bmp_cfg_db_get_int(configdb, "ALSA", "mixer_card", &alsa_cfg.mixer_card); - bmp_cfg_db_get_int(configdb, "ALSA", "buffer_time", - &alsa_cfg.buffer_time); - bmp_cfg_db_get_int(configdb, "ALSA", "thread_buffer_time", - &alsa_cfg.thread_buffer_time); - bmp_cfg_db_get_int(configdb, "ALSA", "period_time", - &alsa_cfg.period_time); - bmp_cfg_db_get_bool(configdb, "ALSA", "mmap", &alsa_cfg.mmap); - bmp_cfg_db_get_bool(configdb, "ALSA", "multi_thread", &alsa_cfg.multi_thread); - bmp_cfg_db_get_bool(configdb, "ALSA", "soft_volume", - &alsa_cfg.soft_volume); - bmp_cfg_db_get_int(configdb, "ALSA", "volume_left", &alsa_cfg.vol.left); - bmp_cfg_db_get_int(configdb, "ALSA", "volume_right", &alsa_cfg.vol.right); + cfgfile = bmp_cfg_db_open(); + if (!bmp_cfg_db_get_string(cfgfile, "ALSA", "pcm_device", + &alsa_cfg.pcm_device)) + alsa_cfg.pcm_device = g_strdup("default"); + g_message("device: %s", alsa_cfg.pcm_device); + if (!bmp_cfg_db_get_string(cfgfile, "ALSA", "mixer_device", + &alsa_cfg.mixer_device)) + alsa_cfg.mixer_device = g_strdup("PCM"); + bmp_cfg_db_get_int(cfgfile, "ALSA", "mixer_card", &alsa_cfg.mixer_card); + bmp_cfg_db_get_int(cfgfile, "ALSA", "buffer_time", &alsa_cfg.buffer_time); + bmp_cfg_db_get_int(cfgfile, "ALSA", "period_time", &alsa_cfg.period_time); + bmp_cfg_db_get_int(cfgfile, "ALSA", "thread_buffer_time", + &alsa_cfg.thread_buffer_time); - bmp_cfg_db_get_bool(configdb, "ALSA", "debug", &alsa_cfg.debug); - - bmp_cfg_db_close(configdb); + alsa_cfg.thread_buffer_time = CLAMP(alsa_cfg.thread_buffer_time, + THREAD_BUFFER_TIME_MIN, + THREAD_BUFFER_TIME_MAX); + + bmp_cfg_db_get_bool(cfgfile, "ALSA", "soft_volume", + &alsa_cfg.soft_volume); + bmp_cfg_db_get_int(cfgfile, "ALSA", "volume_left", &alsa_cfg.vol.left); + bmp_cfg_db_get_int(cfgfile, "ALSA", "volume_right", &alsa_cfg.vol.right); - if (dlopen("libasound.so.2", RTLD_NOW | RTLD_GLOBAL) == NULL) { - g_message("Cannot load alsa library: %s", dlerror()); - /* FIXME, this plugin wont work... */ - } + bmp_cfg_db_get_bool(cfgfile, "ALSA", "debug", &alsa_cfg.debug); + bmp_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... */ + } }