PCM (digital audio) plugins

PCM plugins extends functionality and features of PCM devices. The plugins take care about various sample conversions, sample copying among channels and so on.

Slave definition

The slave plugin can be specified directly with a string or the definition can be entered inside a compound configuration node. Some restrictions can be also specified (like static rate or count of channels).

pcm_slave.NAME {
    pcm STR     # PCM name
    # or
    pcm { }     # PCM definition
    format STR  # Format or "unchanged"
    channels INT    # Count of channels or "unchanged" string
    rate INT    # Rate in Hz or "unchanged" string
    period_time INT # Period time in us or "unchanged" string
    buffer_time INT # Buffer time in us or "unchanged" string
}

Example:

pcm_slave.slave_rate44100Hz {
    pcm "hw:0,0"
    rate 44100
}

pcm.rate44100Hz {
    type plug
    slave slave_rate44100Hz
}

The equivalent configuration (in one compound):

pcm.rate44100Hz {
    type plug
    slave {
        pcm "hw:0,0"
        rate 44100
    }
}

Plugin: hw

This plugin communicates directly with the ALSA kernel driver. It is a raw communication without any conversions. The emulation of mmap access can be optionally enabled, but expect worse latency in the case.

The nonblock option specifies whether the device is opened in a non-blocking manner. Note that the blocking behavior for read/write access won’t be changed by this option. This influences only on the blocking behavior at opening the device. If you would like to keep the compatibility with the older ALSA stuff, turn this option off.

pcm.name {
    type hw         # Kernel PCM
    card INT/STR        # Card name (string) or number (integer)
    [device INT]        # Device number (default 0)
    [subdevice INT]     # Subdevice number (default -1: first available)
    [sync_ptr_ioctl BOOL]   # Use SYNC_PTR ioctl rather than the direct mmap access for control structures
    [nonblock BOOL]     # Force non-blocking open mode
    [format STR]        # Restrict only to the given format
    [channels INT]      # Restrict only to the given channels
    [rate INT]      # Restrict only to the given rate
    [chmap MAP]     # Override channel maps; MAP is a string array
}

Plugin: mmap_emul

pcm.name {
    type mmap_emul
    slave PCM
}

Function reference

Plugin: shm

This plugin communicates with aserver via shared memory. It is a raw communication without any conversions, but it can be expected worse performance.

pcm.name {
        type shm                # Shared memory PCM
    server STR      # Server name
    pcm STR         # PCM name
}

Plugin: Null

This plugin discards contents of a PCM stream or creates a stream with zero samples.

Note: This implementation uses devices /dev/null (playback, must be writable) and /dev/full (capture, must be readable).

pcm.name {
        type null               # Null PCM
    [chmap MAP]     # Provide channel maps; MAP is a string array
}

Plugin: copy

This plugin copies samples from master copy PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
    type copy       # Copy PCM
    slave STR       # Slave name
    # or
    slave {         # Slave definition
        pcm STR     # Slave PCM name
        # or
        pcm { }     # Slave PCM definition
    }
}

Plugin: linear

This plugin converts linear samples from master linear conversion PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
        type linear             # Linear conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                format STR      # Slave format
        }
}

Plugin: linear<->float

This plugin converts linear to float samples and float to linear samples from master linear<->float conversion PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
        type lfloat             # Linear<->Float conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                format STR      # Slave format
        }
}

Plugin: Mu-Law

This plugin converts Mu-Law samples to linear or linear to Mu-Law samples from master Mu-Law conversion PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
        type mulaw              # Mu-Law conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                format STR      # Slave format
        }
}

Plugin: A-Law

This plugin converts A-Law samples to linear or linear to A-Law samples from master A-Law conversion PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
        type alaw               # A-Law conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                format STR      # Slave format
        }
}

Plugin: Ima-ADPCM

This plugin converts Ima-ADPCM samples to linear or linear to Ima-ADPCM samples from master Ima-ADPCM conversion PCM to given slave PCM. The channel count, format and rate must match for both of them.

pcm.name {
        type adpcm              # Ima-ADPCM conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                format STR      # Slave format
        }
}

Plugin: Route & Volume

