All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: "Wischer, Timo (ADITG/ESB)" <twischer@de.adit-jv.com>
Cc: "alsa-devel@alsa-project.org" <alsa-devel@alsa-project.org>
Subject: Re: [PATCH - IOPLUG DRAIN 0/2]
Date: Fri, 23 Mar 2018 10:03:42 +0100	[thread overview]
Message-ID: <s5hr2ob9n9t.wl-tiwai@suse.de> (raw)
In-Reply-To: <s5htvt79ptg.wl-tiwai@suse.de>

On Fri, 23 Mar 2018 09:08:43 +0100,
Takashi Iwai wrote:
> 
> On Fri, 23 Mar 2018 09:01:35 +0100,
> Takashi Iwai wrote:
> > 
> > On Fri, 23 Mar 2018 08:43:10 +0100,
> > Wischer, Timo (ADITG/ESB) wrote:
> > > 
> > > > No, again, in non-blocking mode, the drain callback will get never
> > > > called.  It's the responsibility of application to sync with poll()
> > > > instead.
> > > 
> > > Sorry but I do not get it anyway.
> > > 
> > > The user application which is playing some audio has to do the following to drain in nonblocking mode, right?
> > > snd_pcm_poll_descriptors(pfds)
> > > while (snd_pcm_drain() == -EAGAIN) {
> > > poll(pfds)
> > > }
> > > 
> > > 
> > > But in nonblocking mode the drain callback of the IO plugin will never be called with your solution.
> > > Therefore in case of the pulse IO plugin which function should call pa_stream_drain()?
> > > The user application will not do it directly and poll can also not call it.
> > 
> > OK, now I understand your concern.  Yes it's another missing piece,
> > snd_pcm_ioplug_hw_ptr_update() needs to check the current state, and
> > it drops to SETUP state instead of XRUN when it was DRAINING.
> > Then application can simply do poll() and status update until it goes
> > out of DRAINING state.
> > 
> > But still it's outside the plugin, drain callback isn't called there.
> 
> .... and now thinking of this again, the whole story can be folded
> back:
> 
> - The standard drain behavior can be implemented without plugin's own
>   code; it's just a poll and status check.
> 
> - For any special case (or better implementation than poll()), we may
>   leave the whole draining callback action to each plugin; that's the
>   case of PA.

Maybe it's easier to understand by a patch.  Totally untested, but you
get the idea from it.

The check in snd_pcm_ioplug_hw_ptr_update() can be extended to the
XRUN check, too.  But do it in another patch.

And, yeah, this still misses the proper non-blocking mode handling in
pulse plugin.  It's to be fixed there.


Takashi

-- 8< --
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -47,6 +47,11 @@ typedef struct snd_pcm_ioplug_priv {
 	snd_htimestamp_t trigger_tstamp;
 } ioplug_priv_t;
 
+static int snd_pcm_ioplug_drop(snd_pcm_t *pcm);
+static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm);
+static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
+static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+
 /* update the hw pointer */
 /* called in lock */
 static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
@@ -57,6 +62,7 @@ static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
 	hw = io->data->callback->pointer(io->data);
 	if (hw >= 0) {
 		snd_pcm_uframes_t delta;
+		snd_pcm_uframes_t avail;
 
 		if ((snd_pcm_uframes_t)hw >= io->last_hw)
 			delta = hw - io->last_hw;
@@ -67,6 +73,12 @@ static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
 			delta = wrap_point + hw - io->last_hw;
 		}
 		snd_pcm_mmap_hw_forward(io->data->pcm, delta);
+		/* stop the stream if all samples are drained */
+		if (io->data->state == SND_PCM_STATE_DRAINING) {
+			avail = snd_pcm_mmap_avail(pcm);
+			if (avail >= pcm->buffer_size)
+				snd_pcm_ioplug_drop(pcm);
+		}
 		io->last_hw = (snd_pcm_uframes_t)hw;
 	} else
 		io->data->state = SNDRV_PCM_STATE_XRUN;
@@ -488,20 +500,66 @@ static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
 	return 0;
 }
 
