Alsa-capabilities shows which digital audio formats your USB DA-converter supports

Have you ever wondered which digital audio format your Linux and alsa based music computer, for example one that runs Music Player Daemon in bit perfect / audiophile mode, is actually sending to your sound card or USB DAC when playing a high resolution digital audio file? Especially when your external DAC doesn’t indicate the sample rate or resolution of the incoming stream with LEDs or a display? Or maybe you are curious about the digital audio formats and sample rates your soundcard or USB DAC handles natively? This article and the accompanying script try to assist you with that daunting task.

The alsa-capabilities script –which can be executed on any computer running Linux and alsa– will show the available alsa interfaces for audio playback, and the digital audio formats each sound card or external USB DAC supports.

Instructions for running it straight from the web

Open a terminal screen* on the computer connected to your DAC and copy-and-paste or type the line below in the terminal screen, followed by pressing ENTER:

That’s it!

This will display a list of each alsa audio output interface with its details. When an interface is in use by another program, it will display the name and identifier (pid), so may you examine, stop or kill it, and run the script again.

The script also supports some options. For example, to display the sample rates for each encoding format supported by each USB Audio Class audio interface on your computer, run the script together with the '-l usb' (show only usb interfaces) and the '-s' (show sample rates) options:

This will output something like:

Downloading the script locally

When you want to download it to your computer, you could do the following:

Options can simply be added to the command line like in the following example, which limits the output to only devices which support USB Audio Class 1 or 2 (using -l usb) while adding the listing of supported sample rates for each supported encoding format (the -s option):

To display all options run the script with the -h option:

Opening a terminal screen

For these tasks you need to start a terminal screen on your desktop computer. Linux users may press and hold CTRL+ALT while typing T from within their desktop environment. Both users of Linux and Mac desktops may search for the text "Terminal" in their applications menu.

Windows users can use putty to perform the step below, filling in the appropriate values for username and network address in the connection screen of putty.

When your music computer is remote, you should first make a ssh-connection to that remote computer. For such an connection, you need to know the following:

  • the username and password of a user account on the remote computer, as configured by you or instructed by your manufacturer, and
  • the network address of the music computer, in the form of an ip address (ie 192.168.1.10) or a hostname (ie vortexbox).

To make a SSH connection to the linux based audio computer, first open a terminal screen, and copy-and-paste or type the line below, followed by the ENTER key:

… and fill in the proper password for the "${username}"-user when asked for, for example:

In this remote terminal screen, you may enter any command like you would do on your local computer, including the commands in the instructions above.

Watching an interface reacting on different audio formats

To see how an audio interface reacts when you play different digital audio formats, you can use the output of the script with the watch command. Replace the value of the ${monitor file} below with the name of the file displayed by the script:

Now try throwing audio files of different formats at your player and see what your digital interface makes of it.

Automated usage in scripts etc.

The script supports some features which could be handy in other scripts, like limiting the output to certain classes of audio interfaces, or interfaces with a certain name. To do this, you may use the limit option '-l' with an argument, either 'a' or 'analog', 'd' or 'digital' or 'u', 'usb' or 'uac' to only show interfaces fitting that limit. In addition, a custom regular expression filter may be specified as an argument for the 'c' option.To list only interfaces that support USB Audio Class you should execute:

Furthermore the script can be sourced. That way one may automate and store certain properties for use in other scripts or config files, like mpd-configure does. Here’s a rough example.

To see all properties that can be accessed this way see the scripts source or grep for the following:

The working of the script explained

To detect which digital interfaces your computer has, the script filters the output of the command 'aplay -l' to list interfaces which have one of the words "usb", "digital", "hdmi", "i2s", "spdif", "toslink" or "adat" in them. However, before it does that, it temporary pauses pulseaudio, which would otherwise block the interface exclusively. It then reformats the output of the "aplay" command to show a clear listing of each alsa interface, consisting of a "hw:X,Y" hardware addresses, its human readable name, the character device it uses, the digital formats it supports natively, and –in case of a USB Audio Class device, the class (1 or 2) and its stream file.

After an interface is selected, either by the script (in case of single interface) or you (in the case of multiple interfaces), the script will play random noise to the interface, in order to force alsa to display the native digital formats the interface accepts. To keep this test silent, the sound output of the interface is redirected to /dev/null.

NOTE: for this to work one should temporary stop or pause any program using that interface, like mpd. However, the script will detect and show you which processes/programs are accessing which device while performing this test, so you may abort the script and stop the listed program, using pkill ${process_name} or kill -9 ${process_id}, before re-running the script.

The output below is that of my own system, with a sound card embedded on an Intel motherboard and two USB DACs connected:

After this, the watch command may be used with the monitor file, which resides in the pseudo file system /proc, which allows for inspecting the snd_usb_audio kernel module’s parameters and their values, see the source of /tree/sound/usb. The script does this by translating the selected interface address hw:X,Y to the associated filename /proc/asound/cardX/streamY, where X is the number of the sound card and Y that of the output interface. Because this steam file is created by the kernel module, it only exists when you have interfaces that support a USB Audio Class, see the source of sound/usb/proc.c). In such cases, the file contains the actual values of the snd_usb_audio kernel module associated with the specific interface.

The script displays the changing contents of this file with a 100ms refresh rate (0.1s) using the watch command.

The script

The script is written in bash and part of my mpd-configure project hosted at github:

Contents of the alsa stream files for USB Audio Class 1 & 2 DAC’s

Alsa stream file in adaptive UAC1 mode

I used to have a Pink Faun 3.24 USB DAC, fitted with a USB Audio Class (UAC) 1 transceiver chip from Tenor. With these UAC1 devices, the communication with the host computer runs in isochronous adaptive mode, meaning the data transfer type is isochronous and the audio synchronization type adaptive. See the official USB Audio Class 2 specification “A Device Class for Audio” from the USB consortium.

The contents of the stream file /proc/asound/card0/stream0 look like this when playing a 16bit/44.1kHz CD-ripped file:

When playing a 24bit/96kHz file, the output of the file changes to the following.

Note that the Altset value has changed from 1 to 2 and Momentary freq from 44100 to 96000, indicating that the second interface (Altset = 2) is activated with a 24bit format (Format = S24_3LE) and 96kHz sample rate (Momentary freq = 96000).

The story above is summed up in the following diff:

Alsa stream file in asynchronous UAC2 mode

With UAC1 device in isochronous adaptive mode, the DAC and computer negotiate a shared sample rate, mostly using a PLL mechanism. The Momentary freq value shows the result of that negotation which should be equal to that of the file being played.

With USB Audio Class 2 in isochronous asynchronous mode, like new Pink Faun DAC2 with an Amanero(?) supports, every 125us the DAC tells the computer how many SPDIF-packets it should sent in one USB Request Block (URB).

In the output you can actually see that happening when playing high resolution files; the Momentary freq flips from 192.000Hz to something like 191.999Hz and back again.

Other differences with the UAC1 device output are:

Field UAC1 UAC2
URBs 8 64
Packet Size 582 1024
Feedback Format (non-existent) 16.16
Endpoint 3 OUT (ADAPTIVE) 5 OUT (ASYNC)
Data packet interval 1ms (1000us) 125us

The output looks like this when playing a 16bit/44.1kHz file:

It changes to the following when playing a 24bit/96kHz file:
And, finally, this is what it looks like when playing a 24bit/192kHz file:
As you can see below, this device pads each sample (with zeroes) until it fills up 32bits, regardless of the resolution of the source file. Therefore, it needs only a single AltSet and doesn’t change anything when changing from 16bit/44.1kHz to 24bit/192kHz, apart from the sampling frequency (MomentaryFreq):

Changelog

Jan 26, 2016: enhanced handling of pulseaudio:
Jan 4, 2016: Enhanced program flow and optimized display of supported sample rates for UAC type interfaces:
Jan 3, 2016: Added support for accurate but (very) slow displaying of supported sample rates for each format an interface supports:
Dec 9, 2015: Fixed a (rather long running) error in the script:
May 13, 2015: Added a lot of extra error checking:
  • modified alsa-capabilities to make the script more robust
