September 5, 2012

Audio output selection under Linux on i.MX6

Our i.MX6 boards (Sabre Lite and Nitrogen6X) are the first boards we’ve produced with completely separate output channels (HDMI and SGTL5000), and we’ve been mostly ignoring the question of how to configure this until now.

Under Ubuntu, the “Sound” control panel applet allows you to choose between the two outputs.

Under Android, there’s a setting in init.freescale.rc that we’ve been setting to force output over the SGTL5000:
    # hdmi audio output
    setprop ro.HDMI_AUDIO_OUTPUT 0
But how and where do you make the decision under Linux? This is a question we’ve mostly ignored, but now have some answers to share.

First of all, if you look in /proc/asound/cards, you’ll see that the SGTL5000 is card number 0 and the HDMI audio channel is card number 1:
root@freescale ~$ cat /proc/asound/cards
 0 [sgtl5000audio  ]: sgtl5000-audio - sgtl5000-audio
 1 [imxhdmisoc     ]: imx-hdmi-soc - imx-hdmi-soc

If you’re using aplay, you can use the -c flag on some Linux releases:
# to play on the SGTL5000
~$ aplay -c 0 Blackbird.wav
# to play on the HDMI audio channel
~$ aplay -c 1 Blackbird.wav

On other Linux releases (including 12.09-GA), the -c option is the number of channels, and you’ll need to use -D to specify the device like so:
# to play on the SGTL5000
~$ aplay -D hw:0,0 Blackbird.wav
# to play on the HDMI audio channel
~$ aplay -D hw:1,0 Blackbird.wav

If you’re using gstreamer, you can use this card numbering to tell the alsasink element which card to use:
# play on SGTL5000
~$ gst-launch filesrc location=BlackBird2.mp3 ! 
   queue max-size-time=0 ! mfw_mp3decoder ! 
   audioconvert ! 'audio/x-raw-int, channels=2' ! 
   alsasink device='hw:0,0'
# play on HDMI
~$ gst-launch filesrc location=BlackBird2.mp3 ! 
   queue max-size-time=0 ! mfw_mp3decoder ! 
   audioconvert ! 'audio/x-raw-int, channels=2' ! 
   alsasink device='hw:1,0'

Finally, for a poor-man’s surround-sound, you can output to both channels by introducing a tee:
~/$ gst-launch filesrc location=BlackBird2.wav  ! wavparse 
               ! tee name=both 
               ! queue ! autoaudiosink both. 
               ! queue ! audioconvert ! alsasink device="hw:1,0"

There’s a lot more to this story, but we hope this gets you pointed in the right direction.

