Author: Mugabi Siro

Category: QEMU

Summary:

Examples of configuring QEMU audio. References to QEMU sources are with respect to the root of the source tree. QEMU v2.2.0 used for reference.

Tags: qemu linux alsa

Linux Audio

The Advanced Linux Sound Architecture (ALSA) project was started around the year 1998 by Jarslav Kysela. It has been the official/core Linux audio subsystem since v2.6. It replaced the the Open Sound System (OSS) which was the major Linux sound system during the v2.4 era.

A number of audio application/development libraries and sound servers are also available. These facilities generally sit on top of the ALSA library. Application libraries include the Simple DirectMedia Layer (SDL) which is a cross-platform development framework that supports GNU/Linux as well as other operating systems. Sound servers manage resources exported by ALSA lib and control sound flows between applications. Examples include the Enlightened Sound Daemon a.k.a esound (esd) for Gnome (designed to support desktop event sounds and lightweight game support) and PulseAudio by Lennart Poettering. PulseAudio is the default sound server for a number GNU/Linux distros including Fedora (since version 8) and Ubuntu (since 8.04).

More information about Linux Audio can be found @ Linux Sound

QEMU-Linux Audio Architecture

To provide audio support for the virtual machine, QEMU includes a number of programs, i.e. backends, that operate on the Linux audio facilities mentioned above. Audio data (PCM) from the QEMU virtual devices (i.e. the emulated soundcards) is routed through these backend programs to the interfaces exported by the audio libraries or sound servers on the host - and vice versa. These backend programs are what are referred to as audio drivers in QEMU parlance.

QEMU-Linux Audio Arch

With respect to the Linux audio facilities described in section Linux Audio, QEMU includes audio driver (or backend) support for ALSA lib (alsa), OSS (oss), SDL (sdl), PulseAudio (pa), etc.

QEMU Audio Config and Build

By default, QEMU currently builds with OSS only backend support. Including support for other Linux audio facilities requires explicit specification on configure's command line. The list of available backend audio drivers can be obtained by, say, running configure with:

$ ./configure --audio-drv-list=?

ERROR: Unknown driver '?' selected
     Possible drivers are: oss alsa sdl esd pa fmod

For example, to only include ALSA and SDL support:

$ ./configure --audio-drv-list=alsa,sdl [...]
  • NOTE: The order in which the audio drivers are specified against --audio-drv-list= influences QEMU-Audio behaviour when selecting the default audio backend at runtime. More details in Section Testing:Host-Side.

In this case, after a successful build, the CONFIG_AUDIO_DRIVERS definition in the config-host.h file (generated during build) should resemble:

$ make [-jN]

$ cat config-host.h
...
 #define CONFIG_AUDIO_DRIVERS \
     &alsa_audio_driver,\
     &sdl_audio_driver,\
...

where: alsa_audio_driver, sdl_audio_driver, etc, are of type struct audio_driver (see audio/audio_int.h). These structures contain the necessary information - including the initialization functions - for the respective backend audio drivers. This definition, CONFIG_AUDIO_DRIVERS, is part of the drvtab array (see audio/audio.c):

/* audio/audio.c */

46 static struct audio_driver *drvtab[] = {
47 #ifdef CONFIG_SPICE
48     &spice_audio_driver,
49 #endif
50     CONFIG_AUDIO_DRIVERS
51     &no_audio_driver,
52     &wav_audio_driver
53 };

During QEMU startup, the audio/audio.c:audio_init() function loops over the elements of the drvtab[] array, performing string matches in order to determine the user specified audio driver and invoke the appropriate audio backend initialization function via audio/audio.c:audio_driver_init():

static void audio_init (void)
{
    ...
    drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
    ...
    for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
        if (!strcmp (drvname, drvtab[i]->name)) {
            done = !audio_driver_init (s, drvtab[i]);
            found = 1;
            break;
        }
    }
    ...

Pay special attention to the QEMU_AUDIO_DRV QEMU environment variable. It is used to specify the name of the required audio driver during QEMU launch.

  • NOTE: Omitted in the snippet above is code that handles default/specified audio backend initialization failure. Section Testing:Host-Side includes a few examples that illustrate QEMU-Audio behaviour as defined by this error handling code.

