ALSA PCM 通道映射 API¶
Takashi Iwai <tiwai@suse.de>
概述¶
通道映射 API 允许用户查询可能的通道映射和当前的通道映射,还可以选择修改当前流的通道映射。
通道映射是每个 PCM 通道的位置数组。通常,立体声 PCM 流的通道映射为 { front_left, front_right }
,而 4.0 环绕声 PCM 流的通道映射为 { front left, front right, rear left, rear right }.
到目前为止,问题在于我们没有明确的标准通道映射,应用程序也无法知道哪个通道对应哪个(扬声器)位置。因此,应用程序为 5.1 输出应用了错误的通道,你突然会听到来自后方的奇怪声音。或者,一些设备秘密地假设中心/低频效果是第三/第四通道,而其他设备则假设 C/LFE 是第五/第六通道。
此外,一些设备(如 HDMI)即使在总通道数相同的情况下,也可以配置不同的扬声器位置。但是,由于缺乏通道映射规范,无法指定这一点。这些是新的通道映射 API 的主要动机。
设计¶
实际上,“通道映射 API”在内核/用户空间 ABI 视角下并没有引入任何新东西。它仅使用现有的控制元素功能。
作为基础设计,每个 PCM 子流可以包含一个提供通道映射信息和配置的控制元素。此元素由以下内容指定:
iface = SNDRV_CTL_ELEM_IFACE_PCM
name = “Playback Channel Map” 或 “Capture Channel Map”
device = 为分配的 PCM 子流分配的相同设备编号
index = 为分配的 PCM 子流分配的相同索引编号
请注意,名称因 PCM 子流方向而异。
每个控制元素至少提供 TLV 读取操作和读取操作。可以选择提供写入操作,以允许用户动态更改通道映射。
TLV¶
TLV 操作提供可用通道映射的列表。通道映射的列表项通常是 type data-bytes ch0 ch1 ch2...
的 TLV,其中 type 是 TLV 类型值,第二个参数是通道值的总字节数(不是数字),其余是每个通道的位置值。
作为 TLV 类型,可以使用 SNDRV_CTL_TLVT_CHMAP_FIXED
、SNDRV_CTL_TLV_CHMAP_VAR
或 SNDRV_CTL_TLVT_CHMAP_PAIRED
。 _FIXED
类型用于通道位置固定的通道映射,而后两种类型用于灵活的通道位置。_VAR
类型用于所有通道都可以自由交换的通道映射,而 _PAIRED
类型用于成对通道可以交换的通道映射。例如,当您有 {FL/FR/RL/RR} 通道映射时,_PAIRED
类型将允许您仅交换 {RL/RR/FL/FR},而 _VAR
类型甚至允许交换 FL 和 RR。
这些新的 TLV 类型在 sound/tlv.h
中定义。
可用的通道位置值在 sound/asound.h
中定义,这是一个节选
/* 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,
};
当 PCM 流可以提供多个通道映射时,您可以在 TLV 容器类型中提供多个通道映射。要返回的 TLV 数据将包含如下内容:
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
通道位置以 LSB 16 位提供。高位用于位标志。
#define SNDRV_CHMAP_POSITION_MASK 0xffff
#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16)
#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16)
SNDRV_CHMAP_PHASE_INVERSE
指示通道的相位已反转(因此,将左右通道相加几乎会导致静音)。一些数字麦克风设备具有此功能。
当设置 SNDRV_CHMAP_DRIVER_SPEC
时,所有通道位置值都不遵循上述标准定义,而是特定于驱动程序的。
读取操作¶
控制读取操作用于提供给定流的当前通道映射。控制元素返回一个整数数组,其中包含每个通道的位置。
当在指定通道数之前执行此操作时(即,设置了 hw_params),它应返回设置为 UNKNOWN
的所有通道。
写入操作¶
控制写入操作是可选的,仅适用于可以动态更改通道配置的设备,例如 HDMI。用户需要传递一个整数值,其中包含分配的 PCM 子流的所有通道的有效通道位置。
仅允许在 PCM PREPARED 状态下执行此操作。在其他状态下调用时,它应返回错误。