| 
									
										
										
										
											2012-08-15 16:06:43 +02:00
										 |  |  | 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, | 
					
						
							| 
									
										
										
										
											2012-09-12 18:06:54 +02:00
										 |  |  | 	SNDRV_CHMAP_NA,		/* N/A, silent */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_MONO,	/* mono stream */ | 
					
						
							|  |  |  | 	/* this follows the alsa-lib mixer channel value + 3 */ | 
					
						
							| 
									
										
										
										
											2012-08-15 16:06:43 +02:00
										 |  |  | 	SNDRV_CHMAP_FL,		/* front left */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_FR,		/* front right */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_RL,		/* rear left */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_RR,		/* rear right */ | 
					
						
							| 
									
										
										
										
											2012-08-21 14:47:18 +02:00
										 |  |  | 	SNDRV_CHMAP_FC,		/* front center */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_LFE,	/* LFE */ | 
					
						
							| 
									
										
										
										
											2012-08-15 16:06:43 +02:00
										 |  |  | 	SNDRV_CHMAP_SL,		/* side left */ | 
					
						
							|  |  |  | 	SNDRV_CHMAP_SR,		/* side right */ | 
					
						
							| 
									
										
										
										
											2012-08-21 14:47:18 +02:00
										 |  |  | 	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 */ | 
					
						
							| 
									
										
										
										
											2012-08-15 16:06:43 +02:00
										 |  |  | 	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 */ | 
					
						
							| 
									
										
										
										
											2012-09-12 18:06:54 +02:00
										 |  |  | 	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, | 
					
						
							| 
									
										
										
										
											2012-08-15 16:06:43 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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. |