aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-07-05 16:14:44 +0200
committerTakashi Iwai <tiwai@suse.de>2007-07-05 16:14:44 +0200
commit13585db857b220173875baffae1f4847e3e484bb (patch)
treeae60c2313a593702f65d6c9bb4072ffb2d71b03c
parent6f5ad82ce51190e9782077343346a1d7641848e3 (diff)
downloadsalsa-lib-13585db857b220173875baffae1f4847e3e484bb.tar.gz
Add async handler support
-rw-r--r--configure.ac19
-rw-r--r--src/Makefile.am9
-rw-r--r--src/async.c135
-rw-r--r--src/control.c27
-rw-r--r--src/control.h6
-rw-r--r--src/ctl_macros.h15
-rw-r--r--src/global.h56
-rw-r--r--src/pcm.c26
-rw-r--r--src/pcm.h6
-rw-r--r--src/pcm_macros.h15
-rw-r--r--src/recipe.h.in3
11 files changed, 301 insertions, 16 deletions
diff --git a/configure.ac b/configure.ac
index d86b42b..40f8891 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,6 +37,10 @@ AC_SUBST(SND_LIB_EXTRAVER)
dnl Component selections
+AC_ARG_ENABLE(pcm,
+ AS_HELP_STRING([--disable-pcm],
+ [disable PCM interface]),
+ pcm="$enableval", pcm="yes")
AC_ARG_ENABLE(mixer,
AS_HELP_STRING([--disable-mixer],
[disable mixer interface]),
@@ -66,6 +70,10 @@ AC_ARG_ENABLE(tlv,
AS_HELP_STRING([--enable-tlv],
[enable TLV (dB) support]),
tlv="$enableval", tlv="no")
+AC_ARG_ENABLE(async,
+ AS_HELP_STRING([--enable-async],
+ [enable async handler support]),
+ async="$enableval", async="yes")
AC_ARG_ENABLE(libasound,
AS_HELP_STRING([--enable-libasound],
@@ -78,6 +86,7 @@ AC_ARG_ENABLE(everything,
everything="$enableval", everything="no")
if test "$everything" = "yes"; then
+ pcm="yes"
mixer="yes"
rawmidi="yes"
hwdep="yes"
@@ -85,15 +94,18 @@ if test "$everything" = "yes"; then
sndconf="yes"
sndseq="yes"
tlv="yes"
+ async="yes"
libasound="yes"
fi
+AM_CONDITIONAL(BUILD_PCM, test "$pcm" = "yes")
AM_CONDITIONAL(BUILD_MIXER, test "$mixer" = "yes")
AM_CONDITIONAL(BUILD_RAWMIDI, test "$rawmidi" = "yes")
AM_CONDITIONAL(BUILD_HWDEP, test "$hwdep" = "yes")
AM_CONDITIONAL(BUILD_TIMER, test "$timer" = "yes")
AM_CONDITIONAL(BUILD_CONF, test "$sndconf" = "yes")
AM_CONDITIONAL(BUILD_SEQ, test "$sndseq" = "yes")
+AM_CONDITIONAL(BUILD_ASYNC, test "$async" = "yes")
if test "$tlv" = "yes"; then
SALSA_HAS_TLV_SUPPORT=1
@@ -102,6 +114,13 @@ else
fi
AC_SUBST(SALSA_HAS_TLV_SUPPORT)
+if test "$async" = "yes"; then
+ SALSA_HAS_ASYNC_SUPPORT=1
+else
+ SALSA_HAS_ASYNC_SUPPORT=0
+fi
+AC_SUBST(SALSA_HAS_ASYNC_SUPPORT)
+
AM_CONDITIONAL(LINK_LIBASOUND, test "$libasound" = "yes")
dnl OK, let's output...
diff --git a/src/Makefile.am b/src/Makefile.am
index 9592aa3..6b4ec1a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,8 +1,13 @@
AM_CFLAGS = -Wall -g
lib_LTLIBRARIES = libsalsa.la
-libsalsa_la_SOURCES = control.c cards.c \
- pcm.c pcm_params.c pcm_misc.c
+libsalsa_la_SOURCES = control.c cards.c
+if BUILD_PCM
+libsalsa_la_SOURCES += pcm.c pcm_params.c pcm_misc.c
+endif
+if BUILD_ASYNC
+libsalsa_la_SOURCES += async.c
+endif
if BUILD_MIXER
libsalsa_la_SOURCES += hcontrol.c mixer.c
endif
diff --git a/src/async.c b/src/async.c
new file mode 100644
index 0000000..28a82b9
--- /dev/null
+++ b/src/async.c
@@ -0,0 +1,135 @@
+/*
+ * SALSA-Lib - Async handler helpers
+ *
+ * Copyright (c) 2007 by Takashi Iwai <tiwai@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#define __USE_GNU
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include "recipe.h"
+#include "global.h"
+
+
+static snd_async_handler_t *async_list;
+
+static int snd_set_async(snd_async_handler_t *h, int sig)
+{
+ long flags;
+ int err;
+
+ flags = fcntl(h->fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
+ if (sig >= 0)
+ flags |= O_ASYNC;
+ else
+ flags &= ~O_ASYNC;
+ if (fcntl(h->fd, F_SETFL, flags) < 0)
+ return -errno;
+ if (sig >= 0) {
+ if (fcntl(h->fd, F_SETSIG, (long)sig) < 0 ||
+ fcntl(h->fd, F_SETOWN, (long)getpid()) < 0) {
+ err = -errno;
+ fcntl(h->fd, F_SETFL, flags & ~O_ASYNC);
+ return err;
+ }
+ }
+ return 0;
+}
+
+static void snd_async_handler(int signo, siginfo_t *siginfo, void *context)
+{
+ snd_async_handler_t *h;
+ int fd = siginfo->si_fd;
+
+ for (h = async_list; h; h = h->next) {
+ if (h->fd == fd && h->callback)
+ h->callback(h);
+ }
+}
+
+int snd_async_add_handler(snd_async_handler_t **handler, int fd,
+ snd_async_callback_t callback, void *private_data)
+{
+ snd_async_handler_t *h;
+ int err;
+
+ h = calloc(1, sizeof(*h));
+ if (!h)
+ return -ENOMEM;
+ h->fd = fd;
+ h->callback = callback;
+ h->private_data = private_data;
+ h->next = async_list;
+ err = snd_set_async(h, SIGIO);
+ if (err < 0) {
+ free(h);
+ return err;
+ }
+ if (!async_list) {
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ act.sa_sigaction = snd_async_handler;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(SIGIO, &act, NULL) < 0) {
+ int err = -errno;
+ snd_set_async(h, -1);
+ free(h);
+ return err;
+ }
+ }
+ async_list = h;
+ *handler = h;
+ return 0;
+}
+
+int snd_async_del_handler(snd_async_handler_t *handler)
+{
+ snd_async_handler_t *h, *prev;
+
+ for (h = async_list, prev = NULL; h; prev = h, h = h->next) {
+ if (h == handler) {
+ if (prev)
+ prev->next = h->next;
+ else
+ async_list = h;
+ snd_set_async(h, -1);
+ if (h->pointer)
+ *h->pointer = NULL;
+ free(h);
+ break;
+ }
+ }
+
+ if (!async_list) {
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_flags = 0;
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGIO, &act, NULL);
+ }
+ return 0;
+}
diff --git a/src/control.c b/src/control.c
index 4e1ccba..ab2dddd 100644
--- a/src/control.c
+++ b/src/control.c
@@ -85,6 +85,10 @@ int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode)
int snd_ctl_close(snd_ctl_t *ctl)
{
+#if SALSA_HAS_ASYNC_SUPPORT
+ if (ctl->async)
+ snd_async_del_handler(ctl->async);
+#endif
close(ctl->fd);
free(ctl);
return 0;
@@ -315,3 +319,26 @@ const char *_snd_ctl_elem_iface_names[] = {
const char *_snd_ctl_event_type_names[] = {
EVENT(ELEM),
};
+
+
+#if SALSA_HAS_ASYNC_SUPPORT
+/*
+ * async helper
+ */
+int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl,
+ snd_async_callback_t callback,
+ void *private_data)
+{
+ int err;
+
+ if (ctl->async)
+ return -EBUSY;
+ err = snd_async_add_handler(&ctl->async, ctl->fd,
+ callback, private_data);
+ if (err < 0)
+ return err;
+ ctl->async->rec = ctl;
+ ctl->async->pointer = &ctl->async;
+ return 0;
+}
+#endif /* SALSA_HAS_ASYNC_SUPPORT */
diff --git a/src/control.h b/src/control.h
index 1176848..36e41ce 100644
--- a/src/control.h
+++ b/src/control.h
@@ -45,6 +45,12 @@ int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
const unsigned int *tlv);
#endif
+#if SALSA_HAS_ASYNC_SUPPORT
+int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl,
+ snd_async_callback_t callback,
+ void *private_data);
+#endif
+
#include "ctl_macros.h"
#define snd_ctl_elem_id_alloca(ptr) do { *ptr = alloca(snd_ctl_elem_id_sizeof()); memset(*ptr, 0, snd_ctl_elem_id_sizeof()); } while (0)
diff --git a/src/ctl_macros.h b/src/ctl_macros.h
index 1f0efd6..6c72bff 100644
--- a/src/ctl_macros.h
+++ b/src/ctl_macros.h
@@ -20,6 +20,9 @@ struct _snd_ctl {
int card;
int protocol;
struct pollfd pollfd;
+#if SALSA_HAS_ASYNC_SUPPORT
+ snd_async_handler_t *async;
+#endif
};
@@ -1187,6 +1190,16 @@ char *snd_device_name_get_hint(const void *hint, const char *id)
return NULL;
}
+#if SALSA_HAS_ASYNC_SUPPORT
+
+static inline
+snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler)
+{
+ return handler->rec;
+}
+
+#else
+
static inline __attribute__ ((deprecated))
int snd_async_add_ctl_handler(snd_async_handler_t **handler, snd_ctl_t *ctl,
snd_async_callback_t callback,
@@ -1201,4 +1214,6 @@ snd_ctl_t *snd_async_handler_get_ctl(snd_async_handler_t *handler)
return NULL;
}
+#endif /* SALSA_HAS_ASYNC_SUPPORT */
+
#endif /* __ALSA_CTL_MACROS_H */
diff --git a/src/global.h b/src/global.h
index 4a85af2..f33215f 100644
--- a/src/global.h
+++ b/src/global.h
@@ -23,20 +23,6 @@
#define __ALSA_GLOBAL_H
typedef struct _snd_config snd_config_t;
-typedef struct _snd_async_handler snd_async_handler_t;
-typedef void (*snd_async_callback_t)(snd_async_handler_t *handler);
-
-#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE)
-struct timeval {
- time_t tv_sec; /* seconds */
- long tv_usec; /* microseconds */
-};
-
-struct timespec {
- time_t tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
-};
-#endif
typedef struct timeval snd_timestamp_t;
typedef struct timespec snd_htimestamp_t;
@@ -56,6 +42,48 @@ typedef struct _snd_seq snd_seq_t;
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
+/* async helpers */
+typedef struct _snd_async_handler snd_async_handler_t;
+typedef void (*snd_async_callback_t)(snd_async_handler_t *handler);
+
+#if SALSA_HAS_ASYNC_SUPPORT
+
+struct _snd_async_handler {
+ int fd;
+ snd_async_callback_t callback;
+ void *private_data;
+ void *rec;
+ struct _snd_async_handler **pointer;
+ struct _snd_async_handler *next;
+};
+
+#define snd_async_handler_get_signo(h) SIGIO
+#define snd_async_handler_get_fd(h) (h)->fd
+#define snd_async_handler_get_callback_private(h) (h)->private_data
+int snd_async_add_handler(snd_async_handler_t **handler, int fd,
+ snd_async_callback_t callback, void *private_data);
+int snd_async_del_handler(snd_async_handler_t *handler);
+
+#else
+
+#define snd_async_handler_get_signo(h) -1
+#define snd_async_handler_get_fd(h) -1
+#define snd_async_handler_get_callback_private(h) NULL
+static inline __attribute__((deprecated))
+int snd_async_add_handler(snd_async_handler_t **handler, int fd,
+ snd_async_callback_t callback, void *private_data)
+{
+ return -ENXIO;
+}
+static inline __attribute__((deprecated))
+int snd_async_del_handler(snd_async_handler_t *handler)
+{
+ return -ENXIO;
+}
+
+#endif /* SALSA_HAS_ASYNC_SUPPORT */
+
+/* only for internal use */
int _snd_set_nonblock(int fd, int nonblock);
#endif /* __ALSA_GLOBAL_H */
diff --git a/src/pcm.c b/src/pcm.c
index 286ec90..603cd01 100644
--- a/src/pcm.c
+++ b/src/pcm.c
@@ -158,6 +158,10 @@ int snd_pcm_close(snd_pcm_t *pcm)
}
_snd_pcm_munmap(pcm);
snd_pcm_hw_munmap_status(pcm);
+#if SALSA_HAS_ASYNC_SUPPORT
+ if (pcm->async)
+ snd_async_del_handler(pcm->async);
+#endif
close(pcm->fd);
free(pcm);
return 0;
@@ -980,6 +984,28 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
}
+#if SALSA_HAS_ASYNC_SUPPORT
+/*
+ * async handler
+ */
+int snd_async_add_pcm_handler(snd_async_handler_t **handlerp, snd_pcm_t *pcm,
+ snd_async_callback_t callback,
+ void *private_data)
+{
+ int err;
+
+ if (pcm->async)
+ return -EBUSY;
+ err = snd_async_add_handler(&pcm->async, pcm->fd,
+ callback, private_data);
+ if (err < 0)
+ return err;
+ pcm->async->rec = pcm;
+ pcm->async->pointer = &pcm->async;
+ return 0;
+}
+#endif /* SALSA_HAS_ASYNC_SUPPORT */
+
/*
* HELPERS
*/
diff --git a/src/pcm.h b/src/pcm.h
index 0f1ac2c..6bada8a 100644
--- a/src/pcm.h
+++ b/src/pcm.h
@@ -104,6 +104,12 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_channels,
unsigned int channels, snd_pcm_uframes_t frames,
snd_pcm_format_t format);
+#if SALSA_HAS_ASYNC_SUPPORT
+int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm,
+ snd_async_callback_t callback,
+ void *private_data);
+#endif
+
#include "pcm_macros.h"
#define snd_pcm_info_alloca(ptr) do { *ptr = alloca(snd_pcm_info_sizeof()); memset(*ptr, 0, snd_pcm_info_sizeof()); } while (0)
diff --git a/src/pcm_macros.h b/src/pcm_macros.h
index 8c343bd..dbbbdcc 100644
--- a/src/pcm_macros.h
+++ b/src/pcm_macros.h
@@ -64,6 +64,9 @@ struct _snd_pcm {
snd_pcm_channel_info_t *mmap_channels;
snd_pcm_channel_area_t *running_areas;
+#if SALSA_HAS_ASYNC_SUPPORT
+ snd_async_handler_t *async;
+#endif
};
/*
@@ -2166,6 +2169,16 @@ snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs,
return -ENXIO;
}
+#if SALSA_HAS_ASYNC_SUPPORT
+
+static inline
+snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler)
+{
+ return handler->rec;
+}
+
+#else /* !SALSA_HAS_ASYNC_SUPPORT */
+
static inline __attribute__ ((deprecated))
int snd_async_add_pcm_handler(snd_async_handler_t **handler, snd_pcm_t *pcm,
snd_async_callback_t callback,
@@ -2180,4 +2193,6 @@ snd_pcm_t *snd_async_handler_get_pcm(snd_async_handler_t *handler)
return NULL;
}
+#endif /* SALSA_HAS_ASYNC_SUPPORT */
+
#endif /* __ALSA_PCM_MACROS_H */
diff --git a/src/recipe.h.in b/src/recipe.h.in
index f667aee..7de7393 100644
--- a/src/recipe.h.in
+++ b/src/recipe.h.in
@@ -4,4 +4,7 @@
/* Build with TLV support */
#define SALSA_HAS_TLV_SUPPORT @SALSA_HAS_TLV_SUPPORT@
+/* Build with async support */
+#define SALSA_HAS_ASYNC_SUPPORT @SALSA_HAS_ASYNC_SUPPORT@
+
#endif /* __ALSA_RECIPE_H */