This plugin converts channels and applies volume during the conversion. The format and rate must match for both of them.

SCHANNEL can be a channel name instead of a number (e g FL, LFE). If so, a matching channel map will be selected for the slave.

pcm.name {
        type route              # Route & Volume conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                [format STR]    # Slave format
                [channels INT]  # Slave channels
        }
        ttable {                # Transfer table (bi-dimensional compound of cchannels * schannels numbers)
                CCHANNEL {
                        SCHANNEL REAL   # route value (0.0 - 1.0)
                }
        }
}

Plugin: Rate

This plugin converts a stream rate. The input and output formats must be linear.

pcm.name {
    type rate               # Rate PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                rate INT        # Slave rate
                [format STR]    # Slave format
        }
    converter STR           # optional
    # or
    converter [ STR1 STR2 ... ] # optional
                # Converter type, default is taken from
                # defaults.pcm.rate_converter
}

Automatic conversion plugin

This plugin converts channels, rate and format on request.

pcm.name {
        type plug               # Automatic conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        [format STR]    # Slave format (default nearest) or "unchanged"
        [channels INT]  # Slave channels (default nearest) or "unchanged"
        [rate INT]  # Slave rate (default nearest) or "unchanged"
        }
    route_policy STR    # route policy for automatic ttable generation
                # STR can be 'default', 'average', 'copy', 'duplicate'
                # average: result is average of input channels
                # copy: only first channels are copied to destination
                # duplicate: duplicate first set of channels
                # default: copy policy, except for mono capture - sum
    ttable {        # Transfer table (bi-dimensional compound of cchannels * schannels numbers)
        CCHANNEL {
            SCHANNEL REAL   # route value (0.0 - 1.0)
        }
    }
    rate_converter STR  # type of rate converter
    # or
    rate_converter [ STR1 STR2 ... ]
                # type of rate converter
                # default value is taken from defaults.pcm.rate_converter
}

Function reference

  • snd_pcm_plug_open()
  • _snd_pcm_plug_open()

Plugin: File

This plugin stores contents of a PCM stream to file or pipes the stream to a command, and optionally uses an existing file as an input data source (i.e., “virtual mic”)

pcm.name {
        type file               # File PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        }
    file STR        # Output filename (or shell command the stream
                # will be piped to if STR starts with the pipe
                # char).
                # STR can contain format keys, replaced by
                # real values corresponding to the stream:
                # %r    rate (replaced with: 48000)
                # %c    channels (replaced with: 2)
                # %b    bits per sample (replaced with: 16)
                # %f    sample format string
                #           (replaced with: S16_LE)
                # %%    replaced with %
    or
    file INT        # Output file descriptor number
    infile STR      # Input filename - only raw format
    or
    infile INT      # Input file descriptor number
    [format STR]        # File format ("raw" or "wav")
    [perm INT]      # Output file permission (octal, def. 0600)
}

Plugin: Multiple streams to One

This plugin converts multiple streams to one.

pcm.name {
        type multi              # Multiple streams conversion PCM
        slaves {        # Slaves definition
        ID STR      # Slave PCM name
        # or
        ID {
            pcm STR     # Slave PCM name
            # or
            pcm { }     # Slave PCM definition
            channels INT    # Slave channels
        }
        }
    bindings {      # Bindings table
        N {
            slave STR   # Slave key
            channel INT # Slave channel
        }
    }
    [master INT]        # Define the master slave
}

For example, to bind two PCM streams with two-channel stereo (hw:0,0 and hw:0,1) as one 4-channel stereo PCM stream, define like this:

pcm.quad {
    type multi

    slaves.a.pcm "hw:0,0"
    slaves.a.channels 2
    slaves.b.pcm "hw:0,1"
    slaves.b.channels 2

    bindings.0.slave a
    bindings.0.channel 0
    bindings.1.slave a
    bindings.1.channel 1
    bindings.2.slave b
    bindings.2.channel 0
    bindings.3.slave b
    bindings.3.channel 1
}

Note that the resultant pcm “quad” is not in the interleaved format but in the “complex” format. Hence, it’s not accessible by applications which can handle only the interleaved (or the non-interleaved) format. In such a case, wrap this PCM with route or plug plugin.

