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