Loading Documentation/sound/alsa/Channel-Mapping-API.txt 0 → 100644 +153 −0 Original line number Diff line number Diff line 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. include/sound/ac97_codec.h +3 −0 Original line number Diff line number Diff line Loading @@ -422,6 +422,7 @@ */ struct snd_ac97; struct snd_pcm_chmap; struct snd_ac97_build_ops { int (*build_3d) (struct snd_ac97 *ac97); Loading Loading @@ -528,6 +529,8 @@ struct snd_ac97 { struct delayed_work power_work; #endif struct device dev; struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */ }; #define to_ac97_t(d) container_of(d, struct snd_ac97, dev) Loading include/sound/asound.h +39 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,45 @@ enum { SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, }; /* 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, }; #define SNDRV_CHMAP_POSITION_MASK 0xffff #define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) #define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) #define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) Loading include/sound/pcm.h +48 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,7 @@ struct snd_pcm_str { struct snd_info_entry *proc_xrun_debug_entry; #endif #endif struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ }; struct snd_pcm { Loading Loading @@ -1086,4 +1087,51 @@ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream return "Capture"; } /* * PCM channel-mapping control API */ /* array element of channel maps */ struct snd_pcm_chmap_elem { unsigned char channels; unsigned char map[15]; }; /* channel map information; retrieved via snd_kcontrol_chip() */ struct snd_pcm_chmap { struct snd_pcm *pcm; /* assigned PCM instance */ int stream; /* PLAYBACK or CAPTURE */ struct snd_kcontrol *kctl; const struct snd_pcm_chmap_elem *chmap; unsigned int max_channels; unsigned int channel_mask; /* optional: active channels bitmask */ void *private_data; /* optional: private data pointer */ }; /* get the PCM substream assigned to the given chmap info */ static inline struct snd_pcm_substream * snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx) { struct snd_pcm_substream *s; for (s = info->pcm->streams[info->stream].substream; s; s = s->next) if (s->number == idx) return s; return NULL; } /* ALSA-standard channel maps (RL/RR prior to C/LFE) */ extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[]; /* Other world's standard channel maps (C/LFE prior to RL/RR) */ extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[]; /* bit masks to be passed to snd_pcm_chmap.channel_mask field */ #define SND_PCM_CHMAP_MASK_24 ((1U << 2) | (1U << 4)) #define SND_PCM_CHMAP_MASK_246 (SND_PCM_CHMAP_MASK_24 | (1U << 6)) #define SND_PCM_CHMAP_MASK_2468 (SND_PCM_CHMAP_MASK_246 | (1U << 8)) int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, const struct snd_pcm_chmap_elem *chmap, int max_channels, unsigned long private_value, struct snd_pcm_chmap **info_ret); #endif /* __SOUND_PCM_H */ include/sound/tlv.h +8 −0 Original line number Diff line number Diff line Loading @@ -86,4 +86,12 @@ #define TLV_DB_GAIN_MUTE -9999999 /* * channel-mapping TLV items * TLV length must match with num_channels */ #define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */ #define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */ #define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */ #endif /* __SOUND_TLV_H */ Loading
Documentation/sound/alsa/Channel-Mapping-API.txt 0 → 100644 +153 −0 Original line number Diff line number Diff line 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.
include/sound/ac97_codec.h +3 −0 Original line number Diff line number Diff line Loading @@ -422,6 +422,7 @@ */ struct snd_ac97; struct snd_pcm_chmap; struct snd_ac97_build_ops { int (*build_3d) (struct snd_ac97 *ac97); Loading Loading @@ -528,6 +529,8 @@ struct snd_ac97 { struct delayed_work power_work; #endif struct device dev; struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */ }; #define to_ac97_t(d) container_of(d, struct snd_ac97, dev) Loading
include/sound/asound.h +39 −0 Original line number Diff line number Diff line Loading @@ -472,6 +472,45 @@ enum { SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, }; /* 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, }; #define SNDRV_CHMAP_POSITION_MASK 0xffff #define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) #define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) #define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) Loading
include/sound/pcm.h +48 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,7 @@ struct snd_pcm_str { struct snd_info_entry *proc_xrun_debug_entry; #endif #endif struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ }; struct snd_pcm { Loading Loading @@ -1086,4 +1087,51 @@ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream return "Capture"; } /* * PCM channel-mapping control API */ /* array element of channel maps */ struct snd_pcm_chmap_elem { unsigned char channels; unsigned char map[15]; }; /* channel map information; retrieved via snd_kcontrol_chip() */ struct snd_pcm_chmap { struct snd_pcm *pcm; /* assigned PCM instance */ int stream; /* PLAYBACK or CAPTURE */ struct snd_kcontrol *kctl; const struct snd_pcm_chmap_elem *chmap; unsigned int max_channels; unsigned int channel_mask; /* optional: active channels bitmask */ void *private_data; /* optional: private data pointer */ }; /* get the PCM substream assigned to the given chmap info */ static inline struct snd_pcm_substream * snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx) { struct snd_pcm_substream *s; for (s = info->pcm->streams[info->stream].substream; s; s = s->next) if (s->number == idx) return s; return NULL; } /* ALSA-standard channel maps (RL/RR prior to C/LFE) */ extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[]; /* Other world's standard channel maps (C/LFE prior to RL/RR) */ extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[]; /* bit masks to be passed to snd_pcm_chmap.channel_mask field */ #define SND_PCM_CHMAP_MASK_24 ((1U << 2) | (1U << 4)) #define SND_PCM_CHMAP_MASK_246 (SND_PCM_CHMAP_MASK_24 | (1U << 6)) #define SND_PCM_CHMAP_MASK_2468 (SND_PCM_CHMAP_MASK_246 | (1U << 8)) int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream, const struct snd_pcm_chmap_elem *chmap, int max_channels, unsigned long private_value, struct snd_pcm_chmap **info_ret); #endif /* __SOUND_PCM_H */
include/sound/tlv.h +8 −0 Original line number Diff line number Diff line Loading @@ -86,4 +86,12 @@ #define TLV_DB_GAIN_MUTE -9999999 /* * channel-mapping TLV items * TLV length must match with num_channels */ #define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */ #define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */ #define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */ #endif /* __SOUND_TLV_H */