pcm.quad2 {
    type route
    slave.pcm "quad"
    ttable.0.0 1
    ttable.1.1 1
    ttable.2.2 1
    ttable.3.3 1
}

Plugin: Share

This plugin allows sharing of multiple channels with more clients. The access to each channel is exlusive (samples are not mixed together). It means, if the channel zero is used with first client, the channel cannot be used with second one. If you are looking for a mixing plugin, use the dmix plugin.

The difference from dshare plugin is that share plugin requires the server program “aserver”, while dshare plugin doesn’t need the explicit server but access to the shared buffer.

pcm.name {
        type share              # Share PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                [format STR]    # Slave format
                [channels INT]  # Slave channels
                [rate INT]      # Slave rate
                [period_time INT] # Slave period time in us
                [buffer_time INT] # Slave buffer time in us
        }
    bindings {
        N INT       # Slave channel INT for client channel N
    }
}

Plugin: hooks

This plugin is used to call some ‘hook’ function when this plugin is opened, modified or closed. Typically, it is used to change control values for a certain state specially for the PCM (see the example below).

# Hook arguments definition
hook_args.NAME {
    ...         # Arbitrary arguments
}

# PCM hook type
pcm_hook_type.NAME {
    [lib STR]       # Library file (default libasound.so)
    [install STR]       # Install function (default _snd_pcm_hook_NAME_install)
}

# PCM hook definition
pcm_hook.NAME {
    type STR        # PCM Hook type (see pcm_hook_type)
    [args STR]      # Arguments for install function (see hook_args)
    # or
    [args { }]      # Arguments for install function
}

# PCM hook plugin
pcm.NAME {
    type hooks      # PCM with hooks
    slave STR       # Slave name
    # or
    slave {         # Slave definition
        pcm STR     # Slave PCM name
        # or
        pcm { }     # Slave PCM definition
    }
    hooks {
        ID STR      # Hook name (see pcm_hook)
        # or
        ID { }      # Hook definition (see pcm_hook)
    }
}

Example:

hooks.0 {
    type ctl_elems
    hook_args [
        {
            name "Wave Surround Playback Volume"
            preserve true
            lock true
            optional true
            value [ 0 0 ]
        }
        {
            name "EMU10K1 PCM Send Volume"
            index { @func private_pcm_subdevice }
            lock true
            value [ 0 0 0 0 0 0 255 0 0 0 0 255 ]
        }
    ]
}

Here, the controls “Wave Surround Playback Volume” and “EMU10K1 PCM Send Volume” are set to the given values when this pcm is accessed. Since these controls take multi-dimensional values, the value field is written as an array. When preserve is true, the old values are saved and restored when the pcm is closed. The lock means that the control is locked during this pcm is opened, and cannot be changed by others. When optional is set, no error is returned but ignored even if the specified control doesn’t exist.

Function reference

Plugin: dmix

This plugin provides direct mixing of multiple streams. The resolution for 32-bit mixing is only 24-bit. The low significant byte is filled with zeros. The extra 8 bits are used for the saturation.

pcm.name {
    type dmix       # Direct mix
    ipc_key INT     # unique IPC key
    ipc_key_add_uid BOOL    # add current uid to unique IPC key
    ipc_perm INT        # IPC permissions (octal, default 0600)
    slave STR
    # or
    slave {         # Slave definition
        pcm STR     # slave PCM name
        # or
        pcm { }     # slave PCM definition
        format STR  # format definition
        rate INT    # rate definition
        channels INT
        period_time INT # in usec
        # or
        period_size INT # in bytes
        buffer_time INT # in usec
        # or
        buffer_size INT # in bytes
        periods INT # when buffer_size or buffer_time is not specified
    }
    bindings {      # note: this is client independent!!!
        N INT       # maps slave channel to client channel N
    }
    slowptr BOOL        # slow but more precise pointer updates
}

ipc_key specfies the unique IPC key in integer. This number must be unique for each different dmix definition, since the shared memory is created with this key number. When ipc_key_add_uid is set true, the uid value is added to the value set in ipc_key. This will avoid the confliction of the same IPC key with different users concurrently.

