69b41650ad
SuSE! svn path=/nixpkgs/trunk/; revision=4607
1475 lines
39 KiB
Diff
1475 lines
39 KiB
Diff
diff -rc xmms-1.2.10-orig/Output/alsa/alsa.h xmms-1.2.10/Output/alsa/alsa.h
|
|
*** xmms-1.2.10-orig/Output/alsa/alsa.h 2004-01-11 17:27:26.000000000 +0100
|
|
--- xmms-1.2.10/Output/alsa/alsa.h 2006-01-27 00:28:49.000000000 +0100
|
|
***************
|
|
*** 50,57 ****
|
|
char *mixer_device;
|
|
int buffer_time;
|
|
int period_time;
|
|
gboolean debug;
|
|
- gboolean mmap;
|
|
struct
|
|
{
|
|
int left, right;
|
|
--- 50,57 ----
|
|
char *mixer_device;
|
|
int buffer_time;
|
|
int period_time;
|
|
+ int thread_buffer_time;
|
|
gboolean debug;
|
|
struct
|
|
{
|
|
int left, right;
|
|
***************
|
|
*** 65,72 ****
|
|
void alsa_about(void);
|
|
void alsa_configure(void);
|
|
int alsa_get_mixer(snd_mixer_t **mixer, int card);
|
|
- snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, char *name, int index);
|
|
- int alsa_setup_mixer(void);
|
|
void alsa_save_config(void);
|
|
|
|
void alsa_get_volume(int *l, int *r);
|
|
--- 65,70 ----
|
|
diff -rc xmms-1.2.10-orig/Output/alsa/audio.c xmms-1.2.10/Output/alsa/audio.c
|
|
*** xmms-1.2.10-orig/Output/alsa/audio.c 2004-01-28 00:09:39.000000000 +0100
|
|
--- xmms-1.2.10/Output/alsa/audio.c 2006-01-27 00:28:49.000000000 +0100
|
|
***************
|
|
*** 17,52 ****
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "alsa.h"
|
|
#include <ctype.h>
|
|
#include <libxmms/xconvert.h>
|
|
|
|
static snd_pcm_t *alsa_pcm = NULL;
|
|
- static snd_pcm_status_t *alsa_status = NULL;
|
|
- static snd_pcm_channel_area_t *areas = NULL;
|
|
|
|
static snd_output_t *logs = NULL;
|
|
|
|
! static int alsa_bps = 0;
|
|
! static guint64 alsa_total_written = 0;
|
|
|
|
/* Set/Get volume */
|
|
static snd_mixer_elem_t *pcm_element = NULL;
|
|
static snd_mixer_t *mixer = NULL;
|
|
|
|
! static gboolean mmap, force_start, going, paused;
|
|
|
|
! static gpointer buffer;
|
|
|
|
- static int alsa_can_pause;
|
|
|
|
struct snd_format {
|
|
unsigned int rate;
|
|
unsigned int channels;
|
|
snd_pcm_format_t format;
|
|
AFormat xmms_format;
|
|
};
|
|
|
|
static struct snd_format *inputf = NULL;
|
|
--- 17,72 ----
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
+ *
|
|
+ *
|
|
+ * CHANGES
|
|
+ *
|
|
+ * 2005.01.05 Takashi Iwai <tiwai@suse.de>
|
|
+ * Impelemented the multi-threaded mode with an audio-thread.
|
|
+ * Many fixes and cleanups.
|
|
*/
|
|
|
|
#include "alsa.h"
|
|
#include <ctype.h>
|
|
+ #include <pthread.h>
|
|
#include <libxmms/xconvert.h>
|
|
|
|
static snd_pcm_t *alsa_pcm = NULL;
|
|
|
|
static snd_output_t *logs = NULL;
|
|
|
|
! static guint64 alsa_total_written = 0; /* input bytes */
|
|
! static guint64 alsa_hw_written = 0; /* output bytes */
|
|
! static gint output_time_offset = 0;
|
|
!
|
|
! /* 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 = NULL;
|
|
static snd_mixer_t *mixer = NULL;
|
|
|
|
! static gboolean going, paused;
|
|
|
|
! static gboolean alsa_can_pause;
|
|
!
|
|
! /* for audio thread */
|
|
! static pthread_t audio_thread; /* audio loop thread */
|
|
! static int thread_buffer_size; /* size of intermediate buffer in bytes */
|
|
! static char *thread_buffer; /* audio intermediate buffer */
|
|
! static int rd_index, wr_index; /* current read/write position in int-buffer */
|
|
! static gboolean pause_request; /* pause status currently requested */
|
|
! static gint flush_request; /* flush status (time) currently requested */
|
|
|
|
|
|
struct snd_format {
|
|
unsigned int rate;
|
|
unsigned int channels;
|
|
snd_pcm_format_t format;
|
|
AFormat xmms_format;
|
|
+ int sample_bits;
|
|
+ int bps;
|
|
};
|
|
|
|
static struct snd_format *inputf = NULL;
|
|
***************
|
|
*** 54,61 ****
|
|
static struct snd_format *outputf = NULL;
|
|
|
|
static int alsa_setup(struct snd_format *f);
|
|
! static void alsa_mmap_audio(char *data, int length);
|
|
! static void alsa_write_audio(gpointer data, int length);
|
|
|
|
static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels);
|
|
|
|
--- 74,80 ----
|
|
static struct snd_format *outputf = NULL;
|
|
|
|
static int alsa_setup(struct snd_format *f);
|
|
! static void alsa_write_audio(char *data, int length);
|
|
|
|
static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels);
|
|
|
|
***************
|
|
*** 71,92 ****
|
|
} format_table[] =
|
|
{{FMT_S16_LE, SND_PCM_FORMAT_S16_LE},
|
|
{FMT_S16_BE, SND_PCM_FORMAT_S16_BE},
|
|
! {FMT_S16_NE,
|
|
! #ifdef WORDS_BIGENDIAN
|
|
! SND_PCM_FORMAT_S16_BE
|
|
! #else
|
|
! SND_PCM_FORMAT_S16_LE
|
|
! #endif
|
|
! },
|
|
{FMT_U16_LE, SND_PCM_FORMAT_U16_LE},
|
|
{FMT_U16_BE, SND_PCM_FORMAT_U16_BE},
|
|
! {FMT_U16_NE,
|
|
! #ifdef WORDS_BIGENDIAN
|
|
! SND_PCM_FORMAT_U16_BE
|
|
! #else
|
|
! SND_PCM_FORMAT_U16_LE
|
|
! #endif
|
|
! },
|
|
{FMT_U8, SND_PCM_FORMAT_U8},
|
|
{FMT_S8, SND_PCM_FORMAT_S8},
|
|
};
|
|
--- 90,99 ----
|
|
} format_table[] =
|
|
{{FMT_S16_LE, SND_PCM_FORMAT_S16_LE},
|
|
{FMT_S16_BE, SND_PCM_FORMAT_S16_BE},
|
|
! {FMT_S16_NE, SND_PCM_FORMAT_S16},
|
|
{FMT_U16_LE, SND_PCM_FORMAT_U16_LE},
|
|
{FMT_U16_BE, SND_PCM_FORMAT_U16_BE},
|
|
! {FMT_U16_NE, SND_PCM_FORMAT_U16},
|
|
{FMT_U8, SND_PCM_FORMAT_U8},
|
|
{FMT_S8, SND_PCM_FORMAT_S8},
|
|
};
|
|
***************
|
|
*** 106,281 ****
|
|
}
|
|
}
|
|
|
|
! int alsa_playing(void)
|
|
! {
|
|
! if (!going || paused)
|
|
! return FALSE;
|
|
!
|
|
! return(snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING);
|
|
! }
|
|
!
|
|
! static void xrun_recover(void)
|
|
! {
|
|
! int err;
|
|
!
|
|
! if (alsa_cfg.debug)
|
|
! {
|
|
! snd_pcm_status_alloca(&alsa_status);
|
|
! if ((err = 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);
|
|
! }
|
|
! }
|
|
!
|
|
! if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_XRUN)
|
|
! {
|
|
! if ((err = snd_pcm_prepare(alsa_pcm)) < 0)
|
|
! g_warning("xrun_recover(): snd_pcm_prepare() failed.");
|
|
! }
|
|
! }
|
|
!
|
|
! static snd_pcm_sframes_t alsa_get_avail(void)
|
|
! {
|
|
! snd_pcm_sframes_t ret;
|
|
! if ((ret = snd_pcm_avail_update(alsa_pcm)) == -EPIPE)
|
|
! xrun_recover();
|
|
! else if (ret < 0)
|
|
! {
|
|
! g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",
|
|
! snd_strerror(-ret));
|
|
! return 0;
|
|
! }
|
|
! else
|
|
! return ret;
|
|
! if ((ret = snd_pcm_avail_update(alsa_pcm)) < 0)
|
|
! {
|
|
! g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",
|
|
! snd_strerror(-ret));
|
|
! return 0;
|
|
! }
|
|
! return ret;
|
|
! }
|
|
!
|
|
! int alsa_free(void)
|
|
! {
|
|
! if (paused)
|
|
! return 0;
|
|
! else
|
|
! {
|
|
! int err;
|
|
! if (force_start &&
|
|
! snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED)
|
|
! {
|
|
! if ((err = snd_pcm_start(alsa_pcm)) < 0)
|
|
! g_warning("alsa_free(): snd_pcm_start() "
|
|
! "failed: %s", snd_strerror(-err));
|
|
! else
|
|
! debug("Stream started");
|
|
! }
|
|
! force_start = TRUE;
|
|
!
|
|
! return snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
|
|
! }
|
|
! }
|
|
!
|
|
! void alsa_pause(short p)
|
|
! {
|
|
! debug("alsa_pause");
|
|
! if (p)
|
|
! paused = TRUE;
|
|
!
|
|
! if (alsa_can_pause)
|
|
! snd_pcm_pause(alsa_pcm, p);
|
|
! else if (p)
|
|
! snd_pcm_drop(alsa_pcm);
|
|
!
|
|
! if (!p)
|
|
! paused = FALSE;
|
|
! }
|
|
!
|
|
! void alsa_close(void)
|
|
! {
|
|
! int err, started;
|
|
!
|
|
! debug("Closing device");
|
|
!
|
|
! started = going;
|
|
! going = 0;
|
|
!
|
|
! pcm_element = NULL;
|
|
!
|
|
! if (mixer)
|
|
! {
|
|
! snd_mixer_close(mixer);
|
|
! mixer = NULL;
|
|
! }
|
|
!
|
|
! if (alsa_pcm != NULL)
|
|
! {
|
|
! if (started)
|
|
! if ((err = snd_pcm_drop(alsa_pcm)) < 0)
|
|
! g_warning("alsa_pcm_drop() failed: %s",
|
|
! snd_strerror(-err));
|
|
!
|
|
! if ((err = snd_pcm_close(alsa_pcm)) < 0)
|
|
! g_warning("alsa_pcm_close() failed: %s",
|
|
! snd_strerror(-err));
|
|
! alsa_pcm = NULL;
|
|
! }
|
|
!
|
|
! if (mmap) {
|
|
! g_free(buffer);
|
|
! buffer = NULL;
|
|
!
|
|
! g_free(areas);
|
|
! areas = NULL;
|
|
! }
|
|
!
|
|
! xmms_convert_buffers_destroy(convertb);
|
|
! convertb = NULL;
|
|
! g_free(inputf);
|
|
! inputf = NULL;
|
|
! g_free(effectf);
|
|
! effectf = NULL;
|
|
!
|
|
! alsa_save_config();
|
|
!
|
|
! debug("Device closed");
|
|
! }
|
|
!
|
|
! static void alsa_reopen(struct snd_format *f)
|
|
! {
|
|
! unsigned int tmp = alsa_get_written_time();
|
|
!
|
|
! if (alsa_pcm != NULL)
|
|
! {
|
|
! snd_pcm_close(alsa_pcm);
|
|
! alsa_pcm = NULL;
|
|
! }
|
|
!
|
|
! if (mmap) {
|
|
! g_free(buffer);
|
|
! buffer = NULL;
|
|
!
|
|
! g_free(areas);
|
|
! areas = NULL;
|
|
! }
|
|
!
|
|
! if (alsa_setup(f) < 0)
|
|
! g_warning("Failed to reopen the audio device");
|
|
!
|
|
! alsa_total_written = tmp;
|
|
! snd_pcm_prepare(alsa_pcm);
|
|
! }
|
|
!
|
|
! void alsa_flush(int time)
|
|
! {
|
|
! alsa_total_written = (guint64) time * alsa_bps / 1000;
|
|
! }
|
|
!
|
|
static void parse_mixer_name(char *str, char **name, int *index)
|
|
{
|
|
char *end;
|
|
--- 113,121 ----
|
|
}
|
|
}
|
|
|
|
! /*
|
|
! * mixer stuff
|
|
! */
|
|
static void parse_mixer_name(char *str, char **name, int *index)
|
|
{
|
|
char *end;
|
|
***************
|
|
*** 337,343 ****
|
|
}
|
|
|
|
|
|
! 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;
|
|
--- 177,183 ----
|
|
}
|
|
|
|
|
|
! 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;
|
|
***************
|
|
*** 353,359 ****
|
|
return elem;
|
|
}
|
|
|
|
! int alsa_setup_mixer(void)
|
|
{
|
|
char *name;
|
|
long int a, b;
|
|
--- 193,199 ----
|
|
return elem;
|
|
}
|
|
|
|
! static int alsa_setup_mixer(void)
|
|
{
|
|
char *name;
|
|
long int a, b;
|
|
***************
|
|
*** 406,411 ****
|
|
--- 246,260 ----
|
|
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)
|
|
{
|
|
static gboolean first = TRUE;
|
|
***************
|
|
*** 461,485 ****
|
|
}
|
|
|
|
|
|
int alsa_get_output_time(void)
|
|
{
|
|
snd_pcm_sframes_t delay;
|
|
! ssize_t db = 0;
|
|
|
|
! if (!going)
|
|
return 0;
|
|
|
|
! if (!snd_pcm_delay(alsa_pcm, &delay))
|
|
! db = snd_pcm_frames_to_bytes(alsa_pcm, delay);
|
|
!
|
|
! if (db < alsa_total_written)
|
|
! return ((alsa_total_written - db) * 1000 / alsa_bps);
|
|
! return 0;
|
|
}
|
|
|
|
int alsa_get_written_time(void)
|
|
{
|
|
! return (alsa_total_written * 1000 / alsa_bps);
|
|
}
|
|
|
|
#define STEREO_ADJUST(type, type2, endian) \
|
|
--- 310,512 ----
|
|
}
|
|
|
|
|
|
+ /*
|
|
+ * audio stuff
|
|
+ */
|
|
+
|
|
+ int alsa_playing(void)
|
|
+ {
|
|
+ if (!going || paused || alsa_pcm == NULL)
|
|
+ return FALSE;
|
|
+
|
|
+ return(snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING);
|
|
+ }
|
|
+
|
|
+
|
|
+ /* handle generic errors */
|
|
+ static int alsa_handle_error(int err)
|
|
+ {
|
|
+ switch (err) {
|
|
+ case -EPIPE: /* XRUN */
|
|
+ if (alsa_cfg.debug) {
|
|
+ snd_pcm_status_t *alsa_status;
|
|
+ snd_pcm_status_alloca(&alsa_status);
|
|
+ if (snd_pcm_status(alsa_pcm, alsa_status) < 0)
|
|
+ g_warning("xrun_recover(): snd_pcm_status() failed");
|
|
+ else {
|
|
+ printf("Status:\n");
|
|
+ snd_pcm_status_dump(alsa_status, logs);
|
|
+ }
|
|
+ }
|
|
+ return snd_pcm_prepare(alsa_pcm);
|
|
+
|
|
+ case -ESTRPIPE: /* suspend */
|
|
+ while ((err = snd_pcm_resume(alsa_pcm)) == -EAGAIN)
|
|
+ sleep(1); /* wait until suspend flag is released */
|
|
+ if (err < 0) {
|
|
+ g_warning("suspend_recover(): snd_pcm_resume() failed.");
|
|
+ return snd_pcm_prepare(alsa_pcm);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ /* update and get the available space on h/w buffer (in frames) */
|
|
+ static snd_pcm_sframes_t alsa_get_avail(void)
|
|
+ {
|
|
+ snd_pcm_sframes_t ret;
|
|
+
|
|
+ if (alsa_pcm == NULL)
|
|
+ return 0;
|
|
+
|
|
+ while ((ret = snd_pcm_avail_update(alsa_pcm)) < 0) {
|
|
+ ret = alsa_handle_error(ret);
|
|
+ if (ret < 0) {
|
|
+ g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",
|
|
+ snd_strerror(-ret));
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* do pause operation */
|
|
+ static void alsa_do_pause(gboolean p)
|
|
+ {
|
|
+ if (paused == p)
|
|
+ return;
|
|
+
|
|
+ if (alsa_pcm) {
|
|
+ if (alsa_can_pause) {
|
|
+ snd_pcm_pause(alsa_pcm, p);
|
|
+ } else if (p) {
|
|
+ snd_pcm_drop(alsa_pcm);
|
|
+ snd_pcm_prepare(alsa_pcm);
|
|
+ }
|
|
+ }
|
|
+ paused = p;
|
|
+ }
|
|
+
|
|
+ void alsa_pause(short p)
|
|
+ {
|
|
+ debug("alsa_pause");
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* reopen ALSA PCM */
|
|
+ static int alsa_reopen(struct snd_format *f)
|
|
+ {
|
|
+ /* remember the current position */
|
|
+ output_time_offset += (alsa_hw_written * 1000) / outputf->bps;
|
|
+ alsa_hw_written = 0;
|
|
+
|
|
+ alsa_close_pcm();
|
|
+
|
|
+ return alsa_setup(f);
|
|
+ }
|
|
+
|
|
+ /* do flush (drop) operation */
|
|
+ static void alsa_do_flush(int time)
|
|
+ {
|
|
+ if (alsa_pcm) {
|
|
+ snd_pcm_drop(alsa_pcm);
|
|
+ snd_pcm_prepare(alsa_pcm);
|
|
+ }
|
|
+ /* correct the offset */
|
|
+ output_time_offset = time;
|
|
+ alsa_total_written = (guint64) time * inputf->bps / 1000;
|
|
+ rd_index = wr_index = alsa_hw_written = 0;
|
|
+ }
|
|
+
|
|
+ void alsa_flush(int time)
|
|
+ {
|
|
+ flush_request = time;
|
|
+ while (flush_request != -1)
|
|
+ xmms_usleep(10000);
|
|
+ }
|
|
+
|
|
+ void alsa_close(void)
|
|
+ {
|
|
+ if (! going)
|
|
+ return;
|
|
+
|
|
+ debug("Closing device");
|
|
+
|
|
+ going = 0;
|
|
+
|
|
+ pthread_join(audio_thread, NULL);
|
|
+
|
|
+ alsa_cleanup_mixer();
|
|
+
|
|
+ xmms_convert_buffers_destroy(convertb);
|
|
+ convertb = NULL;
|
|
+ g_free(inputf);
|
|
+ inputf = NULL;
|
|
+ g_free(effectf);
|
|
+ effectf = NULL;
|
|
+ g_free(outputf);
|
|
+ outputf = NULL;
|
|
+
|
|
+ alsa_save_config();
|
|
+
|
|
+ if (alsa_cfg.debug)
|
|
+ snd_output_close(logs);
|
|
+ debug("Device closed");
|
|
+ }
|
|
+
|
|
+ /* return the size of audio data filled in the audio thread buffer */
|
|
+ static int get_thread_buffer_filled(void)
|
|
+ {
|
|
+ int filled = wr_index - rd_index;
|
|
+ if (filled >= 0)
|
|
+ return filled;
|
|
+ return thread_buffer_size + filled;
|
|
+ }
|
|
+
|
|
+ /* get the free space on buffer */
|
|
+ int alsa_free(void)
|
|
+ {
|
|
+ return thread_buffer_size - get_thread_buffer_filled() - 1;
|
|
+ }
|
|
+
|
|
int alsa_get_output_time(void)
|
|
{
|
|
snd_pcm_sframes_t delay;
|
|
! guint64 bytes = 0;
|
|
|
|
! if (!going || alsa_pcm == NULL)
|
|
return 0;
|
|
|
|
! if (!snd_pcm_delay(alsa_pcm, &delay)) {
|
|
! bytes = snd_pcm_frames_to_bytes(alsa_pcm, delay);
|
|
! if (alsa_hw_written < bytes)
|
|
! bytes = 0;
|
|
! else
|
|
! bytes = alsa_hw_written - bytes;
|
|
! }
|
|
! return output_time_offset + (bytes * 1000) / outputf->bps;
|
|
}
|
|
|
|
int alsa_get_written_time(void)
|
|
{
|
|
! if (!going)
|
|
! return 0;
|
|
! return (alsa_total_written * 1000) / inputf->bps;
|
|
}
|
|
|
|
#define STEREO_ADJUST(type, type2, endian) \
|
|
***************
|
|
*** 584,636 ****
|
|
}
|
|
|
|
|
|
! void alsa_write(gpointer data, int length)
|
|
{
|
|
! EffectPlugin *ep;
|
|
|
|
if (paused)
|
|
return;
|
|
|
|
! force_start = FALSE;
|
|
!
|
|
! if (effects_enabled() && (ep = get_current_effect_plugin()))
|
|
! {
|
|
! int new_freq = inputf->rate;
|
|
! int new_chn = inputf->channels;
|
|
! AFormat f = inputf->xmms_format;
|
|
|
|
! if (ep->query_format)
|
|
! {
|
|
! ep->query_format(&f, &new_freq, &new_chn);
|
|
!
|
|
! if (f != effectf->xmms_format ||
|
|
! new_freq != effectf->rate ||
|
|
! new_chn != effectf->channels)
|
|
! {
|
|
! debug("Changing audio format for effect plugin");
|
|
!
|
|
! g_free(effectf);
|
|
! effectf = snd_format_from_xmms(f, new_freq,
|
|
! new_chn);
|
|
! alsa_reopen(effectf);
|
|
! }
|
|
!
|
|
! }
|
|
|
|
length = ep->mod_samples(&data, length,
|
|
inputf->xmms_format,
|
|
inputf->rate,
|
|
inputf->channels);
|
|
}
|
|
- else if (effectf)
|
|
- {
|
|
- g_free(effectf);
|
|
- effectf = NULL;
|
|
- effectf = snd_format_from_xmms(inputf->xmms_format,
|
|
- inputf->rate,
|
|
- inputf->channels);
|
|
- alsa_reopen(inputf);
|
|
- }
|
|
|
|
if (alsa_convert_func != NULL)
|
|
length = alsa_convert_func(convertb, &data, length);
|
|
--- 611,657 ----
|
|
}
|
|
|
|
|
|
! /* 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)
|
|
{
|
|
! EffectPlugin *ep = NULL;
|
|
! int new_freq;
|
|
! int new_chn;
|
|
! AFormat f;
|
|
|
|
if (paused)
|
|
return;
|
|
|
|
! new_freq = inputf->rate;
|
|
! new_chn = inputf->channels;
|
|
! f = inputf->xmms_format;
|
|
|
|
! if (effects_enabled() && (ep = get_current_effect_plugin()) &&
|
|
! ep->query_format)
|
|
! ep->query_format(&f, &new_freq, &new_chn);
|
|
|
|
+ if (f != effectf->xmms_format || new_freq != effectf->rate ||
|
|
+ new_chn != effectf->channels) {
|
|
+ debug("Changing audio format for effect plugin");
|
|
+ g_free(effectf);
|
|
+ effectf = snd_format_from_xmms(f, new_freq, new_chn);
|
|
+ if (alsa_reopen(effectf) < 0) {
|
|
+ /* fatal error... */
|
|
+ alsa_close();
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ep) {
|
|
length = ep->mod_samples(&data, length,
|
|
inputf->xmms_format,
|
|
inputf->rate,
|
|
inputf->channels);
|
|
}
|
|
|
|
if (alsa_convert_func != NULL)
|
|
length = alsa_convert_func(convertb, &data, length);
|
|
***************
|
|
*** 644,656 ****
|
|
if (alsa_cfg.soft_volume)
|
|
volume_adjust(data, length, outputf->xmms_format, outputf->channels);
|
|
|
|
! if (mmap)
|
|
! alsa_mmap_audio(data, length);
|
|
! else
|
|
! alsa_write_audio(data, length);
|
|
}
|
|
|
|
! static void alsa_write_audio(gpointer data, int length)
|
|
{
|
|
snd_pcm_sframes_t written_frames;
|
|
|
|
--- 665,693 ----
|
|
if (alsa_cfg.soft_volume)
|
|
volume_adjust(data, length, outputf->xmms_format, outputf->channels);
|
|
|
|
! alsa_write_audio(data, length);
|
|
}
|
|
|
|
! /* write callback */
|
|
! void alsa_write(gpointer data, int length)
|
|
! {
|
|
! int cnt;
|
|
! char *src = (char *)data;
|
|
!
|
|
! alsa_total_written += length;
|
|
! while (length > 0) {
|
|
! int wr;
|
|
! cnt = MIN(length, thread_buffer_size - wr_index);
|
|
! memcpy(thread_buffer + wr_index, src, cnt);
|
|
! wr = (wr_index + cnt) % thread_buffer_size;
|
|
! wr_index = wr;
|
|
! length -= cnt;
|
|
! src += cnt;
|
|
! }
|
|
! }
|
|
!
|
|
! /* transfer data to audio h/w via normal write */
|
|
! static void alsa_write_audio(char *data, int length)
|
|
{
|
|
snd_pcm_sframes_t written_frames;
|
|
|
|
***************
|
|
*** 663,735 ****
|
|
{
|
|
int written = snd_pcm_frames_to_bytes(alsa_pcm,
|
|
written_frames);
|
|
- alsa_total_written += written;
|
|
length -= written;
|
|
! data = (char*) data + written;
|
|
}
|
|
! else if (written_frames == -EPIPE)
|
|
! xrun_recover();
|
|
! else
|
|
! {
|
|
! g_warning("alsa_write_audio(): write error: %s",
|
|
! snd_strerror(-written_frames));
|
|
! break;
|
|
}
|
|
}
|
|
}
|
|
|
|
! static void alsa_mmap_audio(char *data, int length)
|
|
{
|
|
! int cnt = 0, err;
|
|
! snd_pcm_uframes_t offset, frames, frame;
|
|
! const snd_pcm_channel_area_t *chan_areas = areas;
|
|
! int channel_offset = 0, channel;
|
|
! ssize_t sample_size, offset_bytes, step;
|
|
!
|
|
! alsa_get_avail();
|
|
|
|
! while (length > 0)
|
|
! {
|
|
! frames = snd_pcm_bytes_to_frames(alsa_pcm, length);
|
|
! if ((err = snd_pcm_mmap_begin(alsa_pcm, &chan_areas, &offset, &frames) < 0))
|
|
! g_warning("alsa_mmap_audio(): snd_pcm_mmap_begin() "
|
|
! "failed: %s", snd_strerror(-err));
|
|
!
|
|
! cnt = snd_pcm_frames_to_bytes(alsa_pcm, frames);
|
|
!
|
|
! sample_size = snd_pcm_samples_to_bytes(alsa_pcm, 1);
|
|
! step = chan_areas[0].step / 8;
|
|
! offset_bytes = offset * step;
|
|
|
|
! for (frame = 0; frame < frames; frame++)
|
|
! {
|
|
! for (channel = 0; channel < outputf->channels; channel++)
|
|
! {
|
|
! char *ptr = chan_areas[channel].addr;
|
|
! memcpy(ptr + chan_areas[channel].first / 8 +
|
|
! offset_bytes,
|
|
! data + channel_offset, sample_size);
|
|
! channel_offset += sample_size;
|
|
}
|
|
! offset_bytes += step;
|
|
}
|
|
-
|
|
- err = snd_pcm_mmap_commit(alsa_pcm, offset, frames);
|
|
- if (err == -EPIPE)
|
|
- xrun_recover();
|
|
- else if (err < 0)
|
|
- g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit() "
|
|
- "failed: %s", snd_strerror(-err));
|
|
- else if (err != frames)
|
|
- g_warning("alsa_mmap_audio(): snd_pcm_mmap_commit "
|
|
- "returned %d, expected %d", err, (int)frames);
|
|
-
|
|
- alsa_total_written += cnt;
|
|
-
|
|
- length -= cnt;
|
|
}
|
|
}
|
|
|
|
int alsa_open(AFormat fmt, int rate, int nch)
|
|
{
|
|
debug("Opening device");
|
|
--- 700,785 ----
|
|
{
|
|
int written = snd_pcm_frames_to_bytes(alsa_pcm,
|
|
written_frames);
|
|
length -= written;
|
|
! data += written;
|
|
! alsa_hw_written += written;
|
|
}
|
|
! else {
|
|
! int err = alsa_handle_error((int)written_frames);
|
|
! if (err < 0) {
|
|
! g_warning("alsa_write_audio(): write error: %s",
|
|
! snd_strerror(-err));
|
|
! break;
|
|
! }
|
|
}
|
|
}
|
|
}
|
|
|
|
! /* transfer audio data from thread buffer to h/w */
|
|
! static void alsa_write_out_thread_data(void)
|
|
{
|
|
! gint length, cnt, avail;
|
|
|
|
! length = MIN(hw_period_size_in, get_thread_buffer_filled());
|
|
! avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
|
|
! length = MIN(length, avail);
|
|
! while (length > 0) {
|
|
! int rd;
|
|
! cnt = MIN(length, thread_buffer_size - rd_index);
|
|
! alsa_do_write(thread_buffer + rd_index, cnt);
|
|
! rd = (rd_index + cnt) % thread_buffer_size;
|
|
! rd_index = rd;
|
|
! length -= cnt;
|
|
! }
|
|
! }
|
|
|
|
! /* audio thread loop */
|
|
! /* FIXME: proper lock? */
|
|
! static void *alsa_loop(void *arg)
|
|
! {
|
|
! int npfds = snd_pcm_poll_descriptors_count(alsa_pcm);
|
|
! struct pollfd *pfds;
|
|
! unsigned short *revents;
|
|
!
|
|
! if (npfds <= 0)
|
|
! goto _error;
|
|
! pfds = alloca(sizeof(*pfds) * npfds);
|
|
! revents = alloca(sizeof(*revents) * npfds);
|
|
! while (going && alsa_pcm) {
|
|
! if (! paused && get_thread_buffer_filled() > hw_period_size_in) {
|
|
! snd_pcm_poll_descriptors(alsa_pcm, pfds, npfds);
|
|
! if (poll(pfds, npfds, 10) > 0) {
|
|
! /* need to check revents. poll() with dmix returns
|
|
! * a postive value even if no data is available
|
|
! */
|
|
! int i;
|
|
! snd_pcm_poll_descriptors_revents(alsa_pcm, pfds, npfds, revents);
|
|
! for (i = 0; i < npfds; i++)
|
|
! if (revents[i] & POLLOUT) {
|
|
! alsa_write_out_thread_data();
|
|
! break;
|
|
! }
|
|
}
|
|
! } else
|
|
! xmms_usleep(10000);
|
|
!
|
|
! if (pause_request != paused)
|
|
! alsa_do_pause(pause_request);
|
|
!
|
|
! if (flush_request != -1) {
|
|
! alsa_do_flush(flush_request);
|
|
! flush_request = -1;
|
|
}
|
|
}
|
|
+
|
|
+ _error:
|
|
+ alsa_close_pcm();
|
|
+ g_free(thread_buffer);
|
|
+ thread_buffer = NULL;
|
|
+ pthread_exit(NULL);
|
|
}
|
|
|
|
+ /* open callback */
|
|
int alsa_open(AFormat fmt, int rate, int nch)
|
|
{
|
|
debug("Opening device");
|
|
***************
|
|
*** 739,746 ****
|
|
if (alsa_cfg.debug)
|
|
snd_output_stdio_attach(&logs, stdout, 0);
|
|
|
|
- mmap = alsa_cfg.mmap;
|
|
-
|
|
if (alsa_setup(inputf) < 0)
|
|
{
|
|
alsa_close();
|
|
--- 789,794 ----
|
|
***************
|
|
*** 751,763 ****
|
|
|
|
convertb = xmms_convert_buffers_new();
|
|
|
|
! alsa_total_written = 0;
|
|
going = TRUE;
|
|
paused = FALSE;
|
|
- force_start = FALSE;
|
|
-
|
|
- snd_pcm_prepare(alsa_pcm);
|
|
|
|
return 1;
|
|
}
|
|
|
|
--- 799,823 ----
|
|
|
|
convertb = xmms_convert_buffers_new();
|
|
|
|
! output_time_offset = 0;
|
|
! alsa_total_written = alsa_hw_written = 0;
|
|
going = TRUE;
|
|
paused = FALSE;
|
|
|
|
+ thread_buffer_size = (guint64)alsa_cfg.thread_buffer_time * inputf->bps / 1000;
|
|
+ if (thread_buffer_size < hw_buffer_size)
|
|
+ thread_buffer_size = hw_buffer_size * 2;
|
|
+ if (thread_buffer_size < 8192)
|
|
+ thread_buffer_size = 8192;
|
|
+ thread_buffer_size += hw_buffer_size;
|
|
+ thread_buffer_size -= thread_buffer_size % hw_period_size;
|
|
+ thread_buffer = g_malloc0(thread_buffer_size);
|
|
+ wr_index = rd_index = 0;
|
|
+ pause_request = FALSE;
|
|
+ flush_request = -1;
|
|
+
|
|
+ pthread_create(&audio_thread, NULL, alsa_loop, NULL);
|
|
+
|
|
return 1;
|
|
}
|
|
|
|
***************
|
|
*** 787,792 ****
|
|
--- 847,854 ----
|
|
|
|
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;
|
|
}
|
|
***************
|
|
*** 806,812 ****
|
|
int err;
|
|
snd_pcm_hw_params_t *hwparams;
|
|
snd_pcm_sw_params_t *swparams;
|
|
! int alsa_buffer_time, bits_per_sample;
|
|
unsigned int alsa_period_time;
|
|
snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;
|
|
|
|
--- 868,874 ----
|
|
int err;
|
|
snd_pcm_hw_params_t *hwparams;
|
|
snd_pcm_sw_params_t *swparams;
|
|
! int alsa_buffer_time;
|
|
unsigned int alsa_period_time;
|
|
snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;
|
|
|
|
***************
|
|
*** 816,824 ****
|
|
alsa_stereo_convert_func = NULL;
|
|
alsa_frequency_convert_func = NULL;
|
|
|
|
! outputf = snd_format_from_xmms(effectf->xmms_format,
|
|
! effectf->rate,
|
|
! effectf->channels);
|
|
|
|
debug("Opening device: %s", alsa_cfg.pcm_device);
|
|
/* FIXME: Can snd_pcm_open() return EAGAIN? */
|
|
--- 878,885 ----
|
|
alsa_stereo_convert_func = NULL;
|
|
alsa_frequency_convert_func = NULL;
|
|
|
|
! g_free(outputf);
|
|
! outputf = snd_format_from_xmms(f->xmms_format, f->rate, f->channels);
|
|
|
|
debug("Opening device: %s", alsa_cfg.pcm_device);
|
|
/* FIXME: Can snd_pcm_open() return EAGAIN? */
|
|
***************
|
|
*** 829,838 ****
|
|
g_warning("alsa_setup(): Failed to open pcm device (%s): %s",
|
|
alsa_cfg.pcm_device, snd_strerror(-err));
|
|
alsa_pcm = NULL;
|
|
return -1;
|
|
}
|
|
- snd_pcm_nonblock(alsa_pcm, FALSE);
|
|
|
|
if (alsa_cfg.debug)
|
|
{
|
|
snd_pcm_info_t *info;
|
|
--- 890,903 ----
|
|
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;
|
|
***************
|
|
*** 856,872 ****
|
|
return -1;
|
|
}
|
|
|
|
! if (mmap &&
|
|
! (err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
|
|
! SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
|
|
! {
|
|
! g_message("alsa_setup(): Cannot set mmap'ed mode: %s. "
|
|
! "falling back to direct write", snd_strerror(-err));
|
|
! mmap = 0;
|
|
! }
|
|
!
|
|
! if (!mmap &&
|
|
! (err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
|
|
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
|
{
|
|
g_warning("alsa_setup(): Cannot set direct write mode: %s",
|
|
--- 921,927 ----
|
|
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",
|
|
***************
|
|
*** 894,910 ****
|
|
break;
|
|
}
|
|
}
|
|
! if (outputf->format != effectf->format)
|
|
{
|
|
outputf->xmms_format =
|
|
format_from_alsa(outputf->format);
|
|
debug("Converting format from %d to %d",
|
|
! effectf->xmms_format, outputf->xmms_format);
|
|
if (outputf->xmms_format < 0)
|
|
return -1;
|
|
alsa_convert_func =
|
|
xmms_convert_get_func(outputf->xmms_format,
|
|
! effectf->xmms_format);
|
|
if (alsa_convert_func == NULL)
|
|
return -1;
|
|
}
|
|
--- 949,965 ----
|
|
break;
|
|
}
|
|
}
|
|
! if (outputf->format != f->format)
|
|
{
|
|
outputf->xmms_format =
|
|
format_from_alsa(outputf->format);
|
|
debug("Converting format from %d to %d",
|
|
! f->xmms_format, outputf->xmms_format);
|
|
if (outputf->xmms_format < 0)
|
|
return -1;
|
|
alsa_convert_func =
|
|
xmms_convert_get_func(outputf->xmms_format,
|
|
! f->xmms_format);
|
|
if (alsa_convert_func == NULL)
|
|
return -1;
|
|
}
|
|
***************
|
|
*** 918,931 ****
|
|
}
|
|
|
|
snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &outputf->channels);
|
|
! if (outputf->channels != effectf->channels)
|
|
{
|
|
debug("Converting channels from %d to %d",
|
|
! effectf->channels, outputf->channels);
|
|
alsa_stereo_convert_func =
|
|
xmms_convert_get_channel_func(outputf->xmms_format,
|
|
outputf->channels,
|
|
! effectf->channels);
|
|
if (alsa_stereo_convert_func == NULL)
|
|
return -1;
|
|
}
|
|
--- 973,986 ----
|
|
}
|
|
|
|
snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &outputf->channels);
|
|
! if (outputf->channels != f->channels)
|
|
{
|
|
debug("Converting channels from %d to %d",
|
|
! f->channels, outputf->channels);
|
|
alsa_stereo_convert_func =
|
|
xmms_convert_get_channel_func(outputf->xmms_format,
|
|
outputf->channels,
|
|
! f->channels);
|
|
if (alsa_stereo_convert_func == NULL)
|
|
return -1;
|
|
}
|
|
***************
|
|
*** 936,945 ****
|
|
g_warning("alsa_setup(): No usable samplerate available.");
|
|
return -1;
|
|
}
|
|
! if (outputf->rate != effectf->rate)
|
|
{
|
|
debug("Converting samplerate from %d to %d",
|
|
! effectf->rate, outputf->rate);
|
|
alsa_frequency_convert_func =
|
|
xmms_convert_get_frequency_func(outputf->xmms_format,
|
|
outputf->channels);
|
|
--- 991,1000 ----
|
|
g_warning("alsa_setup(): No usable samplerate available.");
|
|
return -1;
|
|
}
|
|
! if (outputf->rate != f->rate)
|
|
{
|
|
debug("Converting samplerate from %d to %d",
|
|
! f->rate, outputf->rate);
|
|
alsa_frequency_convert_func =
|
|
xmms_convert_get_frequency_func(outputf->xmms_format,
|
|
outputf->channels);
|
|
***************
|
|
*** 947,960 ****
|
|
return -1;
|
|
}
|
|
|
|
! alsa_buffer_time = alsa_cfg.buffer_time * 1000;
|
|
! if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams,
|
|
! &alsa_buffer_time, 0)) < 0)
|
|
! {
|
|
! g_warning("alsa_setup(): Set buffer time failed: %s.",
|
|
! snd_strerror(-err));
|
|
! return -1;
|
|
! }
|
|
|
|
alsa_period_time = alsa_cfg.period_time * 1000;
|
|
if ((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams,
|
|
--- 1002,1009 ----
|
|
return -1;
|
|
}
|
|
|
|
! outputf->sample_bits = snd_pcm_format_physical_width(outputf->format);
|
|
! outputf->bps = (outputf->rate * outputf->sample_bits * outputf->channels) >> 3;
|
|
|
|
alsa_period_time = alsa_cfg.period_time * 1000;
|
|
if ((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams,
|
|
***************
|
|
*** 965,970 ****
|
|
--- 1014,1028 ----
|
|
return -1;
|
|
}
|
|
|
|
+ alsa_buffer_time = alsa_cfg.buffer_time * 1000;
|
|
+ if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams,
|
|
+ &alsa_buffer_time, 0)) < 0)
|
|
+ {
|
|
+ g_warning("alsa_setup(): Set buffer time failed: %s.",
|
|
+ snd_strerror(-err));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
if (snd_pcm_hw_params(alsa_pcm, hwparams) < 0)
|
|
{
|
|
if (alsa_cfg.debug)
|
|
***************
|
|
*** 1011,1037 ****
|
|
snd_pcm_dump(alsa_pcm, logs);
|
|
}
|
|
|
|
! bits_per_sample = snd_pcm_format_physical_width(outputf->format);
|
|
! alsa_bps = (outputf->rate * bits_per_sample * outputf->channels) >> 3;
|
|
!
|
|
! if (mmap)
|
|
! {
|
|
! int chn;
|
|
! buffer = g_malloc(alsa_period_size * bits_per_sample / 8 * outputf->channels);
|
|
! areas = g_malloc0(outputf->channels * sizeof(snd_pcm_channel_area_t));
|
|
!
|
|
! for (chn = 0; chn < outputf->channels; chn++)
|
|
! {
|
|
! areas[chn].addr = buffer;
|
|
! areas[chn].first = chn * bits_per_sample;
|
|
! areas[chn].step = outputf->channels * bits_per_sample;
|
|
! }
|
|
}
|
|
|
|
debug("Device setup: buffer time: %i, size: %i.", alsa_buffer_time,
|
|
! snd_pcm_frames_to_bytes(alsa_pcm, alsa_buffer_size));
|
|
debug("bits per sample: %i; frame size: %i; Bps: %i",
|
|
! bits_per_sample, snd_pcm_frames_to_bytes(alsa_pcm, 1), alsa_bps);
|
|
|
|
return 0;
|
|
}
|
|
--- 1069,1096 ----
|
|
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),
|
|
! snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps);
|
|
|
|
return 0;
|
|
}
|
|
diff -rc xmms-1.2.10-orig/Output/alsa/configure.c xmms-1.2.10/Output/alsa/configure.c
|
|
*** xmms-1.2.10-orig/Output/alsa/configure.c 2004-01-28 00:09:39.000000000 +0100
|
|
--- xmms-1.2.10/Output/alsa/configure.c 2006-01-27 00:28:49.000000000 +0100
|
|
***************
|
|
*** 20,27 ****
|
|
#include <stdio.h>
|
|
|
|
static GtkWidget *configure_win = NULL;
|
|
! static GtkWidget *buffer_time_spin, *period_time_spin;
|
|
! static GtkWidget *mmap_button, *mixer_card_spin, *softvolume_toggle_button;
|
|
|
|
static GtkWidget *devices_combo, *mixer_devices_combo;
|
|
|
|
--- 20,27 ----
|
|
#include <stdio.h>
|
|
|
|
static GtkWidget *configure_win = NULL;
|
|
! static GtkWidget *buffer_time_spin, *period_time_spin, *thread_buffer_time_spin;
|
|
! static GtkWidget *mixer_card_spin, *softvolume_toggle_button;
|
|
|
|
static GtkWidget *devices_combo, *mixer_devices_combo;
|
|
|
|
***************
|
|
*** 36,42 ****
|
|
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.mmap = GET_TOGGLE(mmap_button);
|
|
alsa_cfg.soft_volume = GET_TOGGLE(softvolume_toggle_button);
|
|
alsa_cfg.mixer_card = GET_SPIN_INT(mixer_card_spin);
|
|
alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
|
|
--- 36,42 ----
|
|
alsa_cfg.pcm_device = GET_CHARS(GTK_COMBO(devices_combo)->entry);
|
|
alsa_cfg.buffer_time = GET_SPIN_INT(buffer_time_spin);
|
|
alsa_cfg.period_time = GET_SPIN_INT(period_time_spin);
|
|
! alsa_cfg.thread_buffer_time = GET_SPIN_INT(thread_buffer_time_spin);
|
|
alsa_cfg.soft_volume = GET_TOGGLE(softvolume_toggle_button);
|
|
alsa_cfg.mixer_card = GET_SPIN_INT(mixer_card_spin);
|
|
alsa_cfg.mixer_device = GET_CHARS(GTK_COMBO(mixer_devices_combo)->entry);
|
|
***************
|
|
*** 51,57 ****
|
|
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "buffer_time", alsa_cfg.buffer_time);
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "period_time", alsa_cfg.period_time);
|
|
! xmms_cfg_write_boolean(cfgfile,"ALSA","mmap",alsa_cfg.mmap);
|
|
xmms_cfg_write_string(cfgfile,"ALSA","pcm_device", alsa_cfg.pcm_device);
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "mixer_card", alsa_cfg.mixer_card);
|
|
xmms_cfg_write_string(cfgfile,"ALSA","mixer_device", alsa_cfg.mixer_device);
|
|
--- 51,57 ----
|
|
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "buffer_time", alsa_cfg.buffer_time);
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "period_time", alsa_cfg.period_time);
|
|
! xmms_cfg_write_int(cfgfile, "ALSA", "thread_buffer_time", alsa_cfg.thread_buffer_time);
|
|
xmms_cfg_write_string(cfgfile,"ALSA","pcm_device", alsa_cfg.pcm_device);
|
|
xmms_cfg_write_int(cfgfile, "ALSA", "mixer_card", alsa_cfg.mixer_card);
|
|
xmms_cfg_write_string(cfgfile,"ALSA","mixer_device", alsa_cfg.mixer_device);
|
|
***************
|
|
*** 212,219 ****
|
|
GtkWidget *dev_vbox, *adevice_frame, *adevice_box;
|
|
GtkWidget *mixer_frame, *mixer_box, *mixer_card_box;
|
|
GtkWidget *buffer_frame, *buffer_vbox, *buffer_table;
|
|
! GtkWidget *buffer_time_label, *period_time_label;
|
|
! GtkObject *buffer_time_adj, *period_time_adj, *mixer_card_adj;
|
|
GtkWidget *bbox, *ok, *cancel;
|
|
|
|
if (configure_win)
|
|
--- 212,219 ----
|
|
GtkWidget *dev_vbox, *adevice_frame, *adevice_box;
|
|
GtkWidget *mixer_frame, *mixer_box, *mixer_card_box;
|
|
GtkWidget *buffer_frame, *buffer_vbox, *buffer_table;
|
|
! GtkWidget *buffer_time_label, *period_time_label, *thread_buffer_time_label;
|
|
! GtkObject *buffer_time_adj, *period_time_adj, *thread_buffer_time_adj, *mixer_card_adj;
|
|
GtkWidget *bbox, *ok, *cancel;
|
|
|
|
if (configure_win)
|
|
***************
|
|
*** 312,318 ****
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(buffer_vbox), 5);
|
|
|
|
! buffer_table = gtk_table_new(2, 2, FALSE);
|
|
gtk_table_set_row_spacings(GTK_TABLE(buffer_table), 5);
|
|
gtk_table_set_col_spacings(GTK_TABLE(buffer_table), 5);
|
|
gtk_box_pack_start(GTK_BOX(buffer_vbox), buffer_table, FALSE, FALSE, 0);
|
|
--- 312,318 ----
|
|
|
|
gtk_container_set_border_width(GTK_CONTAINER(buffer_vbox), 5);
|
|
|
|
! buffer_table = gtk_table_new(2, 3, FALSE);
|
|
gtk_table_set_row_spacings(GTK_TABLE(buffer_table), 5);
|
|
gtk_table_set_col_spacings(GTK_TABLE(buffer_table), 5);
|
|
gtk_box_pack_start(GTK_BOX(buffer_vbox), buffer_table, FALSE, FALSE, 0);
|
|
***************
|
|
*** 345,354 ****
|
|
gtk_table_attach(GTK_TABLE(buffer_table), period_time_spin,
|
|
1, 2, 1, 2, 0, 0, 0, 0);
|
|
|
|
! mmap_button = gtk_check_button_new_with_label(_("Mmap mode"));
|
|
! gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mmap_button),
|
|
! alsa_cfg.mmap);
|
|
! gtk_box_pack_start(GTK_BOX(buffer_vbox), mmap_button, FALSE, FALSE, 0);
|
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buffer_frame,
|
|
gtk_label_new(_("Advanced settings")));
|
|
--- 345,363 ----
|
|
gtk_table_attach(GTK_TABLE(buffer_table), period_time_spin,
|
|
1, 2, 1, 2, 0, 0, 0, 0);
|
|
|
|
! thread_buffer_time_label = gtk_label_new(_("Thread buffer time (ms):"));
|
|
! gtk_label_set_justify(GTK_LABEL(thread_buffer_time_label), GTK_JUSTIFY_LEFT);
|
|
! gtk_misc_set_alignment(GTK_MISC(thread_buffer_time_label), 0, 0.5);
|
|
! gtk_table_attach(GTK_TABLE(buffer_table), thread_buffer_time_label,
|
|
! 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
|
|
! thread_buffer_time_adj = gtk_adjustment_new(alsa_cfg.thread_buffer_time,
|
|
! 1000, 1000000, 100, 100, 100);
|
|
! thread_buffer_time_spin = gtk_spin_button_new(GTK_ADJUSTMENT(thread_buffer_time_adj),
|
|
! 8, 0);
|
|
!
|
|
! gtk_widget_set_usize(thread_buffer_time_spin, 60, -1);
|
|
! gtk_table_attach(GTK_TABLE(buffer_table), thread_buffer_time_spin,
|
|
! 1, 2, 2, 3, 0, 0, 0, 0);
|
|
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buffer_frame,
|
|
gtk_label_new(_("Advanced settings")));
|
|
diff -rc xmms-1.2.10-orig/Output/alsa/init.c xmms-1.2.10/Output/alsa/init.c
|
|
*** xmms-1.2.10-orig/Output/alsa/init.c 2004-01-11 17:27:26.000000000 +0100
|
|
--- xmms-1.2.10/Output/alsa/init.c 2006-01-27 00:28:49.000000000 +0100
|
|
***************
|
|
*** 29,36 ****
|
|
memset(&alsa_cfg, 0, sizeof (alsa_cfg));
|
|
alsa_cfg.buffer_time = 500;
|
|
alsa_cfg.period_time = 50;
|
|
alsa_cfg.debug = 0;
|
|
- alsa_cfg.mmap = 1;
|
|
alsa_cfg.vol.left = 100;
|
|
alsa_cfg.vol.right = 100;
|
|
|
|
--- 29,36 ----
|
|
memset(&alsa_cfg, 0, sizeof (alsa_cfg));
|
|
alsa_cfg.buffer_time = 500;
|
|
alsa_cfg.period_time = 50;
|
|
+ alsa_cfg.thread_buffer_time = 3000;
|
|
alsa_cfg.debug = 0;
|
|
alsa_cfg.vol.left = 100;
|
|
alsa_cfg.vol.right = 100;
|
|
|
|
***************
|
|
*** 44,51 ****
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "mixer_card", &alsa_cfg.mixer_card);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "buffer_time", &alsa_cfg.buffer_time);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "period_time", &alsa_cfg.period_time);
|
|
! xmms_cfg_read_boolean(cfgfile, "ALSA", "mmap", &alsa_cfg.mmap);
|
|
! xmms_cfg_read_int(cfgfile, "ALSA", "period_time", &alsa_cfg.period_time);
|
|
xmms_cfg_read_boolean(cfgfile, "ALSA", "soft_volume",
|
|
&alsa_cfg.soft_volume);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "volume_left", &alsa_cfg.vol.left);
|
|
--- 44,50 ----
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "mixer_card", &alsa_cfg.mixer_card);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "buffer_time", &alsa_cfg.buffer_time);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "period_time", &alsa_cfg.period_time);
|
|
! xmms_cfg_read_int(cfgfile, "ALSA", "thread_buffer_time", &alsa_cfg.thread_buffer_time);
|
|
xmms_cfg_read_boolean(cfgfile, "ALSA", "soft_volume",
|
|
&alsa_cfg.soft_volume);
|
|
xmms_cfg_read_int(cfgfile, "ALSA", "volume_left", &alsa_cfg.vol.left);
|