]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm: direct: check state before enter poll on timer
authorAndreas Pape <apape@de.adit-jv.com>
Tue, 10 Jan 2017 06:33:54 +0000 (12:03 +0530)
committerTakashi Iwai <tiwai@suse.de>
Tue, 10 Jan 2017 08:24:16 +0000 (09:24 +0100)
To avoid the chances of timeout, we need to check the enter poll
in state xrun.

Signed-off-by: Andreas Pape <apape@de.adit-jv.com>
Signed-off-by: Mounesh Sutar <mounesh_sutar@mentor.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index a512dd20f1f77db9b84e2ba4b36a652505f4c6ed..f4d7c3f2f284aa403fb4ccbb9756e7fe7e8d0730 100644 (file)
@@ -645,6 +645,46 @@ int snd_pcm_direct_client_chk_xrun(snd_pcm_direct_t *direct, snd_pcm_t *pcm)
        return 0;
 }
 
+/*
+ * This is the only operation guaranteed to be called before entering poll().
+ * Direct plugins use fd of snd_timer to poll on, these timers do NOT check
+ * state of substream in kernel by intention.
+ * Only the enter to xrun might be notified once (SND_TIMER_EVENT_MSTOP).
+ * If xrun event was not correctly handled or was ignored it will never be
+ * evaluated again afterwards.
+ * This will result in snd_pcm_wait() always returning timeout.
+ * In contrast poll() on pcm hardware checks ALSA state and will immediately
+ * return POLLERR on XRUN.
+ *
+ * To prevent timeout and applications endlessly spinning without xrun
+ * detected we add a state check here which may trigger the xrun sequence.
+ *
+ * return count of filled descriptors or negative error code
+ */
+int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
+                                   unsigned int space)
+{
+       if (pcm->poll_fd < 0) {
+               SNDMSG("poll_fd < 0");
+               return -EIO;
+       }
+       if (space >= 1 && pfds) {
+               pfds->fd = pcm->poll_fd;
+               pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
+       } else {
+               return 0;
+       }
+
+       /* this will also evaluate slave state and enter xrun if necessary */
+       switch (snd_pcm_state(pcm)) {
+       case SND_PCM_STATE_XRUN:
+               return -EPIPE;
+       default:
+               break;
+       }
+       return 1;
+}
+
 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
 {
        snd_pcm_direct_t *dmix = pcm->private_data;
index d48f6b42243d20f5869c6ba315ba00254107e91a..66107ec07477a98a1eab159aa99283894be00781 100644 (file)
@@ -307,6 +307,8 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
                                  snd_config_t *cfg);
 int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
+int snd_pcm_direct_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds,
+                                   unsigned int space);
 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
 int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
index f72ee67b63396cf7fa12f9629903f3b9898736ad..666421081d7b4c1240bdfd889449bd9915323724 100644 (file)
@@ -462,17 +462,22 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
 {
        snd_pcm_direct_t *dmix = pcm->private_data;
+       int err;
        snd_pcm_state_t state;
        state = snd_pcm_state(dmix->spcm);
        switch (state) {
-       case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
        case SND_PCM_STATE_DISCONNECTED:
                dmix->state = state;
                return state;
+       case SND_PCM_STATE_XRUN:
+               if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
+                       return err;
+               break;
        default:
                break;
        }
+       snd_pcm_direct_client_chk_xrun(dmix, pcm);
        if (dmix->state == STATE_RUN_PENDING)
                return SNDRV_PCM_STATE_RUNNING;
        return dmix->state;
@@ -968,7 +973,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
        .avail_update = snd_pcm_dmix_avail_update,
        .mmap_commit = snd_pcm_dmix_mmap_commit,
        .htimestamp = snd_pcm_dmix_htimestamp,
-       .poll_descriptors = NULL,
+       .poll_descriptors = snd_pcm_direct_poll_descriptors,
        .poll_descriptors_count = NULL,
        .poll_revents = snd_pcm_dmix_poll_revents,
 };
index 0d800373e51d4e577fdcd28d587558bb9e88eac1..fdc95e3e617b681be043512efa76c7e9f3ef26f7 100644 (file)
@@ -255,17 +255,22 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
 {
        snd_pcm_direct_t *dshare = pcm->private_data;
+       int err;
        snd_pcm_state_t state;
        state = snd_pcm_state(dshare->spcm);
        switch (state) {
-       case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
        case SND_PCM_STATE_DISCONNECTED:
                dshare->state = state;
                return state;
+       case SND_PCM_STATE_XRUN:
+               if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
+                       return err;
+               break;
        default:
                break;
        }
+       snd_pcm_direct_client_chk_xrun(dshare, pcm);
        if (dshare->state == STATE_RUN_PENDING)
                return SNDRV_PCM_STATE_RUNNING;
        return dshare->state;
@@ -646,7 +651,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
        .avail_update = snd_pcm_dshare_avail_update,
        .mmap_commit = snd_pcm_dshare_mmap_commit,
        .htimestamp = snd_pcm_dshare_htimestamp,
-       .poll_descriptors = NULL,
+       .poll_descriptors = snd_pcm_direct_poll_descriptors,
        .poll_descriptors_count = NULL,
        .poll_revents = snd_pcm_direct_poll_revents,
 };
index 618d469ef56a0182c08db4e51c01a9da7381fce1..a14877176db582dbbadb93263bbe222c57176386 100644 (file)
@@ -208,17 +208,22 @@ static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
 {
        snd_pcm_direct_t *dsnoop = pcm->private_data;
+       int err;
        snd_pcm_state_t state;
        state = snd_pcm_state(dsnoop->spcm);
        switch (state) {
-       case SND_PCM_STATE_XRUN:
        case SND_PCM_STATE_SUSPENDED:
        case SND_PCM_STATE_DISCONNECTED:
                dsnoop->state = state;
                return state;
+       case SND_PCM_STATE_XRUN:
+               if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
+                       return err;
+               break;
        default:
                break;
        }
+       snd_pcm_direct_client_chk_xrun(dsnoop, pcm);
        return dsnoop->state;
 }
 
@@ -531,7 +536,7 @@ static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
        .avail_update = snd_pcm_dsnoop_avail_update,
        .mmap_commit = snd_pcm_dsnoop_mmap_commit,
        .htimestamp = snd_pcm_dsnoop_htimestamp,
-       .poll_descriptors = NULL,
+       .poll_descriptors = snd_pcm_direct_poll_descriptors,
        .poll_descriptors_count = NULL,
        .poll_revents = snd_pcm_direct_poll_revents,
 };