Re: [alsa-devel] [Alsa-user] Status of CM6631 USB
Hi Torstein,
(+ alsa-devel)
On 02.03.2013 12:09, Torstein Hegge wrote:
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.
That's what I suspected.
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.
Ok.
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:
I see - that also explains why explicitly stopping and restarting the stream fixes the problem in most cases, right?
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.
Many thanks for looking into this! Much appreciated.
Could you cook a real patch please and send it to alsa-devel? Have a look at Documentation/SubmittingPatches if that's your first submission.
Best, Daniel
participants (1)
-
Daniel Mack