Issues (garbled sound) with snd_uaudio and hi-res (>48kHz) USB spdif chips

Hi list,


I’m having difficulties getting some USB audio 2.0 chips (TE8802L and CM6631A) to work reliably with FreeBSD. My setup worked perfectly for years using a Texas Instruments PCM2704(/5/6/7)-based asynchronous USB->SPDIF converter (16bit/32, 44.1 and 48kHz). I recently switched to a TEAC AI-501DA digital amplifier, which supports asynchronous 24bit/192kHz via USB through the TE8802L converter chip, but although the hardware was recognized immediately, at any sample rate the sound was garbled, no sysctl setting was of any help. There are no gaps in the music but everything sounds extremely metallic, pitches are all messed up as if the data sample rate doesn’t match the output rate.

As a way out I bought a cheap CM6631A (other USB->SPDIF chip) based convertor board from eBay, to feed the TEAC receiver SPDIF over coax, but the distorted sound was just the same. I tried it on different hardware, different cables etc., but the problem really seems to be with how the FreeBSD uaudio drivers interact with these chips (Mac OSX plays the music just fine, up to 192kHz).

I did some debugging on the CM6631A converter as this one gave me direct access to the SPDIF signal (the TE8802L is embedded in the TEAC, I can only judge it by listening). The information that follows all relates to the CM6631A:

My computer is a small ALIX 3D2 (AMD Geode) board running FreeBSD 10.2 as a read-only system. Sound is outputted either from audio/musicpd (OSS) or shairport-sync (ALSA->OSS), but for testing I mostly used multimedia/mplayer. I use the USB-SPDIF converters in bitperfect mode and without vchans, as there never is more than one audio source and I don’t use mixing or volume control. The hardware *should* just support any input from 16 to 24 bit and from 8000 Hz to 192kHz sample rate.
I had the impression that not using vchans helps for now in getting to the root of the problem.


Dmesg and sysctl settings are printed below.


Interestingly, when hooking up an oscilloscope to the spdif output, I noticed that the converter (CM6631A) always outputs a 48kHz signal, no matter what sample rate is rooted to the chip. Picture here: https://www.dropbox.com/s/ugb9jurqv4d7ywv/48kHz.JPG?dl=0
Thus when I play 32kHz, 44.1 kHz or 96 kHz files, FreeBSD tells me that these sample rates are correctly sent to the converter (monitored with cat /dev/sndstat with verbosity 2), but the oscilloscope just keeps showing 48kHz. Not surprisingly the music sounds fine when a 48kHz file is played, all other rates result in garbled output.

I played around with the usual sysctl settings, most notably
Code:
hw.usb.uaudio.default_rate
hw.snd.report_soft_formats
but without succes, the observed spdif output remains at 48kHz.


While playing with the sysctl’s, I did notice the variable
Code:
dev.pcm.0.feedback_rate

which returns reasonable values (a few bits/second too much or too many), but always around 48000, even when playing 44.1kHz files. But when playing a 32kHz file, dev.pcm.0.feedback_rate jumps between either 48000 and 24000 (!), and nothing in between. Playing a 96kHz file gives a feedback value around 96000 (but with garbled sound), but playing a 88.2kHz file also gives 96000 (and garbled sound). It seems that this feedback value only goes in steps of 24000.

For comparison, the TE8802L (of which I can’t monitor the spdif output) seems a bit more flexible but also gives dev.pcm.0.feedback_rate values which jump +/- 8000 around the desired value, with resulting garbled sound output.

I’m not sure what the variable is supposed to return but something doesn’t seem correct here.


The desired behaviour would be that music files are sent in their native bit format and sample rate to the converter, with the chips autodetecting the sample rate for the spdif clock (re)generation. This is what FreeBSD does very well with my old PCM2704 converter: when playing a 44.1kHz file after a 48kHz one I can see the clock frequency of the spdif signal getting adjusted on the oscilloscope screen. (by the way, the PCM2704 always returns 0 for dev.pcm.0.feedback_rate).

It should be possible to have these newer chips working at different sample rates, here is the spdif signal of the CM6631A playing 96kHz and 192kHz files just fine on OSX, as verified with the oscilloscope:
https://www.dropbox.com/s/rrk7qe0it3i83nt/96kHz.JPG?dl=0
https://www.dropbox.com/s/9ie19gq4nanjwth/192kHz.JPG?dl=0


To make a long story short, is there something wrong with how the supported sample rates are being detected on FreeBSD?



Thanks!


