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 输出时会应用错误的通道,您会突然从后方听到奇怪的声音。或者,有些设备私下认为中置/LFE 是第三/第四通道,而另一些设备则认为 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 状态下允许。在其他状态下调用时,应返回错误。