[alsa-devel] [PATCH] Add async support to ioplug

Takashi Iwai tiwai at suse.de
Tue May 20 13:10:35 CEST 2008


Hi,

the patch below adds a framework to support async on ioplug.  Now
an external ioplug plugin can implement appropriate async methods if
possible.

The async callback is just a copy of snd_pcm_async().  When sig >= 0,
activate the async, and with a negative value, deactivate async.

The test patch to alsa-plugins will follow.


Takashi

---
diff -r 8b22022a861d include/local.h
--- a/include/local.h	Fri May 09 16:02:02 2008 +0200
+++ b/include/local.h	Tue May 20 09:02:35 2008 +0200
@@ -149,7 +149,13 @@
 	void *private_data;
 	struct list_head glist;
 	struct list_head hlist;
+	int no_signal;
 };
+
+int _snd_async_add_handler(snd_async_handler_t **handler, int fd, 
+			   snd_async_callback_t callback,
+			   void *private_data, int no_signal);
+void _snd_async_call_handlers(int fd);
 
 typedef enum _snd_set_mode {
 	SND_CHANGE,
diff -r 8b22022a861d include/pcm_ioplug.h
--- a/include/pcm_ioplug.h	Fri May 09 16:02:02 2008 +0200
+++ b/include/pcm_ioplug.h	Tue May 20 09:02:35 2008 +0200
@@ -66,7 +66,7 @@
  */
 #define SND_PCM_IOPLUG_VERSION_MAJOR	1	/**< Protocol major version */
 #define SND_PCM_IOPLUG_VERSION_MINOR	0	/**< Protocol minor version */
-#define SND_PCM_IOPLUG_VERSION_TINY	1	/**< Protocol tiny version */
+#define SND_PCM_IOPLUG_VERSION_TINY	2	/**< Protocol tiny version */
 /**
  * IO-plugin protocol version
  */
@@ -114,6 +114,10 @@
 	unsigned int rate;		/**< rate; filled after hw_params is called */
 	snd_pcm_uframes_t period_size;	/**< period size; filled after hw_params is called */
 	snd_pcm_uframes_t buffer_size;	/**< buffer size; filled after hw_params is called */
+	/**
+	 * fields added by version 1.0.2
+	 */
+	unsigned int no_signal_async;	/**< async support without signal */
 };
 
 /** Callback table of ioplug */
@@ -189,6 +193,10 @@
 	 * get the delay for the running PCM; optional
 	 */
 	int (*delay)(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp);
+	/**
+	 * set up async handler; optional; added in version 1.0.2
+	 */
+	int (*async)(snd_pcm_ioplug_t *io, int sig, pid_t pid);
 };
 
 
@@ -212,6 +220,9 @@
 /* change PCM status */
 int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state);
 
+/* call async handlers */
+void snd_pcm_ioplug_call_async_handlers(snd_pcm_ioplug_t *ioplug);
+
 /** \} */
 
 #endif /* __ALSA_PCM_IOPLUG_H */
diff -r 8b22022a861d src/async.c
--- a/src/async.c	Fri May 09 16:02:02 2008 +0200
+++ b/src/async.c	Tue May 20 09:02:35 2008 +0200
@@ -48,19 +48,48 @@
 #endif
 
 static LIST_HEAD(snd_async_handlers);
+static int sig_count;
 
-static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED)
+#ifndef DOC_HIDDEN
+void _snd_async_call_handlers(int fd)
 {
-	int fd;
 	struct list_head *i;
-	//assert(siginfo->si_code == SI_SIGIO);
-	fd = siginfo->si_fd;
 	list_for_each(i, &snd_async_handlers) {
 		snd_async_handler_t *h = list_entry(i, snd_async_handler_t, glist);
 		if (h->fd == fd && h->callback)
 			h->callback(h);
 	}
 }
+#endif
+
+static void snd_async_handler(int signo ATTRIBUTE_UNUSED, siginfo_t *siginfo, void *context ATTRIBUTE_UNUSED)
+{
+	int fd;
+	//assert(siginfo->si_code == SI_SIGIO);
+	fd = siginfo->si_fd;
+	_snd_async_call_handlers(fd);
+}
+
+#ifndef DOC_HIDDEN
+int _snd_async_add_handler(snd_async_handler_t **handler, int fd, 
+			   snd_async_callback_t callback,
+			   void *private_data, int no_signal)
+{
+	snd_async_handler_t *h;
+	assert(handler);
+	h = malloc(sizeof(*h));
+	if (!h)
+		return -ENOMEM;
+	h->fd = fd;
+	h->callback = callback;
+	h->private_data = private_data;
+	list_add_tail(&h->glist, &snd_async_handlers);
+	INIT_LIST_HEAD(&h->hlist);
+	h->no_signal = no_signal;
+	*handler = h;
+	return 0;
+}
+#endif
 
 /**
  * \brief Registers an async handler.
@@ -94,20 +123,13 @@
 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 was_empty;
-	assert(handler);
-	h = malloc(sizeof(*h));
-	if (!h)
-		return -ENOMEM;
-	h->fd = fd;
-	h->callback = callback;
-	h->private_data = private_data;
-	was_empty = list_empty(&snd_async_handlers);
-	list_add_tail(&h->glist, &snd_async_handlers);
-	INIT_LIST_HEAD(&h->hlist);
-	*handler = h;
-	if (was_empty) {
+	int err;
+
+	err = _snd_async_add_handler(handler, fd, callback, private_data, 0);
+	if (err < 0)
+		return err;
+
+	if (!sig_count) {
 		int err;
 		struct sigaction act;
 		memset(&act, 0, sizeof(act));
@@ -116,10 +138,15 @@
 		sigemptyset(&act.sa_mask);
 		err = sigaction(snd_async_signo, &act, NULL);
 		if (err < 0) {
+			err = -errno;
 			SYSERR("sigaction");
-			return -errno;
+			list_del(&(*handler)->glist);
+			free(*handler);
+			*handler = NULL;
+			return err;
 		}
 	}
+	sig_count++;
 	return 0;
 }
 
@@ -133,15 +160,18 @@
 	int err = 0;
 	assert(handler);
 	list_del(&handler->glist);
-	if (list_empty(&snd_async_handlers)) {
-		struct sigaction act;
-		memset(&act, 0, sizeof(act));
-		act.sa_flags = 0;
-		act.sa_handler = SIG_DFL;
-		err = sigaction(snd_async_signo, &act, NULL);
-		if (err < 0) {
-			SYSERR("sigaction");
-			return -errno;
+	if (!handler->no_signal) {
+		sig_count--;
+		if (!sig_count) {
+			struct sigaction act;
+			memset(&act, 0, sizeof(act));
+			act.sa_flags = 0;
+			act.sa_handler = SIG_DFL;
+			err = sigaction(snd_async_signo, &act, NULL);
+			if (err < 0) {
+				SYSERR("sigaction");
+				/* return -errno; */
+			}
 		}
 	}
 	if (handler->type == SND_ASYNC_HANDLER_GENERIC)
diff -r 8b22022a861d src/pcm/pcm.c
--- a/src/pcm/pcm.c	Fri May 09 16:02:02 2008 +0200
+++ b/src/pcm/pcm.c	Tue May 20 09:02:36 2008 +0200
@@ -1984,8 +1984,10 @@
 	int err;
 	int was_empty;
 	snd_async_handler_t *h;
-	err = snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm),
-				    callback, private_data);
+
+	err = _snd_async_add_handler(&h, _snd_pcm_async_descriptor(pcm),
+				     callback, private_data,
+				     pcm->no_signal_async);
 	if (err < 0)
 		return err;
 	h->type = SND_ASYNC_HANDLER_PCM;
diff -r 8b22022a861d src/pcm/pcm_ioplug.c
--- a/src/pcm/pcm_ioplug.c	Fri May 09 16:02:02 2008 +0200
+++ b/src/pcm/pcm_ioplug.c	Tue May 20 09:02:36 2008 +0200
@@ -698,11 +698,15 @@
 	return 0;
 }
 
-static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
-				int sig ATTRIBUTE_UNUSED,
-				pid_t pid ATTRIBUTE_UNUSED)
+static int snd_pcm_ioplug_async(snd_pcm_t *pcm, int sig, pid_t pid)
 {
-	return -ENOSYS;
+	ioplug_priv_t *io = pcm->private_data;
+
+	if (io->data->version >= 0x010002 &&
+	    io->data->callback->async)
+		return io->data->callback->async(io->data, sig, pid);
+	else
+		return -ENOSYS;
 }
 
 static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
@@ -1037,6 +1041,9 @@
 	ioplug->pcm->poll_events = ioplug->poll_events;
 	ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0;
 	ioplug->pcm->mmap_rw = ioplug->mmap_rw;
+	if (ioplug->version >= 0x010002)
+		ioplug->pcm->no_signal_async = ioplug->no_signal_async;
+
 	return 0;
 }
 
@@ -1070,3 +1077,16 @@
 	ioplug->state = state;
 	return 0;
 }
+
+/**
+ * \brief Call the associated async handlers
+ * \param ioplug the ioplug handle
+ *
+ * Call the async handlers associated with the given ioplug.
+ * This function is usually called from the plugin's async handling
+ * routine appropriately.
+ */
+void snd_pcm_ioplug_call_async_handlers(snd_pcm_ioplug_t *ioplug)
+{
+	_snd_async_call_handlers(ioplug->poll_fd);
+}
diff -r 8b22022a861d src/pcm/pcm_local.h
--- a/src/pcm/pcm_local.h	Fri May 09 16:02:02 2008 +0200
+++ b/src/pcm/pcm_local.h	Tue May 20 09:02:36 2008 +0200
@@ -220,6 +220,7 @@
 					 * use the mmaped buffer of the slave
 					 */
 	unsigned int donot_close: 1;	/* don't close this PCM */
+	unsigned int no_signal_async :1; /* async without signal */
 	snd_pcm_channel_info_t *mmap_channels;
 	snd_pcm_channel_area_t *running_areas;
 	snd_pcm_channel_area_t *stopped_areas;


More information about the Alsa-devel mailing list