Tiemen

uname -a:
Code:
FreeBSD zolder.X.X 10.2-RELEASE FreeBSD 10.2-RELEASE #0 r286666: Wed Aug 12 19:31:38 UTC 2015     root@releng1.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC  i386

/etc/sysctl.conf settings:
Code:
dev.pcm.0.bitperfect=1
hw.snd.maxautovchans=0
dev.pcm.0.play.vchans=0
hw.snd.verbose=2


dmesg output when attaching CM6631A chip:
Code:
ugen1.2: <C-Media Electronics Inc.> at usbus1
uaudio0: <C-Media Electronics Inc. USB2.0 High-Speed True HD Audio, class 239/2, rev 2.00/2.08, addr 2> on usbus1
uaudio0: Play: 384000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 352800 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 192000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 176400 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 96000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 88200 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 88000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 80000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 72000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 64000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 56000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 48000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 44100 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 40000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 32000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 24000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 22050 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 16000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 11025 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: Play: 8000 Hz, 2 ch, 32-bit S-LE PCM format, 2x8ms buffer.
uaudio0: No recording.
uaudio0: No MIDI sequencer.
pcm0: <USB audio> on uaudio0
uaudio0: HID volume keys found.

cat /dev/sndstat output when playing a 32bit/96kHz file (resulting in garbled sound):
Code:
FreeBSD Audio Driver (32bit 2009061500/i386)
Installed devices:
pcm0: <USB audio> at ? kld snd_uaudio (1p:0v/0r:0v) default
    snddev flags=0x200003e7<SIMPLEX,AUTOVCHAN,SOFTPCMVOL,BUSY,MPSAFE,REGISTERED,BITPERFECT,VPC,PRIO_WR>
    [pcm0:play:dsp0.p0]: spd 96000, fmt 0x00201000, flags 0x2000010c, 0x00000001, pid 2494 (mplayer)
    interrupts 1387, underruns 0, feed 1386, ready 109512 [b:12288/6144/2|bs:131072/4096/32]
    channel flags=0x2000010c<RUNNING,TRIGGERED,BUSY,BITPERFECT>
    {userland} -> feeder_root(0x00201000) -> {hardware}

trying to play a (16bit/44.1kHz) CD audio file through mplayer gives:
Code:
[AO OSS] Can't set audio device /dev/dsp to s16le output, trying s16le...

... but stops complaining when forcing it in 32bit mode at the same 44.1kHz (sound still garbled), through mplayer's -format s32le flag; cat /dev/sndstat then gives:
Code:
FreeBSD Audio Driver (32bit 2009061500/i386)
Installed devices:
pcm0: <USB audio> at ? kld snd_uaudio (1p:0v/0r:0v) default
    snddev flags=0x200003e7<SIMPLEX,AUTOVCHAN,SOFTPCMVOL,BUSY,MPSAFE,REGISTERED,BITPERFECT,VPC,PRIO_WR>
    [pcm0:play:dsp0.p0]: spd 44100, fmt 0x00201000, flags 0x2000010c, 0x00000001, pid 2513 (mplayer)
    interrupts 452, underruns 0, feed 451, ready 127056 [b:5648/2824/2|bs:131072/4096/32]
    channel flags=0x2000010c<RUNNING,TRIGGERED,BUSY,BITPERFECT>
    {userland} -> feeder_root(0x00201000) -> {hardware}

Finally some usbconfig output (this is the CM6631A):

usbconfig -d ugen1.2 dump_device_desc dump_curr_config_desc

