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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html