QEMU Audio Runtime

QEMU Audio Device Command line

  • -soundhw vs. -device

    Citing docs/qdev-device-use.txt, the -soundhw C1,... command line option (where C1, C2, ..., indicate names of emulated audio devices) for specifying the guest audio devices is legacy. The new way is to specify each guest audio device separately with -device. Examples:

    -device ES1370
    -device gus,iobase=IOADDR,irq=IRQ,dma=DMA,freq=F
    -device intel-hda,msi=MSI -device hda-duplex
    

    Consider the following command line for an audio interface on the PCI bus:

    $ qemu-system-x86_64 [...] -device ich9-intel-hda -device hda-duplex
    

    where:

    • -device ich9-intel-hda specifies the audio controller on the I/O Controller Hub (ICH).
    • -device hda-duplex specifes a H/W Codec device for the audio controller.

    In this example, the codec is connected to the audio controller via the High Definition Audio (HDA) bus. The codec device is the actual I/O component of this PCI audio interface. For instance, if no codec device is specified, then the system will report something similar to the following upon system boot:

    $ lspci -s 00:04.0 -k
    00:04.0 Audio device: Intel Corporation 82801I (ICH9 Family) HD Audio Controller (rev 03)
      Subsystem: Red Hat, Inc QEMU Virtual Machine
      Kernel driver in use: snd_hda_intel
    
    $ cat /proc/asound/card
    card0/ cards
    
    $ ls /proc/asound/card0/ ## empty directory
    
    $ cat /proc/asound/cards
    --- no soundcards ---
    

    See ALSA Framework: PCM and Control Interfaces for a more detailed discussion.

  • To check for available audio devices for a given QEMU machine - examples:

    • x86

      $ qemu-system-x86_64 -device ? 2>&1 | awk '/^Sound devices/,$1 !~ /^Sound|name/'
      Sound devices:
      [...]
      name "ES1370", bus PCI, desc "ENSONIQ AudioPCI ES1370"
      name "gus", bus ISA, desc "Gravis Ultrasound GF1"
      name "hda-duplex", bus HDA, desc "HDA Audio Codec, duplex (line-out, line-in)"
      [...]
      name "ich9-intel-hda", bus PCI, desc "Intel HD Audio Controller (ich9)"
      name "intel-hda", bus PCI, desc "Intel HD Audio Controller (ich6)"
      name "sb16", bus ISA, desc "Creative Sound Blaster 16"
      name "usb-audio", bus usb-bus
      
    • ARM

      $ qemu-system-arm -machine $MACHINE -device ? |& awk '/^Sound devices/,$1 !~ /^Sound|name/'
      

      where $MACHINE is any of the boards/SoCs reported by:

      $ qemu-system-arm -machine ?
      

    Notice that for audio interfaces on the PCI bus conforming to the Intel HDA standard, the audio controller resides on the PCI bus (i.e. bus PCI) while the audio codec device is connected to it via the HDA bus (i.e. bus HDA).

Apparently, no special config/build options are requied for these virtual/emulated audio devices. They automatically get built into the qemu-system-$ARCH binary. Their source files are usually under hw/audio/. However, note that some devices may not be available for a given machine architecture.

To view the list of properties for a particular audio device, for example:

$ bin/qemu-system-x86_64 -device hda-duplex,?
hda-duplex.cad=uint32
hda-duplex.debug=uint32
hda-duplex.mixer=bool

Needless to mention that stock (guest) Linux already includes the corresponding device driver support.

QEMU Audio Driver Environment Variables

QEMU-Audio environment variables are used to pass values that initialize/control the settings of the backend audio drivers. These variables can be viewed via:

$ qemu-system-$ARCH --audio-help

