Message ID | alpine.DEB.2.02.1510100012390.7332@lnxricardw1.se.axis.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Ricard Wanderlof wrote: > The addition of 0xffff ("almost 1" in Q16.16 format), resulting > in the rounding up of the resulting value, was in the wrong place, > as it is the resulting packet size that needs to be rounded up > to the nearest integer (e.g. if the resulting packet size is > calculated as 55.125 bytes, we need a packet of 56 bytes), > rather than the rate value (ep->freqmax). > > Tested with an Edirol UA-5 both at 44.1 kHz and 96 kHz. > > Signed-off-by: Ricard Wanderlof <ricardw@axis.com> > --- > V2: Added tested device to commit message. No other changes. > > Since this clearly is a sensitive part of the code, here follows a lengthy > rationale with examples to illustrate the problem. There is a maximum size for USB packets, but not for git commit messages. :) > [...] > The problem here is that the addition of 0xffff is in the wrong place. We don't > want the rounding up to take place on the frequency, but on the resulting > packet size. Packets must not contain partial frames, so the rounding must take place on the number of frames per packet. > Let's take an example. We have a sample rate of 96 kHz, so our > ep->freqn is 786432 (see usb_high_speed_rate()). Add 25% (line 612) and we get > 983040. The calculated maxsize is then ((983040 + 65535) * 8) >> 16 = 127 . That code was intended to round correctly, but it's obviously wrong because the result is not an integer multiple of the frame size. (Please write Q16.16 values in hex.) > However, if we do the number of bytes calculation in a less obscure way it's > more apparent what the true corresponding packet size is: we get > (96000 * 1.25 / 8000) * 8 = 120 The value inside the parentheses is the number of frames per packet, and must be rounded. > This is also corroborated by the wMaxPacketSize check on line 616. Assume > that wMaxPacketSize = 108 It would not make sense to have a value that is not a multiple of the frame size. (I'm not saying that it doesn't occur in practice ...) Regards, Clemens
On Sat, 10 Oct 2015, Clemens Ladisch wrote: There is a maximum size for USB packets, but not for git commit messages. :) Smiley aside, do you think more of the rationale should be in the commit message or is it sufficient the way it is? > > The problem here is that the addition of 0xffff is in the wrong place. We don't > > want the rounding up to take place on the frequency, but on the resulting > > packet size. > > Packets must not contain partial frames, so the rounding must take place > on the number of frames per packet. That of course makes perfect sense. > > Let's take an example. We have a sample rate of 96 kHz, so our > > ep->freqn is 786432 (see usb_high_speed_rate()). Add 25% (line 612) and we get > > 983040. The calculated maxsize is then ((983040 + 65535) * 8) >> 16 = 127 . > > That code was intended to round correctly, but it's obviously wrong > because the result is not an integer multiple of the frame size. If that is the case we need to do something like maxsize = (((freqn + 0xffff) & 0xffff0000) * frame_size) >> 16 where the & 0xffff0000 rounds the Q16.16 number down to the nearest integer, so that when multiplying by frame_size we get an integral multiple thereof. In the (trivial) case above (with 983040 = 0xf0000) we get maxsize = (((0xf0000 + 0xffff) & 0xffff0000) *8) >> 16 = 120 (which is correct). > (Please write Q16.16 values in hex.) Ok, will do. > > This is also corroborated by the wMaxPacketSize check on line 616. Assume > > that wMaxPacketSize = 108 > > It would not make sense to have a value that is not a multiple of the > frame size. (I'm not saying that it doesn't occur in practice ...) In this particular case I was withholding information. :) The actual device in question needs a quirk whereby the audio data in each packet is prefixed by an u32 containing the number of audio data bytes in the packet. So 108 is the actual number, as the corresponding number of audio bytes, 104, is a multiple of 8. But of course I should not have used that particular maxsize as an example in this patch. Ok, I'll rework this and resubmit. /Ricard
On Sat, 10 Oct 2015, Ricard Wanderlof wrote: > > That code was intended to round correctly, but it's obviously wrong > > because the result is not an integer multiple of the frame size. > > If that is the case we need to do something like > > maxsize = (((freqn + 0xffff) & 0xffff0000) * frame_size) >> 16 Or, much simpler, I realized later: maxsize = ((freqn + 0xffff) >> 16) * frame_size i.e. we make the conversion from Q16.16 to integer before multiplying with the frame size to automatically get the rounding as intended. /Ricard
On Sat, 10 Oct 2015, Clemens Ladisch wrote: > It would not make sense to have a value that is not a multiple of the > frame size. (I'm not saying that it doesn't occur in practice ...) Yes, I just noted that the Edirol UA-5 has a max packet size of 608, which is not evenly divisible by the frame size of 6 (advanced mode: 3 bytes per sample, stereo). /Ricard
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index e6f7189..be8a972 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -610,7 +610,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, /* assume max. frequency is 25% higher than nominal */ ep->freqmax = ep->freqn + (ep->freqn >> 2); - maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) + maxsize = (ep->freqmax * (frame_bits >> 3) + 0xffff) >> (16 - ep->datainterval); /* but wMaxPacketSize might reduce this */ if (ep->maxpacksize && ep->maxpacksize < maxsize) {