Daniel Mack <zonque <at> gmail.com> writes:
> >> This is a known bug, also most probably flaw in the CMEDIA chip, 
> >> and not yet properly worked around in the snd-usb driver. If you 
> >> want to investigate, have a look at the feedback format 
> >> autodetection code in sound/usb/endpoint.c.
> > 
> > Thanks, I'll have a look.
> 
> I believe what's going on here is that the device is confused after
> sample rate changes and keeps sending back feedback data for the old
> rate on its feedback endpoint. That causes the autodetection algorithm,
> which kicks in on every first packet of a stream, to go nuts, which
> causes the part of the driver that sends the data assume a very wrong
> rate. Some printk() there should give you a hint.

I had a look at this using another C-Media CM6631 based device, the Corda
Daccord (usbid 0x0d8c, 0x0309). As far as I can see, what happens in the
feedback format auto-detection is: 

When starting playback of a file with a different sampling frequency than the 
previous file, the reported feedback frequency is in the same range as the 
previously played file, varying within +-1%.

The feedback format detection gives a shift of -1 and reports the feedback
frequency as ~48kHz when playing a 44.1kHz file after a 96kHz file. Same thing
happens when playing a 96kHz file after a 44.1kHz file, the device reports
feedback frequency in the 44.1kHz range, the feedback format detection gives a
shift of +1 and reports the feedback frequency as ~88kHz.

Bypassing the feedback format detection by hard-coding the frequency shift to
zero and setting the feedback frequency ep->freqm equal to the nominal
frequency ep->freqn if the feedback frequency is far off from the expected
value (like 48kHz when expecting 44.1kHz) does not change the distortion.

Similarly, forcing the feedback detection to run multiple times until it
reaches an acceptable value just keeps the feedback detection to repeatedly
until playback is stopped. This probably means any amount of skipping packages
early in the stream won't work.

It seems like the device stays in the previous frequency until the interface
is reset. One possible workaround is to call usb_set_interface() again after
snd_usb_init_sample_rate(), like this:

diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index d82e378..01978a6 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -710,6 +710,16 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream
*substream)
                subs->need_setup_ep = false;
        }
 
+       /* Some devices doesn't respond to sample rate changes while the 
+        * interface is active. */
+       switch (subs->stream->chip->usb_id) {
+       case USB_ID(0x0d8c, 0x0304): /* C-Media - Schiit USB Interface */
+       case USB_ID(0x0d8c, 0x0309): /* C-Media CM6631 */
+               usb_set_interface(subs->dev, subs->cur_audiofmt->iface,
+                                       subs->cur_audiofmt->altset_idx);
+               break;
+       }   
+
        /* some unit conversions in runtime */
        subs->data_endpoint->maxframesize =
                bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);

This fixes all problems related to sample rate changes for me. I have only
tested with the Daccord, but it should work for the Schiit and other CM6631
based devices as well.

I was initially thinking this could be done in snd_usb_endpoint_start_quirk(),
but the call to usb_set_interface() must be performed before start_endpoints().


Torstein


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_feb
_______________________________________________
Alsa-user mailing list
Alsa-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/alsa-user

Reply via email to