Re: Query about xrun on usb/pcm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 21 Nov 2022 22:14:39 +0100,
Carl Hetherington wrote:
> 
> Hi all,
> 
> I wonder if anybody has any clues/suggestions about problem I'm seeing
> with an XMOS-based USB sound card.
> 
> As far as I can see, the card has endpoint 0x82 set up for capture data,
> 0x2 for playback data, and 0x82 is also used as the sync endpoint for
> playback.  I'm assuming that's a fairly common arrangement?

Yes, that's an oft-seen implicit feedback mode.
You seem hitting a corner case of dealing with that mode...

> I am testing it using simultaneous playback and capture, and simulating
> a high-CPU-load case by sleeping for long enough to cause a lot of
> xruns.  After some random time, I see a failure case that I'm struggling
> to explain.  It goes like this:
> 
> There's an XRUN on the playback PCM, so __snd_pcm_xrun happens, then
>   stop_endpoints() happens, and:
>       it decides not to stop 0x82 because its running is > 1
>       it stops 0x2, so its state goes to EP_STATE_STOPPING
> 
> Then the ALSA userspace code calls prepare on the playback PCM to get it
> going again.
> 
> This ends up in wait_clear_urbs(), which does nothing with 0x82 as it is
> still running.

So far, so good.

> At this point, the prepare thread is interrupted by an XRUN on
> the capture PCM. With this PCM, there is no sync endpoint, and 0x82 is the data
> endpoint.
> In the xrun handler:
>   stop_urbs() sets 0x82 to EP_STATE_STOPPING.
>   ... and the xrun handler finishes.
> 
> Then we end up back in the prepare for the playback PCM.
> wait_clear_urbs() then sets 0x2 to STOPPED, and the prepare is finished.
> 
> Now, snd_usb_endpoint_start() is called on 0x2 and that is fine.  Next,
> snd_usb_endpoint_start() is called on 0x82 and that fails because its
> state is still STOPPING.
> 
> At this point things seem broken.
>
> Does anyone have a hint about where in this sequence things are going
> wrong, and maybe even why?

The problem is that it's treating XRUNs on the both streams
individually.  It's correct to recover only the PCM stream when an
XRUN is reported to the PCM stream.  However, for an XRUN on the
capture stream that serves as a sync source, it should stop and
recover not only the capture PCM stream but also the playback stream
as a sync sink as well.

Below is a possible test fix (totally untested!).
This may give XRUNs twice eventually, which is a bit confusing, but it
aligns with the actual hardware behavior, at least.


thanks,

Takashi

-- 8< --
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -403,10 +403,15 @@ static int prepare_inbound_urb(struct snd_usb_endpoint *ep,
 static void notify_xrun(struct snd_usb_endpoint *ep)
 {
 	struct snd_usb_substream *data_subs;
+	struct snd_usb_endpoint *ep_sink;
 
 	data_subs = READ_ONCE(ep->data_subs);
-	if (data_subs && data_subs->pcm_substream)
+	if (data_subs && data_subs->pcm_substream) {
 		snd_pcm_stop_xrun(data_subs->pcm_substream);
+		ep_sink = READ_ONCE(ep->sync_sink);
+		if (ep_sink)
+			notify_xrun(ep_sink);
+	}
 }
 
 static struct snd_usb_packet_info *



[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux