From: Takashi Iwai <tiwai@suse.de>
To: Carl Hetherington <lists@carlh.net>
Cc: alsa-devel@alsa-project.org
Subject: Re: Query about xrun on usb/pcm
Date: Tue, 29 Nov 2022 08:45:14 +0100 [thread overview]
Message-ID: <87fse2qk51.wl-tiwai@suse.de> (raw)
In-Reply-To: <baa6589-184f-6751-71be-1d5d67f8a6d5@carlh.net>
On Mon, 28 Nov 2022 23:51:55 +0100,
Carl Hetherington wrote:
>
> Hi Takashi,
>
> Thank you for your continued attention with this!
>
> [snip]
>
> > > I'll see if can apply a similar fix to this case, though to my naive
> > > eyes it looks a little trickier as the xrun is found in the snd_pcm
> > > code rather than the USB code. Any suggestions most welcome!
> >
> > OK, then it's a bit different problem, and not so trivial to fix in
> > the kernel side alone, I'm afraid. Basically it's a race between
> > start and stop of two streams. The key point is that, for stopping a
> > (USB) stream, a sync-stop operation is needed, and this can't be
> > performed at the PCM trigger itself (which is an atomic operation).
> > So, the kernel trigger may at most return an error there.
> >
> > I assume that it's from snd_usb_endpoint_start() and it returning
> > -EPIPE error. If so, we may change the PCM core code to set the PCM
> > state again XRUN in such an error case, so that application may repeat
> > the standard recovery process. Something like below.
>
> Thanks for the suggestion. I experimented a little with this, but I
> think the problem I'm seeing is that (even if the application knows it
> should retry the snd_pcm_prepare() step) we still end up with an endpoint
> in EP_STATE_STOPPING while the corresponding stop_operating flag is 0.
Ah, I guess that's a fallout in the logic. When XRUN happens at start
-- receiving an -EPIPE error at snd_pcm_do_start() -- then the patch
sets the XRUN state. This assumed that the stream gets stopped the
following snd_pcm_undo_start() call. Indeed it does stop but there we
forgot setting stop_operating flag unlike what snd_pcm_stop() does.
> This means that snd_pcm_sync_stop will never call the USB sync_stop
> handler, which AFAICS is the only way (?) the endpoint can get back to
> EP_STATE_STOPPED.
>
> In my error case, the code in snd_pcm_sync_stop sets stop_operating to
> false (perhaps assuming that substream->ops->sync_stop will "succeed"
> in setting any STOPPING endpoints to STOPPED) but then this doesn't
> happen because of this xrun that arrives halfway through the sync_stop
> operation.
>
> I experimented with removing the check at the top of snd_pcm_sync_stop,
> so that we enter the if body regardless of
> substream->runtime->stop_operating, and making my application retry
> snd_pcm_prepare() if it fails with -EPIPE, and this seems to "fix" my
> problem. Obviously this causes more (unnecessary) calls to the
> sync_stop() entry point...
>
> I'd be grateful of any thoughts you have about that.
How about the revised patch below?
Takashi
-- 8< --
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1424,16 +1424,28 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream,
static int snd_pcm_do_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
+ int err;
+
if (substream->runtime->trigger_master != substream)
return 0;
- return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ err = substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ /* XRUN happened during the start; usually we do trigger(STOP)
+ * then set the PCM state to XRUN, but in this case, the stream
+ * is stopped in snd_pcm_undo_start() right after this point without
+ * knowing the reason -- so set the PCM state beforehand as exception.
+ */
+ if (err == -EPIPE)
+ __snd_pcm_set_state(substream->runtime, SNDRV_PCM_STATE_XRUN);
+ return err;
}
static void snd_pcm_undo_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
- if (substream->runtime->trigger_master == substream)
+ if (substream->runtime->trigger_master == substream) {
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ substream->runtime->stop_operating = true;
+ }
}
static void snd_pcm_post_start(struct snd_pcm_substream *substream,
next prev parent reply other threads:[~2022-11-29 7:46 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-21 21:14 Query about xrun on usb/pcm Carl Hetherington
2022-11-22 7:25 ` Takashi Iwai
2022-11-22 11:16 ` Carl Hetherington
2022-11-22 14:19 ` Takashi Iwai
2022-11-22 14:22 ` Takashi Iwai
2022-11-28 22:51 ` Carl Hetherington
2022-11-29 7:45 ` Takashi Iwai [this message]
2022-11-30 22:37 ` Carl Hetherington
2022-12-01 7:47 ` Takashi Iwai
2022-12-05 11:59 ` Carl Hetherington
2022-12-05 12:33 ` Takashi Iwai
2022-12-05 18:53 ` Carl Hetherington
2022-12-06 7:51 ` Takashi Iwai
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=87fse2qk51.wl-tiwai@suse.de \
--to=tiwai@suse.de \
--cc=alsa-devel@alsa-project.org \
--cc=lists@carlh.net \
/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.