On Wed, 24 Jul 2013, James Stone wrote:

> Ok - this does seem to be a vast improvement over 3.8.x (and even, in
> some ways the 3.6x series) - with the addition of Clemen's patch.
> However, very low realtime latencies (which seemed to be somewhat
> possible - 64 frames/period or lower - in the 3.6x series) will no
> longer work properly. 128 frames/period looks fairly usable. Will
> continue with bisect to see if I can discover anything else.

I suspect this remaining problem is partly caused by the ALSA driver
misinterpreting the parameters.  For example, when you specify 64
frames/period, what you actually get is 41.3 (on average).

The patch below ought to help.  It is certainly not the correct
solution, but try it out anyway with 64 frames/packet to see if it
works.  And collect a usbmon trace, so I can see whether it really does
behave as intended.  (The patch is meant to apply on top of the one
Clemens sent earlier.)

Alan Stern



Index: usb-3.10/sound/usb/endpoint.c
===================================================================
--- usb-3.10.orig/sound/usb/endpoint.c
+++ usb-3.10/sound/usb/endpoint.c
@@ -575,6 +575,7 @@ static int data_ep_set_params(struct snd
                              struct snd_usb_endpoint *sync_ep)
 {
        unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+       unsigned int min_urbs, max_packs;
        int is_playback = usb_pipeout(ep->pipe);
        int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
@@ -608,10 +609,15 @@ static int data_ep_set_params(struct snd
        else
                ep->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+       if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) {
                packs_per_ms = 8 >> ep->datainterval;
-       else
+               min_urbs = 3;
+               max_packs = MAX_PACKS_HS;
+       } else {
                packs_per_ms = 1;
+               min_urbs = 2;
+               max_packs = MAX_PACKS;
+       }
 
        if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
                urb_packs = max(ep->chip->nrpacks, 1);
@@ -625,42 +631,23 @@ static int data_ep_set_params(struct snd
        if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
                urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
 
-       /* decide how many packets to be used */
-       if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
-               unsigned int minsize, maxpacks;
-               /* determine how small a packet can be */
-               minsize = (ep->freqn >> (16 - ep->datainterval))
-                         * (frame_bits >> 3);
-               /* with sync from device, assume it can be 12% lower */
-               if (sync_ep)
-                       minsize -= minsize >> 3;
-               minsize = max(minsize, 1u);
-               total_packs = (period_bytes + minsize - 1) / minsize;
-               /* we need at least two URBs for queueing */
-               if (total_packs < 2) {
-                       total_packs = 2;
-               } else {
-                       /* and we don't want too long a queue either */
-                       maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
-                       total_packs = min(total_packs, maxpacks);
-               }
-       } else {
-               while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
-                       urb_packs >>= 1;
-               total_packs = MAX_URBS * urb_packs;
-       }
+       /* each URB must fit into one period */
+       urb_packs = min(urb_packs, period_bytes / maxsize);
+       urb_packs = max(1u, urb_packs);
 
-       ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
+       total_packs = min(MAX_QUEUE * packs_per_ms, max_packs);
+       ep->nurbs = total_packs / urb_packs;
        if (ep->nurbs > MAX_URBS) {
                /* too much... */
                ep->nurbs = MAX_URBS;
-               total_packs = MAX_URBS * urb_packs;
-       } else if (ep->nurbs < 2) {
-               /* too little - we need at least two packets
+       } else if (ep->nurbs < min_urbs) {
+               /* too little - we need at least min_urbs URBs
                 * to ensure contiguous playback/capture
                 */
-               ep->nurbs = 2;
+               ep->nurbs = min_urbs;
+               urb_packs = total_packs / ep->nurbs;
        }
+       total_packs = ep->nurbs * urb_packs;
 
        /* allocate and initialize data urbs */
        for (i = 0; i < ep->nurbs; i++) {


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to