Comments 33

  1. Post

    On more recent versions of gstreamer, the alsasink element expects the device
    to be specified using the plughw keyword.

          ~/$ #  play file 0mi2.wav on sgtl5000
          ~/$ gst-launch filesrc location=/root/mp3/0mi2.wav 
                        ! wavparse ! alsasink device=plughw:0,0
          ~/$ #  play file 0mi2.wav on HDMI
          ~/$ gst-launch filesrc location=/root/mp3/0mi2.wav 
                        ! wavparse ! alsasink device=plughw:1,0
    1. Louis Koziarz


      Have you noticed strange output on the headphone jack of the 6Q SABRE Lite board when powering up?

      When I have earbuds plugged into this port and power on, there’s a howl that comes off the SGTL5000 until the kernel has a chance to initialize the chip.


  2. Francois

    When I look in /proc/asound/cards, on my sabreLite, I see that :

    # cat /proc/asound/cards
     0 [sgtl5000audio  ]:  - sgtl5000-audio
     1 [imxhdmisoc     ]:  - imx-hdmi-soc

    When I try the audiotest on the SGTL5000 it works but It doesn’t work on hdmi, I have this message

    # gst-launch audiotestsrc ! alsasink device='hw:1,0'
    Setting pipeline to PAUSED ...
    ERROR: Pipeline doesn't want to pause.
    ERROR: from element /GstPipeline:pipeline0/GstAlsaSink:alsasink0: Could not open audio device for playback.
    Additional debug info:
    gstalsasink.c(694): gst_alsasink_open (): /GstPipeline:pipeline0/GstAlsaSink:alsasink0:
    Playback open error on device 'hw:1,0': No such file or directory
    Setting pipeline to NULL ...
    Freeing pipeline ...

    How can I solve this problem ?

    1. Post
  3. Francois

    It doesn’t work too.
    It works with plughw:0,0, but not with plughw:1,0

    # gst-launch audiotestsrc ! alsasink device=’plughw:1,0′
    Setting pipeline to PAUSED …
    ERROR: Pipeline doesn’t want to pause.
    ERROR: from element /GstPipeline:pipeline0/GstAlsaSink:alsasink0: Could not open audio device for playback.
    Additional debug info:
    gstalsasink.c(694): gst_alsasink_open (): /GstPipeline:pipeline0/GstAlsaSink:alsasink0:
    Playback open error on device ‘plughw:1,0′: No such file or directory
    Setting pipeline to NULL …
    Freeing pipeline …

  4. Vasan

    Hi Eric,

    Does the SL have SGTL jack sense detection support (both plugging in and plugging out) available?


    1. Post

      Hi Vasan,

      Unfortunately, no. It doesn’t appear that the SGTL supports this, and we don’t have a GPIO connected which allows this.

  5. Viktor

    Hi Eric,

    I am trying to plug a high-end DAC into the USB port of the Nitrogen6_Lite. This doesn’t seem to be working. In the /proc/asound/cards I still see only the SGTL5000 device. Is there a way to tell the system that there is another audio device?
    And another related question: what are the caracteristics of the HDMI audio? I dont see the HDMA audio device in the /proc/asound/cards because I don’t have anything plugged it. But if I am to purchase an HDMI audio extractor, will the audio on the HDMI channel be of high quality?
    I am playing lossless sound with 24 bit precision at192kHz sampling rate. The SGTL5000 chip can only reproduce 44.1kHz, so the driver is downsampling. So I want to get the full audio quality from the board. At the moment I see 2 solutions – using external DAC or using HDMI extractor. The HDMI extractor is a cheaper solution and also would probably work, while the DAC is more expensive and might not work in foreseable future (as it’s not working at the present). But in order to use the HDMI I want to be sure that it will send the bit-perfect sound. How can I verify that this would be the case?

    1. Post

      Hi Viktor,

      To use an external (USB) DAC, you’ll need to get the driver and compile the associated module. We limit the number of drivers to the core needed to test the hardware in our default configurations and images.

      Using the HDMI audio channel without video will also likely be a challenge because the clocking for it is driven (derived from) the video clock.

  6. Viktor

    Hi Eric,
    Thank you for the fast response.
    So, in the examples above (in the main text) when you show how to play audio on the HDMI channel, that presumes that there is a video device plugged in and a video signal is being sent to it. In other words, even if I have some device plugged to the HDMI port (e.g. an audio extractor) it will not work unless I am also sending the video there. Presumably that could be just the desktop, but still there has to be some video.
    Please correct me if I am wrong.
    Regarding the driver for USB DAC – do I have to add the driver to the kernel and recompile it, or that could be a driver which get’s installed later? Where to find more information about this?
    Also, is the USB bus on the Nitrogen fast enough to support 192 kHz audio?
    Generally I already have an external DAC driven by a Raspberry Pi and by a Cubie board, but the first one is not fast enought for 192kHz audio and the second can play the audio, but cannot drive the GUI in the same time.
    The Nitrogen board has enough power to play high end audio and present a beautiful GUI in the same time and therefore makes a natural choice for my project. Plus I am already familiar with the device and have made some progress in getting the other components (like touchscreen) to work. I would like to create a product based on the Nitrogen board (I could look into the 4 core board too, if it would do the job).

    1. Post

      Hi Viktor,

      1.) HDMI requirement: The primary requirement is that the HDMI output clock be configured. It doesn’t have to actually display anything (it could be a secondary and blank display), but it will need to negotiate a video mode using EDID, so you’d need an I2C ROM connected to the EDID pins somehow. IOW, it’s a hassle.

      2.) Kernel driver for external DAC: Yes. You’ll need to find a DAC with a driver supported by the kernel (or add one to the kernel sources), then select it using ‘menuconfig’ and re-compile the kernel. The driver itself can be either compiled into the kernel (uImage) or loaded from a .ko file.

      3.) USB Bandwidth: The USB Host and OTG port both support high-speed (480Mbps) mode, so you should have plenty of bandwidth for even 5.1 32-bit 192k audio. This is true of the Solo, Dual-Lite, and of course, Quad-core versions of Nitrogen6X.

  7. Andre

    Hi Eric,
    I have the IMX6 it came with android and by default there is no audio on the HDMI output, and
    nano or vi is not there to edit init.freescale.rc
    I had tried this command
    root@nitrogen6x:/ # setprop ro.HDMI_AUDIO_OUTPUT 0
    root@nitrogen6x:/ # setprop ro.HDMI_AUDIO_OUTPUT 1
    root@nitrogen6x:/ # wl1271: unloaded
    cat /proc/asound/cards
    0 [sgtl5000audio ]: sgtl5000-audio – sgtl5000-audio
    1 [imxhdmisoc ]: imx-hdmi-soc – imx-hdmi-soc

    what would you recommend to get audio out of HDMI?


  8. Andre

    the audio works if I play a movie and pause it and type
    setprop sys.hdmi 1
    but after I reboot the board it stops working, so I have to do the same while I play the movie and I pause it

    1. Post

      Right. The setprop command isn’t persistent.

      I think that you can change this in build.prop, though as you mentioned, there’s no editor installed.

      We typically use adb pull and adb push.

      Note that you’ll need to remount /system as read-write:

      # mount -o remount,rw /system
  9. Mario


    I would like to know what are the audio input and output formats supported (I mean natively supported by the DAC). Where can I find this information?


    1. Post
  10. ericn

    Note that in recent versions of Android, the sys.hdmi property is used as a flag to use the HDMI audio channel, so to route audio to the HDMI port, you’d do this:

    root@nitrogen6x:/ # setprop sys.hdmi 1

    And this to route audio to the SGTL5000:

    root@nitrogen6x:/ # setprop sys.hdmi 0
  11. edsut

    I’m working with the SGTL5000 audio output on Nitrogen6-Max (kernel 3.10.53). Using the following line: “aplay -D plughw:0,0 audiofile.wav”, I get no output from either of the speakers (note: if i plug in the headphones I do get something from one channel).
    Looking at the schematic, I see there is a MUTE control through ENET_TXD1 pin. I assume the intent is to configure that pin as GPIO output to drive the MUTE logic into the amplifier. Probing the U30 SDR/SDL (active low) lines, they are low and based on the datasheet for the TPA2012D2 that means both channels are muted; so it makes sense that there is no audio out of the speakers.
    Still, I’m a bit hesitant to do anything with the MUTE pin gpio because it appears that if MUTE is high and HEADP_DET is low, there is a conflict between MUTE and the ‘Y’ output of the AND gate (U54)…
    Am I missing something?

      1. edsut

        I managed to get things to work, but I had to remove U54 (the AND gate). I’d like to find out if you folks agree with this modification.

      2. edsut

        Hi Laci,
        In addition to removing U54, I had to set GPIO29 to pull the amplifier channels out of shutdown (un-mute)…
        if [ ! -d /sys/class/gpio/gpio29 ]
        echo “Creating /sys/class/gpio/gpio29…”
        echo 29 >/sys/class/gpio/export
        echo out >/sys/class/gpio/gpio29/direction
        echo 1 >/sys/class/gpio/gpio29/value


        1. Laci Tele

          Hi Ed,
          Hmmm. Maybe an easier way to do it.
          I got Nitro-Max on my desk and its working without removing any parts of it.

          If you want to select HDMI audio type :

          $ hdmi-on

          If you want to select sgtl chip (jack plug) then type :
          $ sgtl-on

          These settings are system wide, and persistent (remain valid after rebooting)

          You can check the end of the file /home/ubuntu/.bashrc , and you’ll undertand whats happening.

          1. edsut

            Thanks for responding, but you’re using the audio outputs I’m referring to. Note that it works for me as well with hdmi-out and the jack-plug. I’m trying to use the speakers that are tied to the audio amplifier (J27 & J28). Referring to the Rev3 schematic, the MUTE line (GPIO29) is used to pull the amplifier out of shutdown.
            I believe there is a conflict between the GPIO output and the output of the AND gate U54. Can you check on that?

          2. edsut

            I mistyped the first sentence in my previous reply…
            There’s a critical ‘not’ missing. :-)

            You’re ‘not’ using the same audio output I’m using.


        2. Laci Tele

          “You’re ‘not’ using the same audio output I’m using….”

          Aww, OK sorry. I never used that output, I have to take a look at schematics. Or maybe a HW guy should see your question.
          Give me some time please.

  12. edsut

    Continuation of my previous comment…
    Note that I am using Rev 3 hardware.
    Referring to the schematic, I see that U54 and R205 are both marked ‘NS’ (I assume that means ‘not stuffed’). On my board, R205 is infact not on the board but U54 is populated. My guess is that either U54&R205 should be populated or R226 should be populated (but never U54 & R226); however that’s not the case; hence my concern regarding the output conflict.
    So, it seems to me that the zero-ohm resistor R226 should be moved to R205, making R226 the ‘NS’ part and allowing U54&R205 to support the MUTE logic gated with HEADP_DET. Does that make sense?

  13. edsut

    I just updated my kernel to 3.14.28 (branch boundary-imx_3.14.28_1.0.0_ga), and I am no longer able to access /sys/class/gpio/export so that I can unmute the speakers.
    As superuser I run:
    root@nitrogen:/home/ubuntu# echo 29 >/sys/class/gpio/export
    bash: echo: write error: Device or resource busy

    I need to set GPIO29 to output, value =1 to unmute the speakers.
    Is this done some other way with the new kernel?

      1. edsut

        Yes, I see the code (I put some additional printk’s in there to debug it), but I can’t hear anything through the speakers. Can you confirm that this works with speakers that go through the power amp (using J27 & J28)? I’m working with a brand-new board, running 3.14.28 but not having any luck with audio out through the speakers just running “as is” (not touching gpio29).
        I use aplay and I hear audio through the headphones regardless of whether I mute (or not) the headphone playback in alsamixer.

          1. edsut

            Ok, got it thanks.
            One more issue you may or may not care about…
            In the imx-sgtl5000.c file, I added a few extra pr_info() calls to see what was going on.
            Specifically, in the function init_gpio_data(), I added a message to print if gpio_is_valid() came back false…
            The function imx_sgtl5000_probe makes this call. On the first call the GPIO is 29 and its true; however on the second call, the GPIO is -2 (invalid).

  14. edsut

    More observations on this audio issue…
    Referring to the AUDIO page of the Nitrogen6-MAX schematic…
    The logic provided by U54 does this (in English):
    If MUTE or HEADP_DET is low, the the speaker outputs (through the power amp) are shutdown.
    I put a probe on pin #1 of U54 (MUTE) and then issue an aplay command using the card associated with the sgtl5000 as the device. I see that pin is pulled low during the audio output. This has no harmful effect if headphones are used (cause the plug connection already mutes the spkr); however, if I’m trying to use the speakers, they are being muted through GPIO29 (MUTE) incorrectly.

    There really is no need to even touch gpio29/mute except to to pull it high at startup so that by default the speaker is not muted. If the headphones are plugged in, the plug connection will automatically cause the speaker outputs (through the power amp) to be muted.

    Does that make sense?

Leave a Reply