On 28.08.2013 20:46, Alan Stern wrote:
> On Wed, 28 Aug 2013, Clemens Ladisch wrote:
> 
>> Sorry, what I said applies more to explicit sync endpoints.  When using
>> implicit sync, a playback URB is submitted for each completed capture
>> URB, with the number of samples per packet identical to the
>> corresponding capture packet, so the parameters must be identical.
> 
> Got it.  Below is an updated patch.
> 
> James, the problem you encountered was most likely a result of the
> faulty treatment of capture endpoints that Clemens pointed out.  It was
> quite obvious in the usbmon traces that the unpatched driver used 8
> packets per URB whereas the patched driver used 22.  This updated patch
> should fix that problem.

I gave this patch a try and I can confirm that it results in a
sigificant improvement for small sample buffers.

So feel free to add my

  Tested-by: Daniel Mack <zon...@gmail.com>


Thanks,
Daniel



> Index: usb-3.11/sound/usb/usbaudio.h
> ===================================================================
> --- usb-3.11.orig/sound/usb/usbaudio.h
> +++ usb-3.11/sound/usb/usbaudio.h
> @@ -55,7 +55,6 @@ struct snd_usb_audio {
>       struct list_head mixer_list;    /* list of mixer interfaces */
>  
>       int setup;                      /* from the 'device_setup' module param 
> */
> -     int nrpacks;                    /* from the 'nrpacks' module param */
>       bool autoclock;                 /* from the 'autoclock' module param */
>  
>       struct usb_host_interface *ctrl_intf;   /* the audio control interface 
> */
> Index: usb-3.11/sound/usb/card.c
> ===================================================================
> --- usb-3.11.orig/sound/usb/card.c
> +++ usb-3.11/sound/usb/card.c
> @@ -79,7 +79,6 @@ static bool enable[SNDRV_CARDS] = SNDRV_
>  /* Vendor/product IDs for this card */
>  static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
>  static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
> -static int nrpacks = 8;              /* max. number of packets per urb */
>  static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
>  static bool ignore_ctl_error;
>  static bool autoclock = true;
> @@ -94,8 +93,6 @@ module_param_array(vid, int, NULL, 0444)
>  MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
>  module_param_array(pid, int, NULL, 0444);
>  MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
> -module_param(nrpacks, int, 0644);
> -MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
>  module_param_array(device_setup, int, NULL, 0444);
>  MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
>  module_param(ignore_ctl_error, bool, 0444);
> @@ -374,7 +371,6 @@ static int snd_usb_audio_create(struct u
>       chip->dev = dev;
>       chip->card = card;
>       chip->setup = device_setup[idx];
> -     chip->nrpacks = nrpacks;
>       chip->autoclock = autoclock;
>       chip->probing = 1;
>  
> @@ -756,10 +752,6 @@ static struct usb_driver usb_audio_drive
>  
>  static int __init snd_usb_audio_init(void)
>  {
> -     if (nrpacks < 1 || nrpacks > MAX_PACKS) {
> -             printk(KERN_WARNING "invalid nrpacks value.\n");
> -             return -EINVAL;
> -     }
>       return usb_register(&usb_audio_driver);
>  }
>  
> Index: usb-3.11/sound/usb/endpoint.h
> ===================================================================
> --- usb-3.11.orig/sound/usb/endpoint.h
> +++ usb-3.11/sound/usb/endpoint.h
> @@ -12,6 +12,8 @@ int snd_usb_endpoint_set_params(struct s
>                               snd_pcm_format_t pcm_format,
>                               unsigned int channels,
>                               unsigned int period_bytes,
> +                             unsigned int period_frames,
> +                             unsigned int buffer_periods,
>                               unsigned int rate,
>                               struct audioformat *fmt,
>                               struct snd_usb_endpoint *sync_ep);
> Index: usb-3.11/sound/usb/card.h
> ===================================================================
> --- usb-3.11.orig/sound/usb/card.h
> +++ usb-3.11/sound/usb/card.h
> @@ -2,11 +2,11 @@
>  #define __USBAUDIO_CARD_H
>  
>  #define MAX_NR_RATES 1024
> -#define MAX_PACKS    20
> +#define MAX_PACKS    6               /* per URB */
>  #define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
> -#define MAX_URBS     8
> +#define MAX_URBS     12
>  #define SYNC_URBS    4       /* always four urbs for sync */
> -#define MAX_QUEUE    24      /* try not to exceed this queue length, in ms */
> +#define MAX_QUEUE    18      /* try not to exceed this queue length, in ms */
>  
>  struct audioformat {
>       struct list_head list;
> @@ -87,6 +87,7 @@ struct snd_usb_endpoint {
>       unsigned int phase;             /* phase accumulator */
>       unsigned int maxpacksize;       /* max packet size in bytes */
>       unsigned int maxframesize;      /* max packet size in frames */
> +     unsigned int max_urb_frames;    /* max URB size in frames */
>       unsigned int curpacksize;       /* current packet size in bytes (for 
> capture) */
>       unsigned int curframesize;      /* current packet size in frames (for 
> capture) */
>       unsigned int syncmaxsize;       /* sync endpoint packet size */
> @@ -116,6 +117,8 @@ struct snd_usb_substream {
>       unsigned int channels_max;      /* max channels in the all audiofmts */
>       unsigned int cur_rate;          /* current rate (for hw_params 
> callback) */
>       unsigned int period_bytes;      /* current period bytes (for hw_params 
> callback) */
> +     unsigned int period_frames;     /* current frames per period */
> +     unsigned int buffer_periods;    /* current periods per buffer */
>       unsigned int altset_idx;     /* USB data format: index of alternate 
> setting */
>       unsigned int txfr_quirk:1;      /* allow sub-frame alignment */
>       unsigned int fmt_type;          /* USB audio format type (1-3) */
> @@ -125,6 +128,7 @@ struct snd_usb_substream {
>  
>       unsigned int hwptr_done;        /* processed byte position in the 
> buffer */
>       unsigned int transfer_done;             /* processed frames since last 
> period update */
> +     unsigned int frame_limit;       /* limits number of packets in URB */
>  
>       /* data and sync endpoints for this stream */
>       unsigned int ep_num;            /* the endpoint number */
> Index: usb-3.11/sound/usb/pcm.c
> ===================================================================
> --- usb-3.11.orig/sound/usb/pcm.c
> +++ usb-3.11/sound/usb/pcm.c
> @@ -562,6 +562,7 @@ static int configure_sync_endpoint(struc
>                                                  subs->pcm_format,
>                                                  subs->channels,
>                                                  subs->period_bytes,
> +                                                0, 0,
>                                                  subs->cur_rate,
>                                                  subs->cur_audiofmt,
>                                                  NULL);
> @@ -598,6 +599,7 @@ static int configure_sync_endpoint(struc
>                                         subs->pcm_format,
>                                         sync_fp->channels,
>                                         sync_period_bytes,
> +                                       0, 0,
>                                         subs->cur_rate,
>                                         sync_fp,
>                                         NULL);
> @@ -620,6 +622,8 @@ static int configure_endpoint(struct snd
>                                         subs->pcm_format,
>                                         subs->channels,
>                                         subs->period_bytes,
> +                                       subs->period_frames,
> +                                       subs->buffer_periods,
>                                         subs->cur_rate,
>                                         subs->cur_audiofmt,
>                                         subs->sync_endpoint);
> @@ -656,6 +660,8 @@ static int snd_usb_hw_params(struct snd_
>  
>       subs->pcm_format = params_format(hw_params);
>       subs->period_bytes = params_period_bytes(hw_params);
> +     subs->period_frames = params_period_size(hw_params);
> +     subs->buffer_periods = params_periods(hw_params);
>       subs->channels = params_channels(hw_params);
>       subs->cur_rate = params_rate(hw_params);
>  
> @@ -1330,6 +1336,7 @@ static void prepare_playback_urb(struct
>       frames = 0;
>       urb->number_of_packets = 0;
>       spin_lock_irqsave(&subs->lock, flags);
> +     subs->frame_limit += ep->max_urb_frames;
>       for (i = 0; i < ctx->packets; i++) {
>               if (ctx->packet_size[i])
>                       counts = ctx->packet_size[i];
> @@ -1344,6 +1351,7 @@ static void prepare_playback_urb(struct
>               subs->transfer_done += counts;
>               if (subs->transfer_done >= runtime->period_size) {
>                       subs->transfer_done -= runtime->period_size;
> +                     subs->frame_limit = 0;
>                       period_elapsed = 1;
>                       if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
>                               if (subs->transfer_done > 0) {
> @@ -1366,8 +1374,10 @@ static void prepare_playback_urb(struct
>                               break;
>                       }
>               }
> -             if (period_elapsed &&
> -                 
> !snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint)) /* finish at 
> the period boundary */
> +             /* finish at the period boundary or after enough frames */
> +             if ((period_elapsed ||
> +                             subs->transfer_done >= subs->frame_limit) &&
> +                 !snd_usb_endpoint_implicit_feedback_sink(ep))
>                       break;
>       }
>       bytes = frames * ep->stride;
> Index: usb-3.11/sound/usb/endpoint.c
> ===================================================================
> --- usb-3.11.orig/sound/usb/endpoint.c
> +++ usb-3.11/sound/usb/endpoint.c
> @@ -571,11 +571,14 @@ static int data_ep_set_params(struct snd
>                             snd_pcm_format_t pcm_format,
>                             unsigned int channels,
>                             unsigned int period_bytes,
> +                           unsigned int frames_per_period,
> +                           unsigned int periods_per_buffer,
>                             struct audioformat *fmt,
>                             struct snd_usb_endpoint *sync_ep)
>  {
> -     unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
> -     int is_playback = usb_pipeout(ep->pipe);
> +     unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb;
> +     unsigned int max_packs_per_period, urbs_per_period, urb_packs;
> +     unsigned int max_urbs, i;
>       int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
>  
>       if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
> @@ -608,58 +611,67 @@ 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
> -             packs_per_ms = 1;
> -
> -     if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
> -             urb_packs = max(ep->chip->nrpacks, 1);
> -             urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
> +             max_packs_per_urb = MAX_PACKS_HS;
>       } else {
> -             urb_packs = 1;
> +             packs_per_ms = 1;
> +             max_packs_per_urb = MAX_PACKS;
>       }
> -
> -     urb_packs *= packs_per_ms;
> -
>       if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
> -             urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
> +             max_packs_per_urb = min(max_packs_per_urb,
> +                                     1U << sync_ep->syncinterval);
> +     max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval);
> +
> +     /*
> +      * Capture endpoints need to use small URBs because there's no way
> +      * to tell in advance where the next period will end, and we don't
> +      * want the next URB to complete much after the period ends.
> +      *
> +      * Playback endpoints with implicit sync much use the same parameters
> +      * as their corresponding capture endpoint.
> +      */
> +     if (usb_pipein(ep->pipe) ||
> +                     snd_usb_endpoint_implicit_feedback_sink(ep)) {
> +
> +             /* make capture URBs <= 1 ms and smaller than a period */
> +             urb_packs = min(max_packs_per_urb, packs_per_ms);
> +             while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
> +                     urb_packs >>= 1;
> +             ep->nurbs = MAX_URBS;
>  
> -     /* decide how many packets to be used */
> -     if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
> -             unsigned int minsize, maxpacks;
> +     /*
> +      * Playback endpoints without implicit sync are adjusted so that
> +      * a period fits as evenly as possible in the smallest number of
> +      * URBs.  The total number of URBs is adjusted to the size of the
> +      * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits.
> +      */
> +     } else {
>               /* determine how small a packet can be */
> -             minsize = (ep->freqn >> (16 - ep->datainterval))
> -                       * (frame_bits >> 3);
> +             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;
> -     }
>  
> -     ep->nurbs = (total_packs + urb_packs - 1) / 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
> -              * to ensure contiguous playback/capture
> -              */
> -             ep->nurbs = 2;
> +             /* how many packets will contain an entire ALSA period? */
> +             max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize);
> +
> +             /* how many URBs will contain a period? */
> +             urbs_per_period = DIV_ROUND_UP(max_packs_per_period,
> +                             max_packs_per_urb);
> +             /* how many packets are needed in each URB? */
> +             urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period);
> +
> +             /* limit the number of frames in a single URB */
> +             ep->max_urb_frames = DIV_ROUND_UP(frames_per_period,
> +                                     urbs_per_period);
> +
> +             /* try to use enough URBs to contain an entire ALSA buffer */
> +             max_urbs = min((unsigned) MAX_URBS,
> +                             MAX_QUEUE * packs_per_ms / urb_packs);
> +             ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer);
>       }
>  
>       /* allocate and initialize data urbs */
> @@ -667,8 +679,7 @@ static int data_ep_set_params(struct snd
>               struct snd_urb_ctx *u = &ep->urb[i];
>               u->index = i;
>               u->ep = ep;
> -             u->packets = (i + 1) * total_packs / ep->nurbs
> -                     - i * total_packs / ep->nurbs;
> +             u->packets = urb_packs;
>               u->buffer_size = maxsize * u->packets;
>  
>               if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
> @@ -745,6 +756,8 @@ out_of_memory:
>   * @pcm_format: the audio fomat.
>   * @channels: the number of audio channels.
>   * @period_bytes: the number of bytes in one alsa period.
> + * @period_frames: the number of frames in one alsa period.
> + * @buffer_periods: the number of periods in one alsa buffer.
>   * @rate: the frame rate.
>   * @fmt: the USB audio format information
>   * @sync_ep: the sync endpoint to use, if any
> @@ -757,6 +770,8 @@ int snd_usb_endpoint_set_params(struct s
>                               snd_pcm_format_t pcm_format,
>                               unsigned int channels,
>                               unsigned int period_bytes,
> +                             unsigned int period_frames,
> +                             unsigned int buffer_periods,
>                               unsigned int rate,
>                               struct audioformat *fmt,
>                               struct snd_usb_endpoint *sync_ep)
> @@ -790,7 +805,8 @@ int snd_usb_endpoint_set_params(struct s
>       switch (ep->type) {
>       case  SND_USB_ENDPOINT_TYPE_DATA:
>               err = data_ep_set_params(ep, pcm_format, channels,
> -                                      period_bytes, fmt, sync_ep);
> +                                      period_bytes, period_frames,
> +                                      buffer_periods, fmt, sync_ep);
>               break;
>       case  SND_USB_ENDPOINT_TYPE_SYNC:
>               err = sync_ep_set_params(ep, fmt);
> 
> 

--
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