Re: [PATCH v5 5/5] usb: gadget: f_uac2: send reasonably sized packets

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

 



On Wed, 27 Aug 2014, Daniel Mack wrote:

> The UAC2 function driver currently responds to all packets at all times
> with wMaxPacketSize packets. That results in way too fast audio
> playback as the function driver (which is in fact supposed to define
> the audio stream pace) delivers as fast as it can.
> 
> Fix this by sizing each packet correctly with the following steps:
> 
>  a) Set the packet's size by dividing the nominal data rate by the
>     playback endpoint's interval.q
> 
>  b) If there is a residual value from the calculation in a), add
>     it to a accumulator to keep track of it across packets.
> 
>  c) If the accumulator has gathered at least the number of bytes
>     that are needed for one sample frame, increase the packet size.
> 
> This way, the packet size calculation will get rid of any kind of
> imprecision that would otherwise occur with a simple division over
> time.
> 
> Signed-off-by: Daniel Mack <zonque@xxxxxxxxx>


> @@ -191,8 +195,43 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
>  
>  	spin_lock_irqsave(&prm->lock, flags);
>  
> -	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> +		struct audio_dev *agdev = uac2_to_agdev(uac2);
> +		struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
> +		unsigned int fsz = opts->p_ssize * num_channels(opts->p_chmask);
> +		unsigned int rate = opts->p_srate * fsz;
> +
> +		/*
> +		 * For each IN packet, calculate the minimum packet size by
> +		 * dividing the nominal bytes per second as required by the
> +		 * current audio format by the endpoint's interval.
> +		 */
> +		req->length = min_t(unsigned int,
> +				    rate / uac2->p_interval, prm->max_psize);
> +
> +		/*
> +		 * If there is a residual value from the division, add it to
> +		 * the residue accumulator.
> +		 */
> +		uac2->p_residue += rate % uac2->p_interval;
> +
> +		/*
> +		 * Whenever there are more bytes in the accumulator than we
> +		 * need to add one more sample frame, increase this packet's
> +		 * size and decrease the accumulator.
> +		 */
> +		if (uac2->p_residue / uac2->p_interval >= fsz) {
> +			req->length += fsz;
> +			uac2->p_residue -= fsz * uac2->p_interval;
> +		}

One thing I didn't mention about the algorithm I posted earlier: The
individual packet calculations don't contain any multiplications or
divisions.

The code here is in the hottest part of the driver, so you might want
to optimize it a little.  For instance, several of the operations could 
be precomputed and stored for later use.

Alan Stern

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




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

  Powered by Linux