]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
alsa: Select on the alsa poll fd.
authorAndre Noll <maan@systemlinux.org>
Tue, 26 Jul 2011 18:51:24 +0000 (20:51 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 13 Aug 2011 10:40:30 +0000 (12:40 +0200)
This teaches the post_select method of the alsa writer to get a control
file descriptor from the alsa library via snd_pcm_poll_descriptors().
This file descriptor becomes readable when a buffer period has passed
and new samples can be written to the alsa handle. We add the fd to
the read fd set so that the select() call of the main scheduler loop
returns just in time.

This is more precise and simpler than the previous approach to compute
the time until a buffer underrun occurs.

alsa_write.c
error.h

index 5965159ed9e50af87401f4f2968d7155439bb568..047e88f2200a45f2518c7f1508874108e26a6bce 100644 (file)
@@ -52,6 +52,8 @@ struct private_alsa_write_data {
         */
        unsigned channels;
        struct timeval drain_barrier;
         */
        unsigned channels;
        struct timeval drain_barrier;
+       /* File descriptor for select(). */
+       int poll_fd;
 };
 
 static snd_pcm_format_t get_alsa_pcm_format(enum sample_format sf)
 };
 
 static snd_pcm_format_t get_alsa_pcm_format(enum sample_format sf)
@@ -143,11 +145,13 @@ static int alsa_init(struct private_alsa_write_data *pad,
 
 static void alsa_write_pre_select(struct sched *s, struct task *t)
 {
 
 static void alsa_write_pre_select(struct sched *s, struct task *t)
 {
+       struct pollfd pfd;
        struct writer_node *wn = container_of(t, struct writer_node, task);
        struct private_alsa_write_data *pad = wn->private_data;
        struct writer_node *wn = container_of(t, struct writer_node, task);
        struct private_alsa_write_data *pad = wn->private_data;
-       snd_pcm_sframes_t avail, underrun;
        int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
 
        int ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
 
+       if (pad)
+               pad->poll_fd = -1;
        if (ret == 0)
                return;
        if (!pad) {
        if (ret == 0)
                return;
        if (!pad) {
@@ -158,25 +162,14 @@ static void alsa_write_pre_select(struct sched *s, struct task *t)
                sched_request_barrier_or_min_delay(&pad->drain_barrier, s);
                return;
        }
                sched_request_barrier_or_min_delay(&pad->drain_barrier, s);
                return;
        }
-       /*
-        * Data is available to be written to the alsa handle.  Compute number
-        * of milliseconds until next buffer underrun would occur.
-        *
-        * snd_pcm_avail_update() updates the current available count of
-        * samples for writing.  It is a light method to obtain current stream
-        * position, because it does not require the user <-> kernel context
-        * switch, but the value is less accurate, because ring buffer pointers
-        * are updated in kernel drivers only when an interrupt occurs.
-        */
-       avail = snd_pcm_avail_update(pad->handle);
-       if (avail < 0)
-               avail = 0;
-       underrun = (pad->buffer_frames - avail) * pad->buffer_time
-               / pad->buffer_frames / 1000;
-       if (underrun < 50)
-               underrun = 50;
-       underrun -= 50;
-       sched_request_timeout_ms(underrun, s);
+       ret = snd_pcm_poll_descriptors(pad->handle, &pfd, 1);
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s\n", snd_strerror(-ret));
+               t->error = -E_ALSA_POLL_FDS;
+               return;
+       }
+       pad->poll_fd = pfd.fd;
+       para_fd_set(pfd.fd, &s->rfds, &s->max_fileno);
 }
 
 static void alsa_close(struct writer_node *wn)
 }
 
 static void alsa_close(struct writer_node *wn)
@@ -255,6 +248,8 @@ again:
                wn->min_iqs = pad->bytes_per_frame;
                goto again;
        }
                wn->min_iqs = pad->bytes_per_frame;
                goto again;
        }
+       if (pad->poll_fd >= 0 && !FD_ISSET(pad->poll_fd, &s->rfds))
+               return;
        frames = bytes / pad->bytes_per_frame;
        frames = snd_pcm_writei(pad->handle, data, frames);
        if (frames == 0 || frames == -EAGAIN)
        frames = bytes / pad->bytes_per_frame;
        frames = snd_pcm_writei(pad->handle, data, frames);
        if (frames == 0 || frames == -EAGAIN)
diff --git a/error.h b/error.h
index b8078770e5368c3840e0c6c91e3ff6267a7f7590..da0efc47f6ea317d8f026482a76d0c18dead58d6 100644 (file)
--- a/error.h
+++ b/error.h
@@ -441,6 +441,7 @@ extern const char **para_errlist[];
        PARA_ERROR(SET_RATE, "snd_pcm_hw_params_set_rate_near failed"), \
        PARA_ERROR(START_THRESHOLD, "snd_pcm_sw_params_set_start_threshold() failed"), \
        PARA_ERROR(STOP_THRESHOLD, "snd_pcm_sw_params_set_stop_threshold() failed"), \
        PARA_ERROR(SET_RATE, "snd_pcm_hw_params_set_rate_near failed"), \
        PARA_ERROR(START_THRESHOLD, "snd_pcm_sw_params_set_start_threshold() failed"), \
        PARA_ERROR(STOP_THRESHOLD, "snd_pcm_sw_params_set_stop_threshold() failed"), \
+       PARA_ERROR(ALSA_POLL_FDS, "could not get alsa poll fd"), \
 
 
 #define WRITE_COMMON_ERRORS \
 
 
 #define WRITE_COMMON_ERRORS \