# HG changeset patch # User William Pitcock # Date 1242353111 18000 # Node ID e387614b9be9ea579eaa2d425db4b27a3ecd5963 # Parent 6dd886b5c72b084738931554673193e71183e0c6 alsa-ng: Import rewritten ALSA plugin. This is still woefully incomplete, but supports basic playback. This driver uses the "safe" ALSA API subset, including use of blocking I/O. Right now, it is hardcoded to use "default". Do not complain about bugs in this plugin. diff -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/Makefile Thu May 14 21:05:11 2009 -0500 @@ -0,0 +1,14 @@ +PLUGIN = ALSA${PLUGIN_SUFFIX} + +SRCS = alsa-core.c \ + alsa-ringbuffer.c \ + alsa-util.c + +include ../../buildsys.mk +include ../../extra.mk + +plugindir := ${plugindir}/${OUTPUT_PLUGIN_DIR} + +CFLAGS += ${PLUGIN_CFLAGS} +CPPFLAGS += ${PLUGIN_CPPFLAGS} ${MOWGLI_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${ALSA_CFLAGS} -I../.. +LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${ALSA_LIBS} diff -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-core.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-core.c Thu May 14 21:05:11 2009 -0500 @@ -0,0 +1,250 @@ +/* + * 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" + +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 GMutex *pcm_mutex; +static GCond *pcm_cond; + +static gsize wr_total = 0; +static gsize wr_hwframes = 0; + +static gint flush_request; + +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) +{ + gchar buf[2048]; + + while (pcm_going) + { + if (flush_request != -1) + { + snd_pcm_drop(pcm_handle); + snd_pcm_prepare(pcm_handle); + wr_total = flush_request * (bps / 1000); + flush_request = -1; + } + + if (alsaplug_ringbuffer_read(&pcm_ringbuf, buf, 2048) == -1) + { + GTimeVal pcm_abs_time; + + g_get_current_time(&pcm_abs_time); + g_time_val_add(&pcm_abs_time, 10000); + + g_mutex_lock(pcm_mutex); + g_cond_timed_wait(pcm_cond, pcm_mutex, &pcm_abs_time); + g_mutex_unlock(pcm_mutex); + + continue; + } + + alsaplug_write_buffer(buf, 2048); + } + + snd_pcm_close(pcm_handle); + pcm_handle = NULL; + + return NULL; +} + +/******************************************************************************** + * Output Plugin API implementation. * + ********************************************************************************/ + +static OutputPluginInitStatus +alsaplug_init(void) +{ + gint card = -1; + + pcm_mutex = g_mutex_new(); + pcm_cond = g_cond_new(); + + if (snd_card_next(&card) != 0) + return OUTPUT_PLUGIN_INIT_NO_DEVICES; + + 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 ((err = snd_pcm_open(&pcm_handle, "default", 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; + alsaplug_ringbuffer_init(&pcm_ringbuf, ringbuf_size); + pcm_going = TRUE; + flush_request = -1; + + audio_thread = g_thread_create(alsaplug_loop, NULL, TRUE, NULL); + return 1; +} + +static void +alsaplug_close_audio(void) +{ + pcm_going = FALSE; + + g_thread_join(audio_thread); + + wr_total = 0; + wr_hwframes = 0; + bps = 0; +} + +static void +alsaplug_write_audio(gpointer data, gint length) +{ + wr_total += length; + alsaplug_ringbuffer_write(&pcm_ringbuf, data, length); +} + +static gint +alsaplug_output_time(void) +{ + snd_pcm_sframes_t delay; + gsize bytes = wr_total; + + if (pcm_going && pcm_handle != NULL) + { + if (!snd_pcm_delay(pcm_handle, &delay)) + { + guint d = snd_pcm_frames_to_bytes(pcm_handle, delay); + if (bytes < d) + bytes = 0; + else + bytes -= d; + } + + return (bytes * 1000) / bps; + } + + return 0; +} + +static gint +alsaplug_written_time(void) +{ + if (pcm_going) + return (wr_total * 1000) / bps; + + return 0; +} + +static gint +alsaplug_buffer_free(void) +{ + return alsaplug_ringbuffer_free(&pcm_ringbuf); +} + +static void +alsaplug_flush(gint time) +{ + flush_request = time; + while (flush_request != -1 && pcm_going) + g_usleep(10000); +} + +static gint +alsaplug_buffer_playing(void) +{ + return pcm_going; +} + +/******************************************************************************** + * 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, +}; + +OutputPlugin *alsa_oplist[] = { &alsa_op, NULL }; +SIMPLE_OUTPUT_PLUGIN(alsa, alsa_oplist); diff -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-debug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-debug.h Thu May 14 21:05:11 2009 -0500 @@ -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 -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-ringbuffer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-ringbuffer.c Thu May 14 21:05:11 2009 -0500 @@ -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 -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-ringbuffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-ringbuffer.h Thu May 14 21:05:11 2009 -0500 @@ -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 -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-stdinc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-stdinc.h Thu May 14 21:05:11 2009 -0500 @@ -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 -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-types.h Thu May 14 21:05:11 2009 -0500 @@ -0,0 +1,32 @@ +/* + * 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); + +#endif diff -r 6dd886b5c72b -r e387614b9be9 src/alsa-ng/alsa-util.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alsa-ng/alsa-util.c Thu May 14 21:05:11 2009 -0500 @@ -0,0 +1,51 @@ +/* + * 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_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; +}