diff --git a/audacious-plugins-1.5.1-0006-alsa-plugin-Fix-last-second-s-of-songs-getting-los.patch b/audacious-plugins-1.5.1-0006-alsa-plugin-Fix-last-second-s-of-songs-getting-los.patch deleted file mode 100644 index d176d73..0000000 --- a/audacious-plugins-1.5.1-0006-alsa-plugin-Fix-last-second-s-of-songs-getting-los.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 53306659a71bd4b49a560a7197f2fd0a7ba71ca0 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 8 May 2009 11:59:33 +0200 -Subject: [PATCH 6/9] alsa plugin: Fix last second(s) of songs getting lost - -There are 2 problems with the alsa plugin, which cause the end of a song -to get lost: -1) alsa_playing contains the following check: - get_thread_buffer_filled() > hw_period_size_in - This will cause alsa_playing to return 0 when there are still - frames left in the thread buffer, and once the input plugin then calls - alsa_close, these frames will get lost. - -2) alsa_close_pcm() calls snd_pcm_drop() which will cause all the frames - still in the buffers of the card to be dropped - -Fixing this: -1) Can be fixed by replacing the check with just: - get_thread_buffer_filled() - -2) However is harder to fix, one could replace snd_pcm_drop() with - snd_pcm_drain(), but this will cause delays when we want to - close immediately (stop/prev song/next song) - -After some fiddling I've come the conclusing that 2 is not really a problem, -the problem is that alsa_playing should return 1 as long as there is data -in either the thread buffer or in the hardware buffer of the card. - -For this to work we also need to change the: -get_thread_buffer_filled() > hw_period_size_in -check in alsa_loop with just get_thread_buffer_filled() - -Last this patch also removes the write max hw_period_size_in at a time -bytes check, if there is more then one period_size worth of data available -in the cards buffers its quite alright to write multiple periods at a time. ---- - src/alsa/audio.c | 13 +++++-------- - 1 files changed, 5 insertions(+), 8 deletions(-) - -diff --git a/src/alsa/audio.c b/src/alsa/audio.c -index 8dacdf2..80b92a5 100644 ---- a/src/alsa/audio.c -+++ b/src/alsa/audio.c -@@ -131,13 +131,11 @@ static void debug(char *str, ...) - - int alsa_playing(void) - { -- if (!going || paused || alsa_pcm == NULL) -+ if (!going || paused || prebuffer || 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; -+ return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING || -+ get_thread_buffer_filled(); - } - - static int -@@ -637,7 +635,7 @@ static void alsa_write_out_thread_data(void) - { - gint length, cnt, avail; - -- length = MIN(hw_period_size_in, get_thread_buffer_filled()); -+ length = get_thread_buffer_filled(); - avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail()); - length = MIN(length, avail); - while (length > 0) -@@ -667,8 +665,7 @@ static void *alsa_loop(void *arg) - { - if (get_thread_buffer_filled() > prebuffer_size) - prebuffer = FALSE; -- if (!paused && !prebuffer && -- get_thread_buffer_filled() > hw_period_size_in) -+ if (!paused && !prebuffer && get_thread_buffer_filled()) - { - wr = snd_pcm_wait(alsa_pcm, 10); - if (wr > 0) --- -1.6.2.2 - diff --git a/audacious-plugins-1.5.1-0007-Fix-alsa-plugin-locking.patch b/audacious-plugins-1.5.1-0007-Fix-alsa-plugin-locking.patch deleted file mode 100644 index 43db74d..0000000 --- a/audacious-plugins-1.5.1-0007-Fix-alsa-plugin-locking.patch +++ /dev/null @@ -1,232 +0,0 @@ -From 7910820018fd598e31b969510be407b6dc4fb127 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 11 May 2009 16:28:27 +0200 -Subject: [PATCH 7/9] Fix alsa plugin locking - -audacious sometimes hung after playing the first 3 secs of a song, -this patch fixes this. ---- - src/alsa/audio.c | 113 ++++++++++++++++++++++++++++++++++++------------------ - 1 files changed, 75 insertions(+), 38 deletions(-) - -diff --git a/src/alsa/audio.c b/src/alsa/audio.c -index 80b92a5..c50548b 100644 ---- a/src/alsa/audio.c -+++ b/src/alsa/audio.c -@@ -131,11 +131,19 @@ static void debug(char *str, ...) - - int alsa_playing(void) - { -+ int ret; -+ -+ g_static_mutex_lock(&alsa_mutex); -+ - if (!going || paused || prebuffer || alsa_pcm == NULL) -- return FALSE; -+ ret = FALSE; -+ else -+ ret = snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING || -+ get_thread_buffer_filled(); - -- return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING || -- get_thread_buffer_filled(); -+ g_static_mutex_unlock(&alsa_mutex); -+ -+ return ret; - } - - static int -@@ -215,6 +223,10 @@ static snd_pcm_sframes_t alsa_get_avail(void) - /* get the free space on buffer */ - int alsa_free(void) - { -+ int ret; -+ -+ g_static_mutex_lock(&alsa_mutex); -+ - if (remove_prebuffer && prebuffer) - { - prebuffer = FALSE; -@@ -223,7 +235,11 @@ int alsa_free(void) - if (prebuffer) - remove_prebuffer = TRUE; - -- return thread_buffer_size - get_thread_buffer_filled() - 1; -+ ret = thread_buffer_size - get_thread_buffer_filled() - 1; -+ -+ g_static_mutex_unlock(&alsa_mutex); -+ -+ return ret; - } - - /* do pause operation */ -@@ -276,8 +292,6 @@ void alsa_close(void) - - g_thread_join(audio_thread); - -- g_static_mutex_lock(&alsa_mutex); /* alsa_loop locks alsa_mutex! */ -- - alsa_cleanup_mixer(); - - g_free(inputf); -@@ -290,8 +304,6 @@ void alsa_close(void) - if (alsa_cfg.debug) - snd_output_close(logs); - debug("Device closed"); -- -- g_static_mutex_unlock(&alsa_mutex); - } - - /* reopen ALSA PCM */ -@@ -541,28 +553,46 @@ static int get_thread_buffer_filled(void) - - int alsa_get_output_time(void) - { -+ int ret; - snd_pcm_sframes_t delay; - guint64 bytes = alsa_hw_written; - -- if (!going || alsa_pcm == NULL) -- return 0; -+ g_static_mutex_lock(&alsa_mutex); - -- if (!snd_pcm_delay(alsa_pcm, &delay)) -+ if (going && alsa_pcm) - { -- unsigned int d = snd_pcm_frames_to_bytes(alsa_pcm, delay); -- if (bytes < d) -- bytes = 0; -- else -- bytes -= d; -+ 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; -+ } -+ ret = output_time_offset + (bytes * 1000) / outputf->bps; - } -- return output_time_offset + (bytes * 1000) / outputf->bps; -+ else -+ ret = 0; -+ -+ g_static_mutex_unlock(&alsa_mutex); -+ -+ return ret; - } - - int alsa_get_written_time(void) - { -- if (!going) -- return 0; -- return (alsa_total_written * 1000) / inputf->bps; -+ int ret; -+ -+ g_static_mutex_lock(&alsa_mutex); -+ -+ if (going) -+ ret = (alsa_total_written * 1000) / inputf->bps; -+ else -+ ret = 0; -+ -+ g_static_mutex_unlock(&alsa_mutex); -+ -+ return ret; - } - - /* transfer data to audio h/w; length is given in bytes -@@ -583,7 +613,9 @@ void alsa_write(gpointer data, int length) - { - int cnt; - char *src = (char *)data; -- -+ -+ g_static_mutex_lock(&alsa_mutex); -+ - remove_prebuffer = FALSE; - - alsa_total_written += length; -@@ -597,6 +629,7 @@ void alsa_write(gpointer data, int length) - length -= cnt; - src += cnt; - } -+ g_static_mutex_unlock(&alsa_mutex); - } - - /* transfer data to audio h/w via normal write */ -@@ -653,12 +686,17 @@ static void alsa_write_out_thread_data(void) - /* FIXME: proper lock? */ - static void *alsa_loop(void *arg) - { -- int npfds = snd_pcm_poll_descriptors_count(alsa_pcm); -- int wr = 0; -+ struct pollfd pfd[16]; -+ int npfds, err; - - g_static_mutex_lock(&alsa_mutex); - -- if (npfds <= 0) -+ npfds = snd_pcm_poll_descriptors_count(alsa_pcm); -+ if (npfds <= 0 || npfds > 16) -+ goto _error; -+ -+ err = snd_pcm_poll_descriptors(alsa_pcm, pfd, npfds); -+ if (err != npfds) - goto _error; - - while (going && alsa_pcm) -@@ -667,18 +705,21 @@ static void *alsa_loop(void *arg) - prebuffer = FALSE; - if (!paused && !prebuffer && get_thread_buffer_filled()) - { -- wr = snd_pcm_wait(alsa_pcm, 10); -- if (wr > 0) -- { -- alsa_write_out_thread_data(); -- } -- else if (wr < 0) -- { -- alsa_recovery(wr); -- } -+ g_static_mutex_unlock(&alsa_mutex); -+ err = poll(pfd, npfds, 10); -+ g_static_mutex_lock(&alsa_mutex); -+ -+ if (err < 0 && errno != EINTR) -+ goto _error; -+ -+ alsa_write_out_thread_data(); - } -- else /* XXX: why is this here? --nenolod */ -+ else -+ { -+ g_static_mutex_unlock(&alsa_mutex); - g_usleep(10000); -+ g_static_mutex_lock(&alsa_mutex); -+ } - - if (pause_request != paused) - alsa_do_pause(pause_request); -@@ -715,8 +756,6 @@ int alsa_open(AFormat fmt, int rate, int nch) - return 0; - } - -- g_static_mutex_lock(&alsa_mutex); -- - if (!mixer) - alsa_setup_mixer(); - -@@ -742,8 +781,6 @@ int alsa_open(AFormat fmt, int rate, int nch) - 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; - } --- -1.6.2.2 - diff --git a/audacious-plugins-1.5.1-0008-alsa-output-plugin-allow-usage-of-last-byte-of-thre.patch b/audacious-plugins-1.5.1-0008-alsa-output-plugin-allow-usage-of-last-byte-of-thre.patch deleted file mode 100644 index 22fdeaa..0000000 --- a/audacious-plugins-1.5.1-0008-alsa-output-plugin-allow-usage-of-last-byte-of-thre.patch +++ /dev/null @@ -1,86 +0,0 @@ -From a113a1fad60cbb0e7e1d30f434e759ecca0fa582 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 11 May 2009 16:38:58 +0200 -Subject: [PATCH 8/9] alsa output plugin: allow usage of last byte of thread buffer - -The code before this patch only allowed using 1 less byte then the -actual thread buffer size, as the fifo code had no way to distinguish -if rd_index == wr_index meant the fifo was full or empty. The old never -use the last byte solution was sub optimal, as the thread buffer size -normally is 2x the hardware buffer size, which is a power of 2, and reads are -being done from it a fragment at a time, which usually also are powers of 2. ---- - src/alsa/audio.c | 14 ++++++++++++-- - 1 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/src/alsa/audio.c b/src/alsa/audio.c -index c50548b..ca9c70d 100644 ---- a/src/alsa/audio.c -+++ b/src/alsa/audio.c -@@ -62,6 +62,7 @@ static gboolean alsa_can_pause; - 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 buffer_empty; /* is the buffer empty? */ - 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 */ -@@ -235,7 +236,7 @@ int alsa_free(void) - if (prebuffer) - remove_prebuffer = TRUE; - -- ret = thread_buffer_size - get_thread_buffer_filled() - 1; -+ ret = thread_buffer_size - get_thread_buffer_filled(); - - g_static_mutex_unlock(&alsa_mutex); - -@@ -332,6 +333,7 @@ static void alsa_do_flush(int time) - output_time_offset = time; - alsa_total_written = (guint64) time * inputf->bps / 1000; - rd_index = wr_index = alsa_hw_written = 0; -+ buffer_empty = 1; - } - - void alsa_flush(int time) -@@ -546,8 +548,12 @@ void alsa_set_volume(int l, int r) - /* return the size of audio data filled in the audio thread buffer */ - static int get_thread_buffer_filled(void) - { -- if (wr_index >= rd_index) -+ if (buffer_empty) -+ return 0; -+ -+ if (wr_index > rd_index) - return wr_index - rd_index; -+ - return thread_buffer_size - (rd_index - wr_index); - } - -@@ -626,6 +632,7 @@ void alsa_write(gpointer data, int length) - memcpy(thread_buffer + wr_index, src, cnt); - wr = (wr_index + cnt) % thread_buffer_size; - wr_index = wr; -+ buffer_empty = 0; - length -= cnt; - src += cnt; - } -@@ -678,6 +685,8 @@ static void alsa_write_out_thread_data(void) - alsa_do_write(thread_buffer + rd_index, cnt); - rd = (rd_index + cnt) % thread_buffer_size; - rd_index = rd; -+ if (rd_index == wr_index) -+ buffer_empty = 1; - length -= cnt; - } - } -@@ -778,6 +787,7 @@ int alsa_open(AFormat fmt, int rate, int nch) - thread_buffer_size -= thread_buffer_size % hw_period_size; - thread_buffer = g_malloc0(thread_buffer_size); - wr_index = rd_index = 0; -+ buffer_empty = 1; - pause_request = FALSE; - flush_request = -1; - --- -1.6.2.2 - diff --git a/audacious-plugins-1.5.1-0009-alsa-output-plugin-use-snd_pcm_recover.patch b/audacious-plugins-1.5.1-0009-alsa-output-plugin-use-snd_pcm_recover.patch deleted file mode 100644 index 982ad8a..0000000 --- a/audacious-plugins-1.5.1-0009-alsa-output-plugin-use-snd_pcm_recover.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 7b027ee36f0e7850820b1e9cc0214c69688c6917 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 11 May 2009 16:53:23 +0200 -Subject: [PATCH 9/9] alsa output plugin: use snd_pcm_recover() - -The alsa_recovery() function this patch removes does exactly the same as -the alsa-lib snd_pcm_recover() function, so use that instead. ---- - src/alsa/audio.c | 57 +---------------------------------------------------- - 1 files changed, 2 insertions(+), 55 deletions(-) - -diff --git a/src/alsa/audio.c b/src/alsa/audio.c -index ca9c70d..ed3af92 100644 ---- a/src/alsa/audio.c -+++ b/src/alsa/audio.c -@@ -147,59 +147,6 @@ int alsa_playing(void) - return ret; - } - --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) - { -@@ -210,7 +157,7 @@ static snd_pcm_sframes_t alsa_get_avail(void) - - while ((ret = snd_pcm_avail_update(alsa_pcm)) < 0) - { -- ret = alsa_recovery(ret); -+ ret = snd_pcm_recover(alsa_pcm, ret, !alsa_cfg.debug); - if (ret < 0) - { - g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s", -@@ -659,7 +606,7 @@ static void alsa_write_audio(char *data, int length) - } - else - { -- int err = alsa_recovery((int)written_frames); -+ int err = snd_pcm_recover(alsa_pcm, written_frames, !alsa_cfg.debug); - if (err < 0) - { - g_warning("alsa_write_audio(): write error: %s", --- -1.6.2.2 - diff --git a/audacious-plugins-1.5.1-alsa-ng.patch b/audacious-plugins-1.5.1-alsa-ng.patch new file mode 100644 index 0000000..5e711de --- /dev/null +++ b/audacious-plugins-1.5.1-alsa-ng.patch @@ -0,0 +1,3162 @@ +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. diff --git a/audacious-plugins.spec b/audacious-plugins.spec index 70b92e6..f2f6117 100644 --- a/audacious-plugins.spec +++ b/audacious-plugins.spec @@ -4,7 +4,7 @@ Name: audacious-plugins Version: 1.5.1 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Plugins for the Audacious media player Group: Applications/Multimedia @@ -27,12 +27,8 @@ Patch6: audacious-plugins-1.5.1-amidi-symbol.patch Patch7: audacious-plugins-1.5.1-neon-reader-error-crash.patch Patch8: audacious-plugins-1.5.1-sndfile-cleanup.patch -# ALSA driver bug-fixes originally for Audacious 2.0 series -# backported to legacy 1.5.1 (#499942) -Patch100: audacious-plugins-1.5.1-0006-alsa-plugin-Fix-last-second-s-of-songs-getting-los.patch -Patch101: audacious-plugins-1.5.1-0007-Fix-alsa-plugin-locking.patch -Patch102: audacious-plugins-1.5.1-0008-alsa-output-plugin-allow-usage-of-last-byte-of-thre.patch -Patch103: audacious-plugins-1.5.1-0009-alsa-output-plugin-use-snd_pcm_recover.patch +# alsa-ng plugin from 2.1 devel +Patch50: audacious-plugins-1.5.1-alsa-ng.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -177,10 +173,7 @@ vortex compressed files. # pause and seek for libsndfile input plugin %patch8 -p1 -b .sndfile-cleanup -%patch100 -p1 -b .alsa-499942-0006 -%patch101 -p1 -b .alsa-499942-0007 -%patch102 -p1 -b .alsa-499942-0008 -%patch103 -p1 -b .alsa-499942-0009 +%patch50 -p1 -b .alsa-ng sed -i '\,^.SILENT:,d' buildsys.mk.in @@ -275,6 +268,12 @@ update-desktop-database &> /dev/null || : %changelog +* Mon Jun 29 2009 Michael Schwendt - 1.5.1-8 +- Replace old ALSA output plugin and related patches with the + "alsa-ng" code from Audacious 2.1 development. This is supposed to + get rid of old cruft and mutex-locking overhead that cause performance + regression in 1.5.1-6. + * Fri Jun 5 2009 Michael Schwendt - 1.5.1-7 - Remove unapplied patches and verify that they have been merged. - Multiple different licenses are used for the individual plugins.