usb-audio: Increasing MAX_QUEUE to prevent hiccups in the audio stream?

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

 



Hi folks,

I've spent some time this week trying to debug frequent hiccups in my
audio playback, on my USB sound card. The short version is that it seems
the 24 ms worth of queued URBs is not enough, since the urb complete handler
is frequently called too late and sometimes more than 16ms (plus 8ms in
the urb that completed is 24ms) too late, causing a hiccup in the sound.

My detailed analysis follows.

 - I was having hiccups when playing audio on my Terratec Aureon 5.1 MkII.

 - The hiccups occured frequently when running through pulseaudio with
   timer-based scheduling (tsched=1) and didn't seem to occur when
   running pulseaudio in the "regular" interrupt-driven mode (tsched=0),
   but later analysis suggests that they still occur, but only very
   rarely. I've not found an explanation for this difference, though.

 - These hiccups have been occuring for quite some time, but I've been
   working around then with tsched=0 so far. All of the data gathered in
   this mail, was done using kernel 3.6.0-rc5.

 - While playing audio, I frequently got these messages:
     delay: estimated 240, actual 768
     delay: estimated 1152, actual 768
   They always seem to occur in pairs, (which makes sense since the
   first urb completion is late, but the subsequent one is early). On
   every hiccup, I saw a delay message, but there was not always a
   hiccup when a delay message occurred. It seems that the hiccups only
   occur when the estimated delay is 0 (meaning it's really less than 0,
   i.e. no delay left -> hiccup).
     delay: estimated 0, actual 384
     delay: estimated 384, actual 768

 - My problem seems Similar to a recent report on alsa-devel [2].
   However, that report suggested the problem occured only with an idle
   CPU, while I've observed the problem regardless of CPU usage.

 - These messages are because the urb completion handler is not always
   called in time, probably because the hardware interrupt is somehow
   delayed (as suggested by [1]). This happens frequently, mostly during
   user interaction (switching virtual desktops, changing tabs in the
   browser). Since the completed urb is resubmitted in the completion
   handler, the USB hardware runs out of data to send when the
   completion handler is called more than 16ms too late.

   Note that the completion handler is called at exactly the expected
   moment (8 frames after the previous one) most of the time.

   Also, if urb->start_frame is not lying, the urbs that have their
   completion handler called late did get sent out at the right time, so
   the problem is only that the completion handler is late.

 - By default, the usb snd driver creates three URBs containg 8ms of
   data each, giving me a 24ms buffer (even though the ALSA period size
   is a lot bigger, 1000ms currently). The urb size and count
   calculation in data_ep_set_params initially comes up with a buffer of
   period_size ms, but this is then limited to 24ms because of
   MAX_QUEUE.

 - I can increase the buffer size a bit using the nrpacks module
   parameter. The maximum setting of 20 packets/urb, gets me a buffer of
   40ms (the max_queue tries to limit it again, but since there must be
   two URBs at minimum, I get 40ms). Using this slightly larger buffer,
   the hiccups disappear as good as completely. The delays are still
   there, but apparently they hardly ever get over 20ms.

 - When I tried to double-check something this morning with a clean
   kernel without debugging stuff added, I found out the problem wasn't
   occuring at all, even without passing the nrpacks parameter and with
   tsched=1. I'm not sure what happened there, but presumable there is
   some extra environmental factor involved that I'm missing here
   (I checked everything I could think of, plugged in hardware, running
   processes, doing a standby and hibernate, etc.).

 - I also found a second form of hiccuping that was even more frequent
   (up to a few times per second sometimes). However, these did not go
   paired with delay messages and were always solved by restarting
   pulseaudio, so I'm assuming this is a completely separate issue.

 - There was a recent thread on this list about handling delays in
   isochronous transfers [2]. However, this posting is more concerned
   with recovering after a hiccup, without introducing extra
   (cumulative) latency, which is important for interactive / realtime
   audio streams. For my music stream this doesn't really pose a
   problem, I'm more concerned with preventing the hiccups in the first
   place (and extra latency is not a problem for me).

[1]: http://www.spinics.net/lists/linux-usb/msg69998.html
[2]: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-April/051345.html

So, the real question in this mail is: What can we do to fix this? I've
found out I can somewhat influence the queue size with the nrpacks
variable, which can fix the issue for me, but I'd rather see this work
by default for everyone.

So, a few more considerations:
 - Why is the queue size limited to only 24ms right now? I rather like
   the idea of using pulseaudio and a very big buffer to reduce wakeups
   and thus power usage. Since pulseaudio is keeping a 1000ms buffer in
   my setup, why shouldn't (a large part of) this buffer not be queued
   in urbs to make sure the USB hardware can keep sending data without
   waking up the host system? AFAICS, this would require increasing the
   size of urbs, not just the number of urbs, since an interrupt is
   normally fired after each urb, right? Also, there's probably other
   (performance) considerations that my slightly naive mind is not
   seeing, so please enlighten me :-)
 - In any case, increasing the queue size even a bit helps to fix this
   problem on my particular hardware setup, so probably also on others.
   If the queue size is increased by changing MAX_QUEUE, this would help
   for high-latency applications where the hardware is sometimes slow,
   like my setup, but would still allow for low-latency applications
   when the period_size is set to a small value.
 - Or are the delays in the urb completion handler / interrupt by
   definition a bug in (some other part of) the code? In that case, I
   might be able to dig in deeper to find and fix the cause of the
   delays, if someone can offer some suggestions about where to look for
   the problem.

Gr.

Matthijs

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux