154 lines
5.7 KiB
Plaintext
154 lines
5.7 KiB
Plaintext
|
ALSA PCM channel-mapping API
|
||
|
============================
|
||
|
Takashi Iwai <tiwai@suse.de>
|
||
|
|
||
|
GENERAL
|
||
|
-------
|
||
|
|
||
|
The channel mapping API allows user to query the possible channel maps
|
||
|
and the current channel map, also optionally to modify the channel map
|
||
|
of the current stream.
|
||
|
|
||
|
A channel map is an array of position for each PCM channel.
|
||
|
Typically, a stereo PCM stream has a channel map of
|
||
|
{ front_left, front_right }
|
||
|
while a 4.0 surround PCM stream has a channel map of
|
||
|
{ front left, front right, rear left, rear right }.
|
||
|
|
||
|
The problem, so far, was that we had no standard channel map
|
||
|
explicitly, and applications had no way to know which channel
|
||
|
corresponds to which (speaker) position. Thus, applications applied
|
||
|
wrong channels for 5.1 outputs, and you hear suddenly strange sound
|
||
|
from rear. Or, some devices secretly assume that center/LFE is the
|
||
|
third/fourth channels while others that C/LFE as 5th/6th channels.
|
||
|
|
||
|
Also, some devices such as HDMI are configurable for different speaker
|
||
|
positions even with the same number of total channels. However, there
|
||
|
was no way to specify this because of lack of channel map
|
||
|
specification. These are the main motivations for the new channel
|
||
|
mapping API.
|
||
|
|
||
|
|
||
|
DESIGN
|
||
|
------
|
||
|
|
||
|
Actually, "the channel mapping API" doesn't introduce anything new in
|
||
|
the kernel/user-space ABI perspective. It uses only the existing
|
||
|
control element features.
|
||
|
|
||
|
As a ground design, each PCM substream may contain a control element
|
||
|
providing the channel mapping information and configuration. This
|
||
|
element is specified by:
|
||
|
iface = SNDRV_CTL_ELEM_IFACE_PCM
|
||
|
name = "Playback Channel Map" or "Capture Channel Map"
|
||
|
device = the same device number for the assigned PCM substream
|
||
|
index = the same index number for the assigned PCM substream
|
||
|
|
||
|
Note the name is different depending on the PCM substream direction.
|
||
|
|
||
|
Each control element provides at least the TLV read operation and the
|
||
|
read operation. Optionally, the write operation can be provided to
|
||
|
allow user to change the channel map dynamically.
|
||
|
|
||
|
* TLV
|
||
|
|
||
|
The TLV operation gives the list of available channel
|
||
|
maps. A list item of a channel map is usually a TLV of
|
||
|
type data-bytes ch0 ch1 ch2...
|
||
|
where type is the TLV type value, the second argument is the total
|
||
|
bytes (not the numbers) of channel values, and the rest are the
|
||
|
position value for each channel.
|
||
|
|
||
|
As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED,
|
||
|
SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used.
|
||
|
The _FIXED type is for a channel map with the fixed channel position
|
||
|
while the latter two are for flexible channel positions. _VAR type is
|
||
|
for a channel map where all channels are freely swappable and _PAIRED
|
||
|
type is where pair-wise channels are swappable. For example, when you
|
||
|
have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap
|
||
|
only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and
|
||
|
RR.
|
||
|
|
||
|
These new TLV types are defined in sound/tlv.h.
|
||
|
|
||
|
The available channel position values are defined in sound/asound.h,
|
||
|
here is a cut:
|
||
|
|
||
|
/* channel positions */
|
||
|
enum {
|
||
|
SNDRV_CHMAP_UNKNOWN = 0,
|
||
|
SNDRV_CHMAP_NA, /* N/A, silent */
|
||
|
SNDRV_CHMAP_MONO, /* mono stream */
|
||
|
/* this follows the alsa-lib mixer channel value + 3 */
|
||
|
SNDRV_CHMAP_FL, /* front left */
|
||
|
SNDRV_CHMAP_FR, /* front right */
|
||
|
SNDRV_CHMAP_RL, /* rear left */
|
||
|
SNDRV_CHMAP_RR, /* rear right */
|
||
|
SNDRV_CHMAP_FC, /* front center */
|
||
|
SNDRV_CHMAP_LFE, /* LFE */
|
||
|
SNDRV_CHMAP_SL, /* side left */
|
||
|
SNDRV_CHMAP_SR, /* side right */
|
||
|
SNDRV_CHMAP_RC, /* rear center */
|
||
|
/* new definitions */
|
||
|
SNDRV_CHMAP_FLC, /* front left center */
|
||
|
SNDRV_CHMAP_FRC, /* front right center */
|
||
|
SNDRV_CHMAP_RLC, /* rear left center */
|
||
|
SNDRV_CHMAP_RRC, /* rear right center */
|
||
|
SNDRV_CHMAP_FLW, /* front left wide */
|
||
|
SNDRV_CHMAP_FRW, /* front right wide */
|
||
|
SNDRV_CHMAP_FLH, /* front left high */
|
||
|
SNDRV_CHMAP_FCH, /* front center high */
|
||
|
SNDRV_CHMAP_FRH, /* front right high */
|
||
|
SNDRV_CHMAP_TC, /* top center */
|
||
|
SNDRV_CHMAP_TFL, /* top front left */
|
||
|
SNDRV_CHMAP_TFR, /* top front right */
|
||
|
SNDRV_CHMAP_TFC, /* top front center */
|
||
|
SNDRV_CHMAP_TRL, /* top rear left */
|
||
|
SNDRV_CHMAP_TRR, /* top rear right */
|
||
|
SNDRV_CHMAP_TRC, /* top rear center */
|
||
|
SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
|
||
|
};
|
||
|
|
||
|
When a PCM stream can provide more than one channel map, you can
|
||
|
provide multiple channel maps in a TLV container type. The TLV data
|
||
|
to be returned will contain such as:
|
||
|
SNDRV_CTL_TLVT_CONTAINER 96
|
||
|
SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC
|
||
|
SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR
|
||
|
SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \
|
||
|
SNDRV_CHMAP_RL SNDRV_CHMAP_RR
|
||
|
|
||
|
The channel position is provided in LSB 16bits. The upper bits are
|
||
|
used for bit flags.
|
||
|
|
||
|
#define SNDRV_CHMAP_POSITION_MASK 0xffff
|
||
|
#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16)
|
||
|
#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16)
|
||
|
|
||
|
SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted,
|
||
|
(thus summing left and right channels would result in almost silence).
|
||
|
Some digital mic devices have this.
|
||
|
|
||
|
When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values
|
||
|
don't follow the standard definition above but driver-specific.
|
||
|
|
||
|
* READ OPERATION
|
||
|
|
||
|
The control read operation is for providing the current channel map of
|
||
|
the given stream. The control element returns an integer array
|
||
|
containing the position of each channel.
|
||
|
|
||
|
When this is performed before the number of the channel is specified
|
||
|
(i.e. hw_params is set), it should return all channels set to
|
||
|
UNKNOWN.
|
||
|
|
||
|
* WRITE OPERATION
|
||
|
|
||
|
The control write operation is optional, and only for devices that can
|
||
|
change the channel configuration on the fly, such as HDMI. User needs
|
||
|
to pass an integer value containing the valid channel positions for
|
||
|
all channels of the assigned PCM substream.
|
||
|
|
||
|
This operation is allowed only at PCM PREPARED state. When called in
|
||
|
other states, it shall return an error.
|