+static int ioplug_drain_via_poll(snd_pcm_t *pcm)
+{
+	ioplug_priv_t *io = pcm->private_data;
+	int err;
+
+	/* in non-blocking mode, leave application to poll() by itself */
+	if (io->data->nonblock)
+		return -EAGAIN;
+
+	while (io->data->state == SND_PCM_STATE_DRAINING) {
+		err = snd_pcm_wait_nocheck(pcm, -1);
+		snd_pcm_ioplug_hw_ptr_update(pcm);
+		if (err < 0)
+			break;
+	}
+
+	return 0;
+}
+
 /* need own locking */
 static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
 {
 	ioplug_priv_t *io = pcm->private_data;
 	int err;
 
-	if (io->data->state == SND_PCM_STATE_OPEN)
+	snd_pcm_lock(pcm);
+	switch (io->data->state) {
+	case SND_PCM_STATE_OPEN:
+	case SND_PCM_STATE_DISCONNECTED:
+	case SND_PCM_STATE_SUSPENDED:
 		return -EBADFD;
+	case SND_PCM_STATE_PREPARED:
+		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+			err = snd_pcm_ioplug_start(pcm);
+			if (err < 0)
+				goto unlock;
+			io->data->state = SND_PCM_STATE_DRAINING;
+		}
+		break;
+	case SND_PCM_STATE_RUNNING:
+		io->data->state = SND_PCM_STATE_DRAINING;
+		break;
+	}
 
-	io->data->state = SND_PCM_STATE_DRAINING;
-	if (io->data->callback->drain)
-		io->data->callback->drain(io->data);
-	snd_pcm_lock(pcm);
-	err = snd_pcm_ioplug_drop(pcm);
+	if (io->data->state == SND_PCM_STATE_DRAINING) {
+		if (io->data->callback->drain) {
+			snd_pcm_unlock(pcm); /* let plugin own locking */
+			err = io->data->callback->drain(io->data);
+			snd_pcm_lock(pcm);
+		} else {
+			err = ioplug_drain_via_poll(pcm);
+		}
+		if (err < 0)
+			goto unlock;
+	}
+
+	if (io->data->state != SND_PCM_STATE_SETUP)
+		err = snd_pcm_ioplug_drop(pcm);
+
+ unlock:
 	snd_pcm_unlock(pcm);
 	return err;
 }

  reply	other threads:[~2018-03-23  9:03 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-22 13:48 [PATCH - IOPLUG DRAIN 0/2] twischer
2018-03-22 13:48 ` [PATCH - IOPLUG DRAIN 1/1] ioplug: drain: Wait with pollwhen EAGAIN in blocking mode twischer
2018-03-22 13:48 ` [PATCH - IOPLUG DRAIN 1/1] jack: Support snd_pcm_drain() twischer
2018-03-22 14:28 ` [PATCH - IOPLUG DRAIN 0/2] Takashi Iwai
2018-03-22 14:50   ` Wischer, Timo (ADITG/ESB)
2018-03-22 14:55     ` Takashi Iwai
2018-03-22 15:17       ` Wischer, Timo (ADITG/ESB)
2018-03-22 16:22         ` Takashi Iwai
2018-03-23  7:23           ` Wischer, Timo (ADITG/ESB)
2018-03-23  7:28             ` Takashi Iwai
2018-03-23  7:43               ` Wischer, Timo (ADITG/ESB)
2018-03-23  8:01                 ` Takashi Iwai
2018-03-23  8:08                   ` Takashi Iwai
2018-03-23  9:03                     ` Takashi Iwai [this message]
2018-03-28  8:42                       ` Wischer, Timo (ADITG/ESB)
2018-03-28 16:09                         ` Takashi Iwai
2018-03-29  6:39                           ` Wischer, Timo (ADITG/ESB)
2018-03-29  7:25                             ` Takashi Iwai
2018-03-29  7:38                               ` Wischer, Timo (ADITG/ESB)
2018-03-23  8:21                   ` Wischer, Timo (ADITG/ESB)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=s5hr2ob9n9t.wl-tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@alsa-project.org \
    --cc=twischer@de.adit-jv.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.