Note that the dmix plugin itself supports only a single configuration. That is, it supports only the fixed rate (default 48000), format (S16), channels (2), and period_time (125000). For using other configuration, you have to set the value explicitly in the slave PCM definition. The rate, format and channels can be covered by an additional plug plugin, but there is only one base configuration, anyway.

An example configuration for setting 44100 Hz, S32_LE format as the slave PCM of “hw:0” is like below:

pcm.dmix_44 {
    type dmix
    ipc_key 321456  # any unique value
    ipc_key_add_uid true
    slave {
        pcm "hw:0"
        format S32_LE
        rate 44100
    }
}

You can hear 48000 Hz samples still using this dmix pcm via plug plugin like:

% aplay -Dplug:dmix_44 foo_48k.wav

For using the dmix plugin for OSS emulation device, you have to set the period and the buffer sizes in power of two. For example,

pcm.dmixoss {
    type dmix
    ipc_key 321456  # any unique value
    ipc_key_add_uid true
    slave {
        pcm "hw:0"
        period_time 0
        period_size 1024  # must be power of 2
        buffer_size 8192  # ditto
    }
}

period_time 0 must be set, too, for resetting the default value. In the case of soundcards with multi-channel IO, adding the bindings would help

pcm.dmixoss {
    ...
    bindings {
        0 0   # map from 0 to 0
        1 1   # map from 1 to 1
    }
}

so that only the first two channels are used by dmix. Also, note that ICE1712 have the limited buffer size, 5513 frames (corresponding to 640 kB). In this case, reduce the buffer_size to 4096.

Plugin: dshare

This plugin provides sharing channels. Unlike share plugin, this plugin doesn’t need the explicit server program but accesses the shared buffer concurrently from each client as well as dmix and dsnoop plugins do. The parameters below are almost identical with these plugins.

pcm.name {
    type dshare     # Direct sharing
    ipc_key INT     # unique IPC key
    ipc_key_add_uid BOOL    # add current uid to unique IPC key
    ipc_perm INT        # IPC permissions (octal, default 0600)
    slave STR
    # or
    slave {         # Slave definition
        pcm STR     # slave PCM name
        # or
        pcm { }     # slave PCM definition
        format STR  # format definition
        rate INT    # rate definition
        channels INT
        period_time INT # in usec
        # or
        period_size INT # in bytes
        buffer_time INT # in usec
        # or
        buffer_size INT # in bytes
        periods INT # when buffer_size or buffer_time is not specified
    }
    bindings {      # note: this is client independent!!!
        N INT       # maps slave channel to client channel N
    }
    slowptr BOOL        # slow but more precise pointer updates
}

Plugin: dsnoop

This plugin splits one capture stream to more. It works the reverse way of dmix plugin, reading the shared capture buffer from many clients concurrently. The meaning of parameters below are almost identical with dmix plugin.

pcm.name {
    type dsnoop     # Direct snoop
    ipc_key INT     # unique IPC key
    ipc_key_add_uid BOOL    # add current uid to unique IPC key
    ipc_perm INT        # IPC permissions (octal, default 0600)
    slave STR
    # or
    slave {         # Slave definition
        pcm STR     # slave PCM name
        # or
        pcm { }     # slave PCM definition
        format STR  # format definition
        rate INT    # rate definition
        channels INT
        period_time INT # in usec
        # or
        period_size INT # in bytes
        buffer_time INT # in usec
        # or
        buffer_size INT # in bytes
        periods INT # when buffer_size or buffer_time is not specified
    }
    bindings {      # note: this is client independent!!!
        N INT       # maps slave channel to client channel N
    }
    slowptr BOOL        # slow but more precise pointer updates
}

Plugin: LADSPA <-> ALSA

This plugin allows to apply a set of LADPSA plugins. The input and output format is always SND_PCM_FORMAT_FLOAT (note: this type can be either little or big-endian depending on architecture).

The policy duplicate means that there must be only one binding definition for channel zero. This definition is automatically duplicated for all channels. If the LADSPA plugin has multiple audio inputs or outputs the policy duplicate is automatically switched to policy none.