Code:
ugen1.2: <USB2.0 High-Speed True HD Audio C-Media Electronics Inc.> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (100mA)



  bLength = 0x0012 

  bDescriptorType = 0x0001 

  bcdUSB = 0x0200 

  bDeviceClass = 0x00ef  <Miscellaneous device>

  bDeviceSubClass = 0x0002 

  bDeviceProtocol = 0x0001 

  bMaxPacketSize0 = 0x0040 

  idVendor = 0x0d8c 

  idProduct = 0x0004 

  bcdDevice = 0x0208 

  iManufacturer = 0x0001  <C-Media Electronics Inc.>

  iProduct = 0x0002  <USB2.0 High-Speed True HD Audio>

  iSerialNumber = 0x0000  <no string>

  bNumConfigurations = 0x0001 





 Configuration index 0



    bLength = 0x0009 

    bDescriptorType = 0x0002 

    wTotalLength = 0x012a 

    bNumInterfaces = 0x0003 

    bConfigurationValue = 0x0001 

    iConfiguration = 0x0000  <no string>

    bmAttributes = 0x00c0 

    bMaxPower = 0x0032 



    Additional Descriptor



    bLength = 0x08

    bDescriptorType = 0x0b

    bDescriptorSubType = 0x00

    RAW dump: 

    0x00 | 0x08, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00





    Interface 0

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0000 

      bAlternateSetting = 0x0000 

      bNumEndpoints = 0x0001 

      bInterfaceClass = 0x0001  <Audio device>

      bInterfaceSubClass = 0x0001 

      bInterfaceProtocol = 0x0020 

      iInterface = 0x0000  <no string>



      Additional Descriptor



      bLength = 0x09

      bDescriptorType = 0x24

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x09, 0x24, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x01, 

      0x08 | 0x00



      Additional Descriptor



      bLength = 0x11

      bDescriptorType = 0x24

      bDescriptorSubType = 0x02

      RAW dump: 

      0x00 | 0x11, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x12, 

      0x08 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 

      0x10 | 0x00



      Additional Descriptor



      bLength = 0x0c

      bDescriptorType = 0x24

      bDescriptorSubType = 0x03

      RAW dump: 

      0x00 | 0x0c, 0x24, 0x03, 0x07, 0x01, 0x03, 0x00, 0x0d, 

      0x08 | 0x12, 0x04, 0x00, 0x00





      Additional Descriptor



      bLength = 0x12

      bDescriptorType = 0x24

      bDescriptorSubType = 0x06

      RAW dump: 

      0x00 | 0x12, 0x24, 0x06, 0x0d, 0x01, 0x03, 0x00, 0x00, 

      0x08 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 

      0x10 | 0x00, 0x00





      Additional Descriptor



      bLength = 0x08

      bDescriptorType = 0x24

      bDescriptorSubType = 0x0a

      RAW dump: 

      0x00 | 0x08, 0x24, 0x0a, 0x12, 0x03, 0x07, 0x00, 0x00





    Endpoint 0

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x008f  <IN>

        bmAttributes = 0x0003  <INTERRUPT>

        wMaxPacketSize = 0x0006 

        bInterval = 0x0004 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 





    Interface 1

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0001 

      bAlternateSetting = 0x0000 

      bNumEndpoints = 0x0000 

      bInterfaceClass = 0x0001  <Audio device>

      bInterfaceSubClass = 0x0002 

      bInterfaceProtocol = 0x0020 

      iInterface = 0x0004  <Speaker>





    Interface 1 Alt 1

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0001 

      bAlternateSetting = 0x0001 

      bNumEndpoints = 0x0002 

      bInterfaceClass = 0x0001  <Audio device>

      bInterfaceSubClass = 0x0002 

      bInterfaceProtocol = 0x0020 

      iInterface = 0x0000  <no string>



      Additional Descriptor



      bLength = 0x10

      bDescriptorType = 0x24

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x10, 0x24, 0x01, 0x01, 0x05, 0x01, 0x01, 0x00, 

      0x08 | 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00





      Additional Descriptor



      bLength = 0x06

      bDescriptorType = 0x24

      bDescriptorSubType = 0x02

      RAW dump: 

      0x00 | 0x06, 0x24, 0x02, 0x01, 0x02, 0x10





    Endpoint 0

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0005  <OUT>

        bmAttributes = 0x0005  <ASYNC-ISOCHRONOUS>

        wMaxPacketSize = 0x00c8 

        bInterval = 0x0001 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 



      Additional Descriptor



      bLength = 0x08

      bDescriptorType = 0x25

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x08, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00





    Endpoint 1

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0085  <IN>

        bmAttributes = 0x0011  <ISOCHRONOUS>

        wMaxPacketSize = 0x0004 

        bInterval = 0x0004 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 





    Interface 1 Alt 2

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0001 

      bAlternateSetting = 0x0002 

      bNumEndpoints = 0x0002 

      bInterfaceClass = 0x0001  <Audio device>

      bInterfaceSubClass = 0x0002 

      bInterfaceProtocol = 0x0020 

      iInterface = 0x0000  <no string>



      Additional Descriptor



      bLength = 0x10

      bDescriptorType = 0x24

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x10, 0x24, 0x01, 0x01, 0x05, 0x01, 0x01, 0x00, 

      0x08 | 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00





      Additional Descriptor



      bLength = 0x06

      bDescriptorType = 0x24

      bDescriptorSubType = 0x02

      RAW dump: 

      0x00 | 0x06, 0x24, 0x02, 0x01, 0x03, 0x18





    Endpoint 0

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0005  <OUT>

        bmAttributes = 0x0005  <ASYNC-ISOCHRONOUS>

        wMaxPacketSize = 0x012c 

        bInterval = 0x0001 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 



      Additional Descriptor



      bLength = 0x08

      bDescriptorType = 0x25

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x08, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00





    Endpoint 1

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0085  <IN>

        bmAttributes = 0x0011  <ISOCHRONOUS>

        wMaxPacketSize = 0x0004 

        bInterval = 0x0004 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 





    Interface 1 Alt 3

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0001 

      bAlternateSetting = 0x0003 

      bNumEndpoints = 0x0002 

      bInterfaceClass = 0x0001  <Audio device>

      bInterfaceSubClass = 0x0002 

      bInterfaceProtocol = 0x0020 

      iInterface = 0x0000  <no string>



      Additional Descriptor



      bLength = 0x10

      bDescriptorType = 0x24

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x10, 0x24, 0x01, 0x01, 0x05, 0x01, 0x01, 0x00, 

      0x08 | 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00





      Additional Descriptor



      bLength = 0x06

      bDescriptorType = 0x24

      bDescriptorSubType = 0x02

      RAW dump: 

      0x00 | 0x06, 0x24, 0x02, 0x01, 0x04, 0x20





    Endpoint 0

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0005  <OUT>

        bmAttributes = 0x0005  <ASYNC-ISOCHRONOUS>

        wMaxPacketSize = 0x0190 

        bInterval = 0x0001 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 



      Additional Descriptor



      bLength = 0x08

      bDescriptorType = 0x25

      bDescriptorSubType = 0x01

      RAW dump: 

      0x00 | 0x08, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00





    Endpoint 1

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0085  <IN>

        bmAttributes = 0x0011  <ISOCHRONOUS>

        wMaxPacketSize = 0x0004 

        bInterval = 0x0004 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000 



      Additional Descriptor



      bLength = 0x08

      bDescriptorType = 0x0b

      bDescriptorSubType = 0x02

      RAW dump: 

      0x00 | 0x08, 0x0b, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00







    Interface 2

      bLength = 0x0009 

      bDescriptorType = 0x0004 

      bInterfaceNumber = 0x0002 

      bAlternateSetting = 0x0000 

      bNumEndpoints = 0x0001 

      bInterfaceClass = 0x0003  <HID device>

      bInterfaceSubClass = 0x0000 

      bInterfaceProtocol = 0x0000 

      iInterface = 0x0000  <no string>



      Additional Descriptor



      bLength = 0x09

      bDescriptorType = 0x21

      bDescriptorSubType = 0x00

      RAW dump: 

      0x00 | 0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, 0x32, 

      0x08 | 0x00



    Endpoint 0

        bLength = 0x0007 

        bDescriptorType = 0x0005 

        bEndpointAddress = 0x0084  <IN>

        bmAttributes = 0x0003  <INTERRUPT>

        wMaxPacketSize = 0x0010 

        bInterval = 0x0004 

        bRefresh = 0x0000 

        bSynchAddress = 0x0000
 
Following up on myself (previous post was way too long, sorry...)

I meanwhile changed to a more powerful computer because generating debug output with the sysctl hw.usb.uaudio.debug choked the little Alix board.

With the CM6631A, setting hw.usb.uaudio.debug=2 and playing a 32bit/44.1kHz file generates a lot of lines like this:
Code:
uaudio_hid_rx_callback: actlen=16
uaudio_hid_rx_callback: actlen=16
uaudio_hid_rx_callback: actlen=16
uaudio_chan_play_sync_callback: Value = 0x00060200
uaudio_chan_play_sync_callback: Comparing 48062 Hz :: 44100 Hz
uaudio_hid_rx_callback: actlen=16
note the comparison between 48 and 44.1kHz.

idem dito for a 32bit/88.2kHz file:
Code:
uaudio_chan_play_sync_callback: Value = 0x0005fe00
uaudio_chan_play_sync_callback: Comparing 95875 Hz :: 88200 Hz

This is not good, right?

Attached is the debug output when plugging the usb device out and in (long output)
There's a lot of
Code:
uaudio_chan_fill_info_sub: Wrong number of channels
being repeated.

I hope this makes it more clear
 

Attachments

  • CM6631A-debug.txt
    25.2 KB · Views: 466
Back
Top