This is a merge of a topic branch containing the support for the new channel map API using control elements.tirimbino
commit
e5d6db8e60
@ -0,0 +1,153 @@ |
||||
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. |
Loading…
Reference in new issue