QEMU-Audio environment variables fall under two categories:

  • Audio Options - these settings apply to most backend audio drivers. They mostly correspond to certain low-level ALSA PCM settings for ALSA hardware parameters. Recall that Linux audio facilities, such as application/development libraries (e.g. SDL) and Sound Servers (e.g. PA and ESD), generally sit on top of ALSA-lib. Audio options settings include ALSA sample rate, ALSA sample format, number of channels (e.g. two for stereo), ALSA access modes, etc. Unless one is familiar with tweaking ALSA hardware parameters, leave these variables at their default settings. A discussion on basic ALSA PCM API and ALSA hardware parameters can be found in Basic ALSA PCM API.

  • Backend specific options - these settings pertain to a particular audio driver e.g. alsa, oss, sdl, pa, etc. For example, for the alsa backend, available settings include those for the PCM period length (size or time) and PCM buffer length (size or time), ALSA PCM software parameters settings for the host's device driver (e.g. threshold1), and the ALSA virtual PCM device for playback/capture. Basic ALSA PCM API might be of interest.

Passing values using these environment variables is a simple matter of setting them, say, on the command line. For example, to use the ALSA backend, set QEMU_AUDIO_DRV=alsa.

  • A process' environment can be set directly e.g:

    $ QEMU_AUDIO_DRV=alsa QEMU_ALSA_DAC_DEV=plug:dmix QEMU_ALSA_ADC_DEV=plug:dsnoop \
        QEMU_ALSA_DAC_PERIOD_SIZE=1024 qemu-system-$ARCH [...] -device ich9-intel-hda -device hda-duplex
    
  • Alternatively, via the parent shell's environment:

    $ export QEMU_AUDIO_DRV=alsa               ## execute "unset QEMU_AUDIO_DRV" to undo this setting
    $ qemu-system-$ARCH -device ES1370 [...]
    

    For the C-Shell, replace export(p) with setenv(1).

  • If running QEMU with sudo(8) priviledges:

    $ sudo sh -c "QEMU_AUDIO_DRV=alsa qemu-system-$ARCH ..."
    
    $ sudo env QEMU_AUDIO_DRV=alsa qemu-system-$ARCH ...
    
    (etc)
    
  • If executing via gdb(1), environment variables can be set by way of:

    (gdb) set environment QEMU_AUDIO_DRV=alsa
    
  • etc.

Testing QEMU Audio

Host-Side

This section will mainly focus on the alsa backend. Now, besides the basic requirement for built-in support for a particular audio backend driver, a few other factors will influence QEMU-Audio behaviour:

Default Audio Backend

As illustrated in Section Config and Build, the order of audio driver specification against configure during QEMU build reflects in the QEMU_AUDIO_DRIVERS definition (config-host.h). This order influences the manner in which QEMU-Audio picks the default audio backend, as well as its "fall back" behaviour upon failure of default, or specified, audio backend initialization.

For instance:

$ ./configure --audio-drv-list=alsa,sdl,pa,oss [...]

yields:

$ qemu-system-$ARCH --audio-help | grep Name
Name: alsa
Name: sdl
Name: pa
Name: oss
Name: none
Name: wav

In this case, launching QEMU without the QEMU_AUDIO_DRV audio backend environment setting e.g.

$ qemu-system-$ARCH ... -device ES1370

will result in qemu-system using the first audio backend in the QEMU_AUDIO_DRIVERS list - alsa in this case - with the default audio driver environment variable settings. For example, and in this instance, the ALSA virtual PCM device will be default. A setup like this usually just works "out-of-the-box".

On the other hand, building with, say:

$ ./configure --audio-drv-list=oss,alsa,pa,sdl [...]

gives:

$ qemu-system-$ARCH --audio-help | grep Name
Name: oss
Name: alsa
Name: pa
Name: sdl
Name: none
Name: wav

and launching QEMU without the QEMU_AUDIO_DRV audio backend environment setting e.g.

$ qemu-system-$ARCH ... -device ES1370

might result in the following error message getting emitted:

audio: Could not init `oss' audio driver

due to resource contention, i.e. if some other audio application is executing on the host. In situations like these, the error handling code in audio/audio.c:audio_init() will fall back to the next audio backend on the QEMU_AUDIO_DRIVERS list. In this instance, alsa with default backend settings will be selected. As will be illustrated in the next section, certain ALSA PCM plugins allow several audio applications on a host (without hardware audio stream mixing capability) to operate on a given stream (i.e. playback or capture) simultaneously. The ALSA virtual PCM device to use will depend on the host's audio configuration, e.g. whether the VM audio is being routed via a sound server on the host, or being routed directly via the host's ALSA lib.

Note that a configuration such as:

$ qemu-system-$ARCH --audio-help | grep Name
Name: oss
Name: none
Name: wav

is likely to result in complete QEMU-Audio initialization failure if some other audio app is open on the host - since there is no other "usable" audio backend to fall back to.

ALSA Virtual PCM Devices

Applications opening an ALSA PCM interface specify a virtual PCM device rather than the filename of the PCM device (e.g. /dev/snd/pcmC0D0c). ALSA virtual PCM devices "map" to a PCM plugin. ALSA virtual devices are defined in a configuration file (typically under /usr/share/alsa/, or in /etc/asound.conf, or in ~/.asoundrc). PCM plugins extend functionality and features of PCM devices by performing various sample conversions, sample copying among channels, resampling, etc. The complete information about PCM plugins is quite extensive and can be found here and there and in /usr/share/alsa/alsa.conf. This local entry also includes brief descriptions of a few virtual PCM devices and their corresponding PCM plugins.

Standard ALSA virtual PCM devices generally take the form $PLUGIN[:$CARD[,$DEVICE[,$SUBDEVICE]]] where $CARD is some stringID or zero-based index, while $DEVICE and $SUBDEVICE is some index starting from 0.

For instance, to view available cards and their PCM devices and subdevices:

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: PCH [HDA Intel PCH], device 0: ALC269VB Analog [ALC269VB Analog]
    Subdevices: 1/1
    Subdevice #0: subdevice #0
card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0]
    Subdevices: 1/1
    Subdevice #0: subdevice #0

i.e. the system has one soundcard with two devices (stereo and HDMI) for playback.

To view the (distro defined) ALSA virtual PCM devices (usually under /usr/share/alsa):

$ aplay -L
default
        Playback/recording through the PulseAudio sound server
sysdefault:CARD=PCH
        HDA Intel PCH, ALC269VB Analog
        Default Audio Device
...
hdmi:CARD=PCH,DEV=0
        HDA Intel PCH, HDMI 0
        HDMI Audio Output
...
hw:CARD=PCH,DEV=0
        HDA Intel PCH, ALC269VB Analog
        Direct hardware device without any conversions
hw:CARD=PCH,DEV=3
        HDA Intel PCH, HDMI 0
        Direct hardware device without any conversions
plughw:CARD=PCH,DEV=0
        HDA Intel PCH, ALC269VB Analog
        Hardware device with all software conversions
plughw:CARD=PCH,DEV=3
        HDA Intel PCH, HDMI 0
        Hardware device with all software conversions

In this case, $CARD may take the stringID PCH or index 0, while $DEVICE may assume the values 0 or 3, and $SUBDEVICE is always 0. Available virtual PCM devices for playback include:

  • For the ALC269VB Analog (Realtek stereo codec) device: default (typically configured for a soundserver's PCM plugin, e.g. pulse PCM plugin for pulseaudio(1) on Ubuntu/Fedora systems), hw:0,0 (uses the hw PCM plugin), plughw:0,0 (daisy-chains the plug and hw PCM plugins).

  • For the HDMI (Intel CourgarPoint codec) device: hdmi, hw:0,3 and plughw:0,3 virtual PCM devices.

Omitted in the aplay(1) command's output are several other virtual PCM devices for playback or capture.

  • Example Using the default ALSA virtual PCM device

    This is the default ALSA virtual PCM device for alsa backend. In other words, it is the virtual PCM device used when launching a QEMU-Audio instance with only:

    $ QEMU_AUDIO_DRV=alsa qemu-system-x86_64 ...
    

    Usually, things will just work with this virtual PCM device - notably on systems with sound servers. Generally, sound servers seamlessly support mixing/sharing of playback/capture streams. On host's without hardware audio stream mixing capability, using default with the QEMU-Audio instance should work alongside other audio applications on the host using the sound server.

  • Example Using The [plug]hw[:$CARD[,$DEVICE[,$SUBDEVICE]]] ALSA virtual PCM devices

    These virtual PCM devices effect direct communication with the ALSA device driver, by-passing any sound server functionality. The hw[:$CARD...] virtual PCM devices uses the hw PCM plugin which performs no software conversions (i.e. usable PCM audio parameters are restricted to the configuration space directly supported by the hardware device). The plughw[:$CARD...] virtual PCM device uses the plug PCM plugin to allow software conversions, thereby allowing the user to specify PCM hardware parameters (or PCM configuration spaces) other than the ones directly supported by the hardware. Like default, these virtual PCM devices support both playback and capture streams.

    However, a limitation with these ALSA virtual PCM devices is that on a system without hardware mixing capabilities, then only one application at a time can operate on a given stream. For example, if an application is already performing playback via a sound server, then an attempt to use either of these native ALSA PCM plugins on the same stream from a separate application is quite likely to fail. Below is an instance of using the hw[:$CARD...] PCM device while some other audio application's playback stream via pulseaudio(1) was in effect on an Ubuntu 12.04 host whose hardware possessed no mixing capabilities, and only supported one stream for playback:

    $ QEMU_AUDIO_DRV=alsa QEMU_ALSA_DAC_DEV=hw:0,0 qemu-system-x86_64 ... -append "console=ttyS0" -device ES1370 -nographic
    ...
     * Starting ISC DHCP IPv4 server                                         [ OK ]
     * speech-dispatcher disabled; edit /etc/default/speech-dispatcher
    saned disabled; edit /etc/default/saned
     * Restoring resolver state...                                           [ OK ] 
    alsa: Could not initialize DAC
    alsa: Failed to open `hw:0,0':
    alsa: Reason: Device or resource busy
    ...
    audio: Failed to create voice `es1370.dac2'
    ...
    audio: Failed to create voice `es1370.dac1'
    ...
    
    Ubuntu 14.04.2 LTS vm0-ubuntu-14 ttyS0
    
    vm0-ubuntu-14 login:
    

    and the following attempt in the guest:

    biko@vm0-ubuntu-14:~$ aplay t.wav
    

    did not yeild any results.

  • Using The [plug:]dmix and [plug:]dsnoop ALSA virtual PCM devices

    In order to execute several audio applications on the host without the services of a sound server (i.e. strictly ALSA lib based mixing/sharing), the [plug:]dmix virtual PCM device (playback), and the [plug:]dsnoop virtual PCM device (capture) can be used by the respective applications. The dmix and dsnoop versions perform no software conversions while the plug:dmix and plug:dsnoop counterparts employ the plug PCM plugin to enable software conversions.