Jan 26, 2015: Added a temporary hack to address issue #8:
  • modified alsa-capabilities to skip checking for unset variables and brake on errors
Apr 18, 2014: Major rewrite of the script:
  • moved tests/detect-alsa-output-capabilities.sh to alsa-capabilities
  • modified alsa-capabilities to make it suitable to be sourced or run by itself from the command line
  • added simple and regexp filtering to alsa-capabilities
Apr 8, 2014: Script updated:
  • added functionality to monitor non-UAC devices using its hw_params file and a few improvements in UI.
Apr 3, 2014: Small script changes and moved PCM information:
  • introduced some more bashims to make the script faster and simpler.
  • Moved the background information on the PCM format to The PCM format explained.
Apr 2, 2014: full rewrite of the script
  • to minimize user interaction and making it a bit more robust.
Mar 21, 2014: Small changes to the article:
  • Reformatted the introduction and added some technical background about the script
Mar 20, 2014: Completely rewritten the article
  • the previous version of the article assumed you already had your (default) music player set up for using a alsa hardware playback interface, which most readers are trying to figure out.
  • created a script (detect-alsa-output-capabilities.sh) to quickly list the available interfaces and supported audio formats

43 thoughts on “Alsa-capabilities shows which digital audio formats your USB DA-converter supports

  1. Hi, A wonderful script !!!!!

    One question : I have only one USB audio device
    I get
    ” – digital formats = (can’t detect: device in use”
    I have killed all programs I can think of that are using my soundcard. But I still get the “error”.

    Full output
    0) USB Audio Class Digital alsa audio output interface `hw:0,0′
    – card/device name = SB Live! 24-bit External
    – interface name = USB Audio
    – usb audio class =
    – digital formats = (can’t detect: device in use, run as root to display process.)
    – character device = /dev/snd/pcmC0D0p
    – monitor file = /proc/asound/card0/stream0

    Any ideas?

    Thanks!

    1. Did you try to run it as root like the script suggests? You might use sudo or su, like so:

      or

  2. I get the following error when running ./alsa-capabilities on a Fedora 20

    [root@localhost mpd-configure]# ./alsa-capabilities
    ./alsa-capabilities: line 189: UO_EP_LABELS[${alsa_if_uac_ep}]: unbound variable

    1. Hi Adrian,

      This problem is fixed in the latest version.

      Thanks for reporting and sorry for the inconvience.

      Regards,
      Ronald

  3. Hi.

    I experience the following error in the latest version.

    sudo bash alsa-capabilities -l u
    alsa-capabilities: line 296: UO_EP_LABELS[${alsa_if_uac_ep}]: unbound variable

    Ubuntu 14.04 LTS
    Bash 4.3.11(1)-release

    Regards,
    George

    1. Hi George,

      Sorry for the inconvenience.

      The error you’re receiving should be fixed in the latest version. To make sure you’re using the current version, could you please try to run the script like so:

      sudo bash < (wget -q -O - "http://lacocina.nl/alsa-capabilities")

      I hope this helps, otherwise could you post the output of:

      aplay -l

      Thanks,
      Ronald

      1. I get the exact same error message, just downloaded your script today. Here is my aplay -l:

        **** List of PLAYBACK Hardware Devices ****
        card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
        Subdevices: 1/1
        Subdevice #0: subdevice #0
        card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
        Subdevices: 1/1
        Subdevice #0: subdevice #0
        card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
        Subdevices: 1/1
        Subdevice #0: subdevice #0
        card 1: USB [Scarlett 2i2 USB], device 0: USB Audio [USB Audio]
        Subdevices: 1/1
        Subdevice #0: subdevice #0
        card 2: PCH [HDA Intel PCH], device 0: CS4208 Analog [CS4208 Analog]
        Subdevices: 1/1
        Subdevice #0: subdevice #0
        card 2: PCH [HDA Intel PCH], device 1: CS4208 Digital [CS4208 Digital]
        Subdevices: 1/1
        Subdevice #0: subdevice #0

        1. Canistel, confirmed that the issues still exists.

          Could you please follow the issue at:
          https://github.com/ronalde/mpd-configure/issues/11

          or, when you don’t have or want a github account, try to run the following (all one single line, followed by ENTER):

          cd /tmp/ && bash < (wget -q -O - "https://raw.githubusercontent.com/ronalde/mpd-configure/nomapfile/alsa-capabilities")

          Thanks,
          Ronald

    1. Hello Ishmael,

      Could you please post the output of aplay -l?

      Thanks and sorry for the inconvenience.
      Ronald

  4. Nice script and article, thank you! However, I had to add as “cat” in front of the monitor file’s name in order to observe my DAC’s behaviour:

    LANG=C watch -n 0.1 cat ${monitor_file}

    other wise I get a “permission denied” message concerning this file.

    How can I find out how my DAC handles dsd files, though? I can play them through mpd,
    but I’m unsure if DoP (DSD over PCM) is being used, of whether the DAC can handle the format natively (the documentation is unclear in this respect). Playing a dsd64 file the monitor file does show a sample frequency of 176400. But perhaps mpd performed some conversion already?

    1. Thanks Jürgen.

      Of course you’re right regarding the use of cat. Thanks for pointing that out.

      Regarding your DSD question, I refer to the MPD documentation on DSD support:

      “Native DSD playback is used automatically if available. DoP is only used if enabled explicitly using the dop option, because there is no way for MPD to find out whether the DAC supports it. DSD to PCM conversion is the fallback if DSD cannot be used directly.”

      Apparently “if available” is determined by support for native DSD regarding:

      1. your DAC,
      2. the alsa libraries,
      3. the alsa driver used for your DAC (snd_usb_audio) and
      4. mpd itself.

      While temporary alsa versions support common DSD encodings by default, the alsa driver (snd_usb_audio) only supports certain XMOS-receiver based DACs (see sound/usb/quirks.c). Another limitation is presented by stock mpd versions (at least up to the current 0.19.12) which only support a single DSD-format DSD-U8 (unsigned 8 bit). Apparently ‘common’ DSD files use DSD_U32LE (unsigned 32bit little endian) formats.

      To check whether the required alsa support is there (item 2), you could use the output of aplay like this:

      For item 3, you could use alsa-capabilities with the new -a hw:x,y switch as follows (remember to fill in the proper hw address:

      For item 3, and to see what the combination alsa+mpd+snd_usb_audio+DAC make of a file, you could raise the verbosity of the mpd logging to verbose, restart mpd and play a DSD file, while checking the mpd log (using watch and cat ;).

      In my test setup it indicates the following rather interesting information when playing a 24bit 192kHz file:

      To see what happens to the audio stream after mpd handles it (after the last line in the mpd log, eg output) and hands it over to alsa, you could watch the stream file for the specified alsa interface.

      In your case I suppose mpd “falls back” to DoP (maybe because the file is not encoded in DSD_U8). So to get support for (real) native DSD, you will have to use the patched mpd version at https://github.com/lintweaker/mpd-dsd-019. In your current setup, I guess mpd instructs the alsa driver to pack the 1bit DSD samples (with a rate of 2.822.400Hz) in 16bit PCM samples (in a rate of 176.400Hz).

      Hope this helps, although I must admit I’ve never had the opportunity to use or test DSD-capable hardware.

      Regards,
      Ronald

      1. Thanks for the detailed reply! I’ve just asked the manufacturer of my amp/dac how it handles DSD files. In early 2014, before the amp/dac became available, there was a suggestion that it may use DoP, but it is not specified in the technical data, as far as I can see. Recently, I have been experimenting with a new DSD-aware version of sox that includes a DoP effect, with somewhat strange results, though. Some further experiments seem to be necessary ;-)

        All the best for 2016, and keep up the good work

        — Jürgen

  5. Hello, i have X-FI HD USB card and i still don’t understand does my card support 24 bit output in ubuntu? your script shows this, please explain:

    but in stream 1 file i see Format: S24_3LE!! i’m completely frustrated, audacious can’t play 24 bit, but deadbeef can with alsa HW, but i don’t know is it 24 bit or 16 after all, please help

    1. Hi Serj,

      It seems you’re using a non-current version: could you please try it with:

      and see if S24_3LE: ... is listed as one of the formats (with ... being the samplerates)?

      Regards,
      Ronald

      1. thank you reply, did this – absolutely the same

        here is complete result

        1. Hi Serj, thanks.

          It clearly is a (regression) bug in the detection of formats and sample rates in my script (each samplerate should only be listed once).

          If the stream file of the card states Format: S24_3LE then the interface *does* support playing back 24bit files.

          The stream file indicates the current operating mode (or “altset”) for the USB device with Altset = X (third line from the top). The X refers to an Altset X (notice the absence of the equal = sign), which is fixed at a certain output encoding, indicated by the Format: XXX line.

          In your case I guess the USB receiver in the device has two “interfaces”, each with its own “altset”;

          • one with Format: S16_LE (which my script lists) and
          • one with Format: S24_3LE (which my script ignores).

          To see if it works use the following command to observe the changing AltSet = X, when you switch from playing a 16bit file to playing a 24bit file using deadbeef (configured to use hw:x,y):

          Sorry for the confusion!
          Ronald

      2. stream 1 file for card 1
        you can see S24_3LE

        1. Yup, just what I thought. See my previous comment regarding watching which operating mode/format is actually used when you play back a 24bit file.

          Ronald

        2. Serj, the problem should be solved in the latest version.

          Could you try it again and post the output of the following command::

          Thanks,
          Ronald

          1. sorry for late answer, YES now it’s OK, thank you

  6. and one question to you
    what is “feedback format”? i had 15.17, but now it’s 10.14, why has it changed? and what this digits mean? and another question how to know i have UAC1 or UAC2? thank you

    1. > “and one question to you: what is “feedback format”? i had 15.17, but now it’s 10.14, why has it changed? and what this digits mean? ”

      The digits are a representation of the Q number format, a complex way to let (embedded) DSP systems, like a USB DAC, do fixed point calculations using cheap and simple IC’s or processors, that can’t rely on floating point precision. In the linux kernel it is defined as Qfreqn.freqm where n is the “nominal sampling rate in fs/fps in Q16.16 format” and m the “momentary sampling rate in fs/fps in Q16.16 format”. The values you see in /proc/asound/cardx/stream0 represent “how much to shift the feedback value to get Q16.16” and are calculated in ./sound/usb/proc.c.

      To be short, the fact that you see a “feedback format” is another proof of the fact that your card is UAC2 capable.

      Regards,
      Ronald

        1. Hi Serj,

          Sorry for replying so late. I don’t know why it changed. Could be an updated kernel or updated firmware in the DAC.

          As far as I know it’s just a means to get proper communication between the kernel (modules) and the USB receiver inside the DAC, but I must admit I really don’t understand the implications. I would recommend asking that on the proper alsa mailing list.

          Regards,
          Ronald

          1. Hello again, thank you for answer. And again about UAC, in your script I see that my device is UAC2 compatible, but in stream files I see that it’s connected at FULL SPEED, am I understand right that it uses UAC1! if so, why it doesn’t use UAC2? In windows after installing drivers it’s connected at high speed, but I thought if it UAC2 compatible it should be native in Linux

          2. Hi Serj,

            The script uses the streamfile (eg /proc/asound/cardx/stream0 generated by ./sound/usb/proc.c) to determine the UAC type. So in your case it should state Endpoint: x OUT (ASYNC).

            As far as the source code reveals the streamfile doesn’t contain information on the USB (speed) class. Could you once again post the contents of your streamfile?

            Regards,
            Ronald

Leave a Reply

Your email address will not be published. Required fields are marked *