summaryrefslogtreecommitdiff
path: root/sound/usb/pcm.c
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-08-30 20:52:30 +0400
committerTakashi Iwai <tiwai@suse.de>2012-08-31 23:03:48 +0400
commit245baf983cc39524cce39c24d01b276e6e653c9e (patch)
tree2fbd88aebcbbe95b60a6ae62d946a840ae1ff28b /sound/usb/pcm.c
parentfbcfbf5f673847657ccd98afb4d8e13af7fdc372 (diff)
downloadlinux-245baf983cc39524cce39c24d01b276e6e653c9e.tar.xz
ALSA: snd-usb: fix calls to next_packet_size
In order to support devices with implicit feedback streaming models, packet sizes are now stored with each individual urb, and the PCM handling code which fills the buffers purely relies on the size fields now. However, calling snd_usb_audio_next_packet_size() for all possible packets in an URB at once, prior to letting the PCM code do its job does in fact not lead to the same behaviour than what the old code did: The PCM code will break its loop once a period boundary is reached, consequently using up less packets that it really could. As snd_usb_audio_next_packet_size() implements a feedback mechanism to the endpoints phase accumulator, the number of calls to that function matters, and when called too often, the data rate runs out of bounds. Fix this by making the next_packet function public, and call it from the PCM code as before if the packet data sizes are not defined. Signed-off-by: Daniel Mack <zonque@gmail.com> Cc: stable@kernel.org [v3.5+] Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/pcm.c')
-rw-r--r--sound/usb/pcm.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 5ceb8f1d63fb..e80b6687f43a 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1029,6 +1029,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
struct urb *urb)
{
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ struct snd_usb_endpoint *ep = subs->data_endpoint;
struct snd_urb_ctx *ctx = urb->context;
unsigned int counts, frames, bytes;
int i, stride, period_elapsed = 0;
@@ -1040,7 +1041,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
urb->number_of_packets = 0;
spin_lock_irqsave(&subs->lock, flags);
for (i = 0; i < ctx->packets; i++) {
- counts = ctx->packet_size[i];
+ if (ctx->packet_size[i])
+ counts = ctx->packet_size[i];
+ else
+ counts = snd_usb_endpoint_next_packet_size(ep);
+
/* set up descriptor */
urb->iso_frame_desc[i].offset = frames * stride;
urb->iso_frame_desc[i].length = counts * stride;