In summary, in order to avoid unneccessary complications, or unless you know what you are doing, stick with the default default virtual PCM device. Nevertheless, if you experience underruns (playback) or overruns (capture) when using default over a sound server, then you might consider direct ALSA device driver access by way of the hw, plughw, etc types.

Guest-Side

Upon qemu-system boot, preliminary tests for QEMU-Audio functionality can be carried out with native ALSA tools. For instance, adjust the QEMU Audio device mixer settings via alsamixer(1) and then play some random .wav file via aplay(1):

$ alsamixer

$ aplay foo.wav

If the alsa backend used the distro configured default or plughw:0,0/plug:dmix ALSA virtual PCM devices, then sound should be audible via, say, the PC/laptop's speakers or line-out.

Note that the ALSA framework is quite complex (but with good reason) and troubleshooting audio problems can get quite "involving". If, for example, the alsamixer(1) and aplay(1) commands above fail, and if you don't know any better, try running with sudo(8) priviledges. If this fails (or if it succeeds), then an inspection of the settings of the various ALSA device and configuration files (e.g. /usr/share/alsa/*, /dev/snd, /etc/init/alsa-*, etc) and output of various commands (dmesg(1), lsmod(8), etc) will have to be (or should be) done. There is plenty of online documentation that includes tips on troubleshooting ALSA configuration, e.g. ArchLinux Wiki, ALSA. This local entry also includes a brief description of the ALSA PCM framework.

Footnotes

1. Haven't yet determined which, i.e. start threshold, stop threshold, etc. [go back]