Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 1 | ALSA PCM channel-mapping API |
| 2 | ============================ |
| 3 | Takashi Iwai <tiwai@suse.de> |
| 4 | |
| 5 | GENERAL |
| 6 | ------- |
| 7 | |
| 8 | The channel mapping API allows user to query the possible channel maps |
| 9 | and the current channel map, also optionally to modify the channel map |
| 10 | of the current stream. |
| 11 | |
| 12 | A channel map is an array of position for each PCM channel. |
| 13 | Typically, a stereo PCM stream has a channel map of |
| 14 | { front_left, front_right } |
| 15 | while a 4.0 surround PCM stream has a channel map of |
| 16 | { front left, front right, rear left, rear right }. |
| 17 | |
| 18 | The problem, so far, was that we had no standard channel map |
| 19 | explicitly, and applications had no way to know which channel |
| 20 | corresponds to which (speaker) position. Thus, applications applied |
| 21 | wrong channels for 5.1 outputs, and you hear suddenly strange sound |
| 22 | from rear. Or, some devices secretly assume that center/LFE is the |
| 23 | third/fourth channels while others that C/LFE as 5th/6th channels. |
| 24 | |
| 25 | Also, some devices such as HDMI are configurable for different speaker |
| 26 | positions even with the same number of total channels. However, there |
| 27 | was no way to specify this because of lack of channel map |
| 28 | specification. These are the main motivations for the new channel |
| 29 | mapping API. |
| 30 | |
| 31 | |
| 32 | DESIGN |
| 33 | ------ |
| 34 | |
| 35 | Actually, "the channel mapping API" doesn't introduce anything new in |
| 36 | the kernel/user-space ABI perspective. It uses only the existing |
| 37 | control element features. |
| 38 | |
| 39 | As a ground design, each PCM substream may contain a control element |
| 40 | providing the channel mapping information and configuration. This |
| 41 | element is specified by: |
| 42 | iface = SNDRV_CTL_ELEM_IFACE_PCM |
| 43 | name = "Playback Channel Map" or "Capture Channel Map" |
| 44 | device = the same device number for the assigned PCM substream |
| 45 | index = the same index number for the assigned PCM substream |
| 46 | |
| 47 | Note the name is different depending on the PCM substream direction. |
| 48 | |
| 49 | Each control element provides at least the TLV read operation and the |
| 50 | read operation. Optionally, the write operation can be provided to |
| 51 | allow user to change the channel map dynamically. |
| 52 | |
| 53 | * TLV |
| 54 | |
| 55 | The TLV operation gives the list of available channel |
| 56 | maps. A list item of a channel map is usually a TLV of |
| 57 | type data-bytes ch0 ch1 ch2... |
| 58 | where type is the TLV type value, the second argument is the total |
| 59 | bytes (not the numbers) of channel values, and the rest are the |
| 60 | position value for each channel. |
| 61 | |
| 62 | As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED, |
| 63 | SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used. |
| 64 | The _FIXED type is for a channel map with the fixed channel position |
| 65 | while the latter two are for flexible channel positions. _VAR type is |
| 66 | for a channel map where all channels are freely swappable and _PAIRED |
| 67 | type is where pair-wise channels are swappable. For example, when you |
| 68 | have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap |
| 69 | only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and |
| 70 | RR. |
| 71 | |
| 72 | These new TLV types are defined in sound/tlv.h. |
| 73 | |
| 74 | The available channel position values are defined in sound/asound.h, |
| 75 | here is a cut: |
| 76 | |
| 77 | /* channel positions */ |
| 78 | enum { |
| 79 | SNDRV_CHMAP_UNKNOWN = 0, |
Takashi Iwai | 7b31d00 | 2012-09-12 18:06:54 +0200 | [diff] [blame] | 80 | SNDRV_CHMAP_NA, /* N/A, silent */ |
| 81 | SNDRV_CHMAP_MONO, /* mono stream */ |
| 82 | /* this follows the alsa-lib mixer channel value + 3 */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 83 | SNDRV_CHMAP_FL, /* front left */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 84 | SNDRV_CHMAP_FR, /* front right */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 85 | SNDRV_CHMAP_RL, /* rear left */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 86 | SNDRV_CHMAP_RR, /* rear right */ |
Takashi Iwai | 080108c | 2012-08-21 14:47:18 +0200 | [diff] [blame] | 87 | SNDRV_CHMAP_FC, /* front center */ |
| 88 | SNDRV_CHMAP_LFE, /* LFE */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 89 | SNDRV_CHMAP_SL, /* side left */ |
| 90 | SNDRV_CHMAP_SR, /* side right */ |
Takashi Iwai | 080108c | 2012-08-21 14:47:18 +0200 | [diff] [blame] | 91 | SNDRV_CHMAP_RC, /* rear center */ |
| 92 | /* new definitions */ |
| 93 | SNDRV_CHMAP_FLC, /* front left center */ |
| 94 | SNDRV_CHMAP_FRC, /* front right center */ |
| 95 | SNDRV_CHMAP_RLC, /* rear left center */ |
| 96 | SNDRV_CHMAP_RRC, /* rear right center */ |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 97 | SNDRV_CHMAP_FLW, /* front left wide */ |
| 98 | SNDRV_CHMAP_FRW, /* front right wide */ |
| 99 | SNDRV_CHMAP_FLH, /* front left high */ |
| 100 | SNDRV_CHMAP_FCH, /* front center high */ |
| 101 | SNDRV_CHMAP_FRH, /* front right high */ |
| 102 | SNDRV_CHMAP_TC, /* top center */ |
Takashi Iwai | 7b31d00 | 2012-09-12 18:06:54 +0200 | [diff] [blame] | 103 | SNDRV_CHMAP_TFL, /* top front left */ |
| 104 | SNDRV_CHMAP_TFR, /* top front right */ |
| 105 | SNDRV_CHMAP_TFC, /* top front center */ |
| 106 | SNDRV_CHMAP_TRL, /* top rear left */ |
| 107 | SNDRV_CHMAP_TRR, /* top rear right */ |
| 108 | SNDRV_CHMAP_TRC, /* top rear center */ |
| 109 | SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC, |
Takashi Iwai | be84bbc | 2012-08-15 16:06:43 +0200 | [diff] [blame] | 110 | }; |
| 111 | |
| 112 | When a PCM stream can provide more than one channel map, you can |
| 113 | provide multiple channel maps in a TLV container type. The TLV data |
| 114 | to be returned will contain such as: |
| 115 | SNDRV_CTL_TLVT_CONTAINER 96 |
| 116 | SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC |
| 117 | SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR |
| 118 | SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \ |
| 119 | SNDRV_CHMAP_RL SNDRV_CHMAP_RR |
| 120 | |
| 121 | The channel position is provided in LSB 16bits. The upper bits are |
| 122 | used for bit flags. |
| 123 | |
| 124 | #define SNDRV_CHMAP_POSITION_MASK 0xffff |
| 125 | #define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) |
| 126 | #define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) |
| 127 | |
| 128 | SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted, |
| 129 | (thus summing left and right channels would result in almost silence). |
| 130 | Some digital mic devices have this. |
| 131 | |
| 132 | When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values |
| 133 | don't follow the standard definition above but driver-specific. |
| 134 | |
| 135 | * READ OPERATION |
| 136 | |
| 137 | The control read operation is for providing the current channel map of |
| 138 | the given stream. The control element returns an integer array |
| 139 | containing the position of each channel. |
| 140 | |
| 141 | When this is performed before the number of the channel is specified |
| 142 | (i.e. hw_params is set), it should return all channels set to |
| 143 | UNKNOWN. |
| 144 | |
| 145 | * WRITE OPERATION |
| 146 | |
| 147 | The control write operation is optional, and only for devices that can |
| 148 | change the channel configuration on the fly, such as HDMI. User needs |
| 149 | to pass an integer value containing the valid channel positions for |
| 150 | all channels of the assigned PCM substream. |
| 151 | |
| 152 | This operation is allowed only at PCM PREPARED state. When called in |
| 153 | other states, it shall return an error. |