Hi Takashi,
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.
Thanks for the hint. I checked it out again, and in fact I'm seeing the -EPIPE come back from snd_pcm_do_prepare(). It starts its sync-stop, another xrun comes in (as we talked about before), it tries to start_endpoints() and that fails.
A fairly similar thing to what you suggested seems to work for me:
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f38c2e5e9a29..0b61943cca98 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1948,9 +1948,17 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); }
+ +static void snd_pcm_undo_prepare(struct snd_pcm_substream *substream, + snd_pcm_state_t state) +{ + substream->runtime->stop_operating = true; +} + static const struct action_ops snd_pcm_action_prepare = { .pre_action = snd_pcm_pre_prepare, .do_action = snd_pcm_do_prepare, + .undo_action = snd_pcm_undo_prepare, .post_action = snd_pcm_post_prepare };
Can you see any problems with that? In the application code I do need to re-try the snd_pcm_prepare() if one fails with -EPIPE, but with this undo step the second snd_pcm_prepare() is able to recover the endpoint states, instead of hitting this problem where it tries to start things that are STOPPING, but also won't set things to STOPPED because stop_operating is false.
Thanks and best regards, Carl