aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorJohn S. Gruber <JohnSGruber@gmail.com>2009-12-27 12:19:58 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-28 06:30:41 -0500
commit98e89f606c38a310a20342f90e0c453e6afadf18 (patch)
treeed5a677157cf5bdd781c04e986813f112c6bf72c /sound/usb
parentadc8d31326c32a2a1e145ab80accbc3c6570b117 (diff)
ALSA: usb-audio: relax urb data align. restriction HVR-950Q and HVR-850 only
Addressing audio quality problem. In sound/usb/usbaudio.c, for the Hauppage HVR-950Q and HVR-850 only, change retire_capture_urb to allow transfers on audio sub-slot boundaries rather than audio slots boundaries. With these devices the left and right channel samples can be split between two different urbs. Throwing away extra channel samples causes a sound quality problem for stereo streams as the left and right channels are swapped repeatedly, perhaps many times per second. Urbs unaligned on sub-slot boundaries are still truncated to the next lowest stride (audio slot) to retain synchronization on samples even though left/right channel synchronization may be lost in this case. Detect the quirk using a case statement in snd_usb_audio_probe. BugLink: https://bugs.launchpad.net/ubuntu/+bug/495745 Signed-off-by: John S. Gruber <JohnSGruber@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usbaudio.c31
-rw-r--r--sound/usb/usbaudio.h1
2 files changed, 30 insertions, 2 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 8fcb5d5a94b6..617515f6ec7b 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -169,6 +169,7 @@ struct snd_usb_substream {
169 unsigned int curpacksize; /* current packet size in bytes (for capture) */ 169 unsigned int curpacksize; /* current packet size in bytes (for capture) */
170 unsigned int curframesize; /* current packet size in frames (for capture) */ 170 unsigned int curframesize; /* current packet size in frames (for capture) */
171 unsigned int fill_max: 1; /* fill max packet size always */ 171 unsigned int fill_max: 1; /* fill max packet size always */
172 unsigned int txfr_quirk:1; /* allow sub-frame alignment */
172 unsigned int fmt_type; /* USB audio format type (1-3) */ 173 unsigned int fmt_type; /* USB audio format type (1-3) */
173 174
174 unsigned int running: 1; /* running status */ 175 unsigned int running: 1; /* running status */
@@ -353,14 +354,25 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
353 snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); 354 snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
354 // continue; 355 // continue;
355 } 356 }
356 frames = urb->iso_frame_desc[i].actual_length / stride; 357 bytes = urb->iso_frame_desc[i].actual_length;
357 bytes = frames * stride; 358 frames = bytes / stride;
359 if (!subs->txfr_quirk)
360 bytes = frames * stride;
361 if (bytes % (runtime->sample_bits >> 3) != 0) {
362#ifdef CONFIG_SND_DEBUG_VERBOSE
363 int oldbytes = bytes;
364#endif
365 bytes = frames * stride;
366 snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
367 oldbytes, bytes);
368 }
358 /* update the current pointer */ 369 /* update the current pointer */
359 spin_lock_irqsave(&subs->lock, flags); 370 spin_lock_irqsave(&subs->lock, flags);
360 oldptr = subs->hwptr_done; 371 oldptr = subs->hwptr_done;
361 subs->hwptr_done += bytes; 372 subs->hwptr_done += bytes;
362 if (subs->hwptr_done >= runtime->buffer_size * stride) 373 if (subs->hwptr_done >= runtime->buffer_size * stride)
363 subs->hwptr_done -= runtime->buffer_size * stride; 374 subs->hwptr_done -= runtime->buffer_size * stride;
375 frames = (bytes + (oldptr % stride)) / stride;
364 subs->transfer_done += frames; 376 subs->transfer_done += frames;
365 if (subs->transfer_done >= runtime->period_size) { 377 if (subs->transfer_done >= runtime->period_size) {
366 subs->transfer_done -= runtime->period_size; 378 subs->transfer_done -= runtime->period_size;
@@ -2238,6 +2250,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo
2238 subs->stream = as; 2250 subs->stream = as;
2239 subs->direction = stream; 2251 subs->direction = stream;
2240 subs->dev = as->chip->dev; 2252 subs->dev = as->chip->dev;
2253 subs->txfr_quirk = as->chip->txfr_quirk;
2241 if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { 2254 if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) {
2242 subs->ops = audio_urb_ops[stream]; 2255 subs->ops = audio_urb_ops[stream];
2243 } else { 2256 } else {
@@ -3618,6 +3631,20 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
3618 } 3631 }
3619 } 3632 }
3620 3633
3634 switch (chip->usb_id) {
3635 case USB_ID(0x2040, 0x7200): /* Hauppage hvr950Q */
3636 case USB_ID(0x2040, 0x7221): /* Hauppage hvr950Q */
3637 case USB_ID(0x2040, 0x7222): /* Hauppage hvr950Q */
3638 case USB_ID(0x2040, 0x7223): /* Hauppage hvr950Q */
3639 case USB_ID(0x2040, 0x7224): /* Hauppage hvr950Q */
3640 case USB_ID(0x2040, 0x7225): /* Hauppage hvr950Q */
3641 case USB_ID(0x2040, 0x7230): /* Hauppage hvr850 */
3642 case USB_ID(0x2040, 0x7250): /* Hauppage hvr950Q */
3643 chip->txfr_quirk = 1;
3644 break;
3645 default:
3646 chip->txfr_quirk = 0;
3647 }
3621 err = 1; /* continue */ 3648 err = 1; /* continue */
3622 if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { 3649 if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
3623 /* need some special handlings */ 3650 /* need some special handlings */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 152216738cce..d180554b81f0 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -125,6 +125,7 @@ struct snd_usb_audio {
125 struct snd_card *card; 125 struct snd_card *card;
126 u32 usb_id; 126 u32 usb_id;
127 int shutdown; 127 int shutdown;
128 unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
128 int num_interfaces; 129 int num_interfaces;
129 int num_suspended_intf; 130 int num_suspended_intf;
130 131