The plugin serialization works as expected. You can eventually use more channels (inputs / outputs) inside the LADPSA plugin chain than processed in the ALSA plugin chain. If ALSA channel does not exist for given LADSPA input audio port, zero samples are given to this LADSPA port. On the output side (ALSA next plugin input), the valid channels are checked, too. If specific ALSA channel does not exist, the LADSPA output port is connected to a dummy sample area.

Instances of LADSPA plugins are created dynamically.

pcm.name {
        type ladspa             # ALSA<->LADSPA PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        }
        [channels INT]      # count input channels (input to LADSPA plugin chain)
    [path STR]      # Path (directory) with LADSPA plugins
    plugins |       # Definition for both directions
        playback_plugins |  # Definition for playback direction
    capture_plugins {   # Definition for capture direction
        N {     # Configuration for LADPSA plugin N
            [id INT]    # LADSPA plugin ID (for example 1043)
            [label STR] # LADSPA plugin label (for example 'delay_5s')
            [filename STR]  # Full filename of .so library with LADSPA plugin code
            [policy STR]    # Policy can be 'none' or 'duplicate'
            input | output {
                bindings {
                    C INT or STR    # C - channel, INT - audio port index, STR - audio port name
                }
                controls {
                        # valid only in the input block
                    I INT or REAL   # I - control port index, INT or REAL - control value
                    # or
                    STR INT or REAL # STR - control port name, INT or REAL - control value
                }
            }
        }
    }
}

Plugin: asym

This plugin is a combination of playback and capture PCM streams. Slave PCMs can be defined asymmetrically for both directions.

pcm.name {
        type asym               # Asym PCM
        playback STR            # Playback slave name
        # or
        playback {              # Playback slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        }
        capture STR             # Capture slave name
        # or
        capture {               # Capture slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        }
}

For example, you can combine a dmix plugin and a dsnoop plugin as as a single PCM for playback and capture directions, respectively.

pcm.duplex {
    type asym
    playback.pcm "dmix"
    capture.pcm "dsnoop"
}

By defining only a single direction, the resultant PCM becomes half-duplex.

Function reference

Plugin: IEC958

This plugin converts 32bit IEC958 subframe samples to linear, or linear to 32bit IEC958 subframe samples.

pcm.name {
        type iec958             # IEC958 subframe conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
        }
    [status status-bytes]   # IEC958 status bits (given in byte array)
    # IEC958 preamble bits definitions
    # B/M/W or Z/X/Y, B = block start, M = even subframe, W = odd subframe
    # As default, Z = 0x08, Y = 0x04, X = 0x02
    [preamble.z or preamble.b val]
    [preamble.x or preamble.m val]
    [preamble.y or preamble.w val]
}

Plugin: Soft Volume

This plugin applies the software volume attenuation. The format, rate and channels must match for both of source and destination.

When the control is stereo (count=2), the channels are assumed to be either mono, 2.0, 2.1, 4.0, 4.1, 5.1 or 7.1.

If the control already exists and it’s a system control (i.e. no user-defined control), the plugin simply passes its slave without any changes.

pcm.name {
        type softvol            # Soft Volume conversion PCM
        slave STR               # Slave name
        # or
        slave {                 # Slave definition
                pcm STR         # Slave PCM name
                # or
                pcm { }         # Slave PCM definition
                [format STR]    # Slave format
        }
        control {
            name STR        # control element id string
        [card STR]      # control card index
        [iface STR]     # interface of the element
        [index INT]     # index of the element
        [device INT]    # device number of the element
        [subdevice INT] # subdevice number of the element
        [count INT]     # control channels 1 or 2 (default: 2)
    }
    [min_dB REAL]           # minimal dB value (default: -51.0)
    [max_dB REAL]           # maximal dB value (default:   0.0)
    [resolution INT]        # resolution (default: 256)
                # resolution = 2 means a mute switch
}

Plugin: Null

This plugin discards contents of a PCM stream or creates a stream with zero samples.

Note: This implementation uses devices /dev/null (playback, must be writable) and /dev/full (capture, must be readable).

pcm.name {
        type null               # Null PCM
}

Function reference