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 狀態下允許。在其他狀態下呼叫時,應返回錯誤。