ALSA 用例配置

ALSA 用例配置。參考 ALSA 用例配置 來了解更詳細(xì)信息。

ALSA 用例配置

用例配置文件使用 配置文件 語法來定義靜態(tài)配置樹。該樹在運(yùn)行時(shí)根據(jù)配置樹中的條件和動(dòng)態(tài)變量進(jìn)行評(píng)估(修改)。使用 用例接口 API 解析結(jié)果并將其導(dǎo)出到應(yīng)用程序。

配置目錄和主文件名查找

查找路徑在 ucm.conf 文件中描述。配置結(jié)構(gòu)看起來像下面這樣:

UseCasePath.path1 {
  Directory "conf.virt.d"
  File "${OpenName}.conf"
}
UseCasePath.path2 {
  Directory "external"
  File "${OpenName}.conf"
}

現(xiàn)代 Linux 中,ucm.conf 文件通常位于/usr/share/alsa/ucm2/ucm.conf,該文件結(jié)構(gòu)大體如下:

#
# This is the toplevel file included from the alsa-lib.
#
# It allows to add extra lookups for the old kernels or so.
#
# You may specify the directory (relative to the toplevel) and
# the master configuration file which defines the verbs.
#

#
# Syntax version is reset for the master configuration file.
#

Syntax 3

Define.V1 ""        # non-empty string to enable ucm v1 paths
Define.V2Module yes # empty string to disable
Define.V2Name yes   # empty string to disable

If.driver {
    Condition {
        Type String
        Empty "${CardNumber}"
    }
    True {
        #
        # The probed path for no-hw-card:
        #
        #   ucm2/${OpenName}/${OpenName}.conf
        #
        UseCasePath {
            legacy {
                Directory "${OpenName}"
                File "${OpenName}.conf"
            }
        }
    }
    False {

        #
        # The probed path when hw-card is found:
        #
        #   ucm2/${KernelModule}/${KernelModule}.conf
        #   ucm2/${CardDriver}/${CardLongName}.conf
        #   ucm2/${CardDriver}/${CardDriver}.conf
        #

        If.V2Module {
            Condition {
                Type String
                Empty "${var:V2Module}"
            }
            False {
                Define.KernelModulePath "class/sound/card${CardNumber}/device/driver"
                Define.KernelModule "${sys:$KernelModulePath}"
                UseCasePath.module {
                    Directory "module"
                    File "${var:KernelModule}.conf"
                }
            }
        }
        If.V2Name {
            Condition {
                Type String
                Empty "${var:V2Name}"
            }
            False.UseCasePath {
                longname {
                    Directory "${CardDriver}"
                    File "${CardLongName}.conf"
                }
                driver {
                    Directory "${CardDriver}"
                    File "${CardDriver}.conf"
                }
            }
        }
    }
}

If.V1 {
    Condition {
        Type String
        Empty "${var:V1}"
    }
    False.If.v1_driver {
        Condition {
            Type String
            Empty "${CardNumber}"
        }
        True {
            #
            # The probed path for no-hw-card:
            #
            #   ucm/${OpenName}/${OpenName}.conf
            #
            UseCasePath.v1_legacy {
                Version 1
                Directory "${OpenName}"
                File "${OpenName}.conf"
            }
        }
        False {
            #
            # The ucm v1 probed path when hw-card is found:
            #
            #   ucm/${CardLongName}/${CardLongName}.conf
            #   ucm/${CardName}/${CardName}.conf or \
            #           ucm/${OpenName}/${OpenName}.conf
            #
            UseCasePath.v1_longname {
                Version 1
                Directory "${CardLongName}"
                File "${CardLongName}.conf"
            }
            If.v1_hw {
                Condition {
                    Type String
                    Haystack "${OpenName}"
                    Needle "hw:"
                }
                True.UseCasePath.v1_cardnamme {
                    Version 1
                    Directory "${CardName}"
                    File "${CardName}.conf"
                }
                False.UseCasePath.v1_openname {
                    Version 1
                    Directory "${OpenName}"
                    File "${OpenName}.conf"
                }
            }
        }
    }
}

UCM 主配置文件

每個(gè)聲卡都有一個(gè)主聲卡文件,它列出聲卡支持的所有用例 verbs,如:

# Example master file for blah sound card
# By Joe Blogs <joe@bloggs.org>
 
Syntax 6
 
# Use Case name for user interface
Comment "Nice Abstracted Soundcard"
 
# The file is divided into Use case sections. One section per use case verb.
 
SectionUseCase."Voice Call" {
  File "voice_call_blah"
  Comment "Make a voice phone call."
}
 
SectionUseCase."HiFi" {
  File "hifi_blah"
  Comment "Play and record HiFi quality Music."
}
 
# Define Value defaults
 
ValueDefaults {
  PlaybackChannels 4
  CaptureChannels 4
}
 
# Define boot / initialization sequence
# This sequence is skipped, when the soundcard was already configured by system
# (alsactl configuration was already created). The purpose is to not alter
# ALSA card controls which may be modified by user after initial settings.
 
BootSequence [
  cset "name='Master Playback Switch',index=2 0,0"
  cset "name='Master Playback Volume',index=2 25,25"
  msleep 50
  cset "name='Master Playback Switch',index=2 1,1"
  cset "name='Master Playback Volume',index=2 50,50"
]
 
# Define fixed boot sequence
# This sequence is always executed on boot (hotplug).
 
FixedBootSequence [
  cset "name='Something to toggle' toggle"
]

UCM verb 配置文件

verb 配置文件定義設(shè)備,修飾符和初始化序列。它有點(diǎn)像聲音配置文件。

# Example Use case verb section for Voice call blah
# By Joe Blogs <joe@blogs.com>
 
# verb global section
 
SectionVerb {
 
  # enable and disable sequences are compulsory
  EnableSequence [
    disdevall ""    # run DisableSequence for all devices
  ]
 
  DisableSequence [
    cset "name='Power Save' on"
  ]
 
  # Optional transition verb
  TransitionSequence."ToCaseName" [
    disdevall ""    # run DisableSequence for all devices
    msleep 1
  ]
 
  # Optional TQ and device values
  Value {
    TQ HiFi
    PlaybackChannels 6
  }
}
 
# Each device is described in new section. N devices are allowed
 
SectionDevice."Headphones" {
 
  SupportedDevice [
    "x"
    "y"
  ]
 
  # or (not both)
 
  ConflictingDevice [
    "x"
    "y"
  ]
 
  EnableSequence [
    ...
  ]
 
  DisableSequence [
    ...
  ]
 
  TransitionSequence."ToDevice" [
    ...
  ]
 
  Value {
    PlaybackVolume "name='Master Playback Volume',index=2"
    PlaybackSwitch "name='Master Playback Switch',index=2"
    PlaybackPCM "hw:${CardId},4"
  }
}
 
# Each modifier is described in new section. N modifiers are allowed
 
SectionModifier."Capture Voice" {
  Comment "Record voice call"
 
  SupportedDevice [
    "x"
    "y"
  ]
 
  # or (not both)
 
  ConflictingDevice [
    "x"
    "y"
  ]
 
  EnableSequence [
    ...
  ]
 
  DisableSequence [
    ...
  ]
 
  TransitionSequence."ToModifierName" [
    ...
  ]
 
  # Optional TQ and ALSA PCMs
  Value {
    TQ Voice
    CapturePCM "hw:${CardId},11"
    PlaybackMixerElem "Master"
    PlaybackVolume "name='Master Playback Volume',index=2"
    PlaybackSwitch "name='Master Playback Switch',index=2"
  }
}

序列圖

UCM verb sequence graph
UCM device sequence graph

序列命令

命令名稱 描述
enadev2 ARG 執(zhí)行設(shè)備啟用序列
disdev2 ARG 執(zhí)行設(shè)備禁用序列
disdevall "" 為 verb 中的所有設(shè)備執(zhí)行設(shè)備禁用序列
cdev ARG 為 ALSA 控制設(shè)備名調(diào)用 snd_ctl_open()
cset ARG ALSA 控制設(shè)置 - snd_ctl_ascii_elem_id_parse() + snd_ctl_ascii_value_parse()
cset-new ARG 創(chuàng)建新的 ALSA 用戶控制元素 - snd_ctl_ascii_elem_id_parse() + 描述
ctl-remove ARG 移除 ALSA 用戶控制元素 - snd_ctl_ascii_elem_id_parse()
sysw ARG 寫入 sysfs 樹
usleep ARG 休眠指定的微妙數(shù)
msleep ARG 休眠指定的毫妙數(shù)
exec ARG 執(zhí)行指定的命令 (不通過 shell - man execv)
shell ARG 執(zhí)行指定的命令 (使用 shell - man system)
cfg-save ARG 將 LibraryConfig 保存到文件
# Examples
cset "name='PCM Playback Volue',index=2 99"
cset-new "name='Bool2' type=bool,count=2 1,0"
cset-new "name='Enum' type=enum,labels='L1;L2;L3' 'L2'"
ctl-remove "name='Bool2'"
sysw "-/class/sound/ctl-led/speaker/card${CardNumber}/attach:Speaker Channel Switch"
usleep 10
exec "/bin/echo hello"
shell "set"
cfg-save "/tmp/test.conf:+pcm"

這些命令用在用例管理的配置文件里,而不是 alsaucm 命令行工具。

名稱

參考帶有 SND_USE_CASE_VERB 前綴的宏,如 SND_USE_CASE_VERB_HIFI 來了解已知 verb 的完整列表。

#define SND_USE_CASE_VERB_ANALOG_RADIO   "FM Analog Radio"
#define SND_USE_CASE_VERB_DIGITAL_RADIO   "FM Digital Radio"
#define SND_USE_CASE_VERB_HIFI   "HiFi"
#define SND_USE_CASE_VERB_HIFI_LOW_POWER   "HiFi Low Power"
#define SND_USE_CASE_VERB_INACTIVE   "Inactive"
#define SND_USE_CASE_VERB_IP_VOICECALL   "Voice Call IP"
#define SND_USE_CASE_VERB_VOICE   "Voice"
#define SND_USE_CASE_VERB_VOICE_LOW_POWER   "Voice Low Power"
#define SND_USE_CASE_VERB_VOICECALL   "Voice Call"

參考帶有 SND_USE_CASE_DEV 前綴的宏,如 SND_USE_CASE_DEV_SPEAKER 來了解已知設(shè)備的完整列表。

#define SND_USE_CASE_DEV_BLUETOOTH   "Bluetooth"
#define SND_USE_CASE_DEV_DIRECT   "Direct"
#define SND_USE_CASE_DEV_EARPIECE   "Earpiece"
#define SND_USE_CASE_DEV_HANDSET   "Handset"
#define SND_USE_CASE_DEV_HDMI   "HDMI"
#define SND_USE_CASE_DEV_HEADPHONES   "Headphones"
#define SND_USE_CASE_DEV_HEADSET   "Headset"
#define SND_USE_CASE_DEV_LINE   "Line"
#define SND_USE_CASE_DEV_MIC   "Mic"
#define SND_USE_CASE_DEV_NONE   "None"
#define SND_USE_CASE_DEV_SPDIF   "SPDIF"
#define SND_USE_CASE_DEV_SPEAKER   "Speaker"
#define SND_USE_CASE_DEV_USB   "USB"

如果存在多個(gè)同名的設(shè)備,則應(yīng)在這些名稱中添加數(shù)字后綴,如 HDMI1,HDMI2,HDMI3 等等。不允許有數(shù)字間隙。帶數(shù)字的名稱必須是連續(xù)的。為了提高可讀性,可以在名稱和索引之間放置空格(如“Line 1”)。為了此目的,設(shè)備名稱 “Line 1” 和 “Line1” 是相同的。

如果 EnableSequence/DisableSequence 控制硬件中的獨(dú)立路徑,則還建議分割播放和捕獲 UCM 設(shè)備并使用數(shù)字后綴。示例用例:使用筆記本電腦中的集成麥克風(fēng),而不是耳機(jī)中的麥克風(fēng)。

設(shè)備的優(yōu)先級(jí)由優(yōu)先級(jí)值決定(值越高 = 優(yōu)先級(jí)越高)。

參考帶有 SND_USE_CASE_MOD 前綴的宏,如 SND_USE_CASE_MOD_ECHO_REF 來了解已知修飾符的完整列表。

#define SND_USE_CASE_MOD_CAPTURE_MUSIC   "Capture Music"
#define SND_USE_CASE_MOD_CAPTURE_VOICE   "Capture Voice"
#define SND_USE_CASE_MOD_ECHO_REF   "Echo Reference"
#define SND_USE_CASE_MOD_PLAY_MUSIC   "Play Music"
#define SND_USE_CASE_MOD_PLAY_TONE   "Play Tone"
#define SND_USE_CASE_MOD_PLAY_VOICE   "Play Voice"

啟動(dòng)(alsactl)

FixedBootSequence 在每次啟動(dòng)時(shí)執(zhí)行。BootSequence 僅當(dāng)聲卡的配置缺失時(shí)才會(huì)執(zhí)行。目的是讓用戶修改音量或開關(guān)等配置。alsactl 確保持久性(將控制狀態(tài)存儲(chǔ)到 /var 樹并在下次啟動(dòng)時(shí)加載以前的狀態(tài))。

UCM sequence boot order (using udev and alsactl)

設(shè)備音量

預(yù)計(jì)應(yīng)用程序?qū)⑻幚硪袅吭O(shè)置。如果設(shè)備導(dǎo)出了硬件音量(MixerElem 或 Volume/Switch 值),不建議在 Enable / Disable 序列中為 verbs 或設(shè)備的音量設(shè)置設(shè)定固定值。默認(rèn)的音量設(shè)置應(yīng)該在 BootSequence 中設(shè)置。這種方案的目的是,允許用戶使用 alsactl 聲卡狀態(tài)管理覆蓋默認(rèn)值。

檢查清單:

  1. BootSequence 中設(shè)置默認(rèn)音量
  2. Verb 的 EnableSequence 應(yīng)確保所有設(shè)備都已關(guān)閉(混音器路徑),以避免同時(shí)使用設(shè)備 - 先前的狀態(tài)未知(請參閱 disdevalldisdev2 命令或創(chuàng)建新的自定義命令序列)
UCM volume

動(dòng)態(tài)配置樹

評(píng)估順序可能看起來和從用戶的角度看到的有點(diǎn)不同。首先,解析標(biāo)準(zhǔn) alsa-lib 配置樹。頂層的所有其它層都與這棵樹一起工作。它可能會(huì)將配置塊從所在的配置文件移動(dòng)到樹內(nèi)部。

Example configuration       | Parsed static tree      | Identical static tree
----------------------------+-------------------------+-------------------------------
If.1 {                      | If {                    | If.1.True.Define.VAR "A"
  True.Define.VAR "A"       |   1.True.Define.VAR "A" | If.2.True.Define.VAR "C"
}                           |   2.True.Define.VAR "C" | Define.VAR "B"
Define.VAR "B"              | }                       |
If.2 {                      | Define.VAR "B"          |
  True.Define.VAR "C"       |                         |
}                           |                         |

即使一個(gè)或兩個(gè)條件都被評(píng)估為真,變量 VAR 也將始終被評(píng)估為 B,因?yàn)榈谝粋€(gè) If 塊位于非嵌套的 Define 之前。在文本配置解析器中第二個(gè) If 塊被附加到第一個(gè) If 塊(配置樹中的 Define 之前)中。

語法

除非另有說明,否則使用語法版本 4。

Syntax 4

包含

有兩種方法可以包含其它配置文件。

靜態(tài)包含

靜態(tài)包含繼承自標(biāo)準(zhǔn) alsa-lib 配置語法。它可以放在配置文件的任何位置。搜索路徑由根 alsa 配置路徑(通常為 /usr/share/alsa 的 ucm2 目錄)組成。

<some/path/file.conf>        # include file using the search path
</absolute/path/file.conf>   # include file using the absolute path

惰性包含

惰性包含在運(yùn)行時(shí)進(jìn)行評(píng)估。根路徑是 ucm2 樹。絕對包含將 ucm2 絕對路徑附加到指定路徑。相對包含是相對于包含 Include 配置塊的文件而言的。

配置樹評(píng)估

靜態(tài)配置樹的評(píng)估按照特定順序進(jìn)行(見下表)。當(dāng)動(dòng)態(tài)配置樹發(fā)生變化時(shí),將重新啟動(dòng)評(píng)估序列以評(píng)估所有可能的更改(新的 DefineIncludeIf 塊)。

評(píng)估順序 配置塊 評(píng)估重啟
1 Define No
2 Include Yes
3 If Yes

替換

配置樹中的動(dòng)態(tài)樹標(biāo)識(shí)符和指定值被替換。替換字符串如下表所示。

替換字符串
${OpenName} 原始 UCM 聲卡名稱(傳給 snd_use_case_mgr_open()
${ConfLibDir} 庫頂層配置目錄(如 /usr/share/alsa)
${ConfTopDir} 頂層 UCM 配置目錄(如 /usr/share/alsa/ucm2)
${ConfDir} 聲卡的 UCM 配置目錄(如 /usr/share/alsa/ucm2/conf.d/USB-Audio)
${ConfName} 配置名稱(如 USB-Audio.conf)
${CardNumber} 真實(shí)的 ALSA 聲卡號(hào)(或者對于虛擬 UCM 聲卡為空字符串)
${CardId} ALSA 聲卡標(biāo)識(shí)符(參見 snd_ctl_card_info_get_id()
${CardDriver} ALSA 聲卡驅(qū)動(dòng)(參見 snd_ctl_card_info_get_driver()
${CardName} ALSA 聲卡名稱(參見 snd_ctl_card_info_get_name()
${CardLongName} ALSA 聲卡長名稱(參見 snd_ctl_card_info_get_longname()
${CardComponents} ALSA 聲卡組件(參見 [snd_ctl_card_info_get_components()](https://www.alsa-project.org/alsa-doc/alsa-lib/group___control.html#ga2181aa6bf919fd1342b259d2f3af755b "Get the sound cards "components" property from the given info object."))
${env:<str>} 環(huán)境變量 <str>
${sys:<str>} sysfs 文件 <str> 的內(nèi)容
${var:<str>} UCM 解析器變量(使用 Define 塊創(chuàng)建)
${eval:<str>} 計(jì)算表達(dá)式,如 ($var+2)/3 [Syntax 5]
${find-card:<str>} 查找聲卡 - 參考 查找聲卡替換 部分
${find-device:<str>} 查找設(shè)備 - 參考 查找設(shè)備替換 部分

聲卡相關(guān)的這些部分信息,可以通過 alsa-utils 包里的 amixer 工具來查看,如:

$ amixer info
Card default 'pulse'/'PulseAudio'
  Mixer name    : 'PulseAudio'
  Components    : ''
  Controls      : 4
  Simple ctrls  : 2

amixer 工具實(shí)現(xiàn) info 操作的 info() 函數(shù)定義 (位與 alsa-utils/amixer/amixer.c) 如下:

static int info(void)
{
    int err;
    snd_ctl_t *handle;
    snd_mixer_t *mhandle;
    snd_ctl_card_info_t *info;
    snd_ctl_elem_list_t *clist;
    snd_ctl_card_info_alloca(&info);
    snd_ctl_elem_list_alloca(&clist);
    
    if ((err = snd_ctl_open(&handle, card, 0)) < 0) {
        error("Control device %s open error: %s", card, snd_strerror(err));
        return err;
    }
    
    if ((err = snd_ctl_card_info(handle, info)) < 0) {
        error("Control device %s hw info error: %s", card, snd_strerror(err));
        return err;
    }
    printf("Card %s '%s'/'%s'\n", card, snd_ctl_card_info_get_id(info),
           snd_ctl_card_info_get_longname(info));
    printf("  Mixer name    : '%s'\n", snd_ctl_card_info_get_mixername(info));
    printf("  Components    : '%s'\n", snd_ctl_card_info_get_components(info));
    if ((err = snd_ctl_elem_list(handle, clist)) < 0) {
        error("snd_ctl_elem_list failure: %s", snd_strerror(err));
    } else {
        printf("  Controls      : %i\n", snd_ctl_elem_list_get_count(clist));
    }
    snd_ctl_close(handle);
    if ((err = snd_mixer_open(&mhandle, 0)) < 0) {
        error("Mixer open error: %s", snd_strerror(err));
        return err;
    }
    if (smixer_level == 0 && (err = snd_mixer_attach(mhandle, card)) < 0) {
        error("Mixer attach %s error: %s", card, snd_strerror(err));
        snd_mixer_close(mhandle);
        return err;
    }
    if ((err = snd_mixer_selem_register(mhandle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
        error("Mixer register error: %s", snd_strerror(err));
        snd_mixer_close(mhandle);
        return err;
    }
    err = snd_mixer_load(mhandle);
    if (err < 0) {
        error("Mixer load %s error: %s", card, snd_strerror(err));
        snd_mixer_close(mhandle);
        return err;
    }
    printf("  Simple ctrls  : %i\n", snd_mixer_get_count(mhandle));
    snd_mixer_close(mhandle);
    return 0;
}

amixer info 輸出的信息的格式如下:

Card ${Card} '${CardId}'/'${CardLongName}'
  Mixer name    : 'PulseAudio'
  Components    : '${CardComponents}'
  Controls      : 4
  Simple ctrls  : 2

${CardComponents} 信息由聲卡驅(qū)動(dòng)程序返回,如 Intel 的 ALC 5651 聲卡的驅(qū)動(dòng) (位于 sound/soc/intel/boards/bytcr_rt5651.c):

    snprintf(byt_rt5651_components, sizeof(byt_rt5651_components),
         "cfg-spk:%s cfg-mic:%s%s",
         (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ? "1" : "2",
         mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
         (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ?
            " cfg-hp:lrswap" : "");
    byt_rt5651_card.components = byt_rt5651_components;
#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES)
    snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
         "bytcr-rt5651-%s-spk-%s-mic%s",
         (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ?
            "mono" : "stereo",
         mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
         (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ?
            "-hp-swapped" : "");
    byt_rt5651_card.long_name = byt_rt5651_long_name;
#endif

特殊的整個(gè)字符串替換

替換字符串
${evali:<str>} 計(jì)算表達(dá)式,如 ($var+2)/3 [Syntax 6];目標(biāo)節(jié)點(diǎn)將是整數(shù);僅在 LibraryConfig 子樹中替換

查找聲卡替換

這種替換查找 ALSA 聲卡并返回適當(dāng)?shù)臉?biāo)識(shí)符或聲卡號(hào)(參見返回參數(shù))。

使用示例:

${find-card:field=name,regex='^acp$',return=number}

參數(shù):

參數(shù) 描述
return 返回值類型 (id, number),默認(rèn)值為 id
field 查找的字段 (id, driver, name, longname, mixername, components)
regex 字段匹配的 regex 字符串

查找設(shè)備替換

使用示例:

${find-device:type=pcm,field=name,regex='DMIC'}
參數(shù) 描述
type 設(shè)備類型 (pcm)
stream stream 類型 (playback, capture),默認(rèn)為 playback
field 查找的字段 (id, name, subname)
regex 字段匹配的 regex 字符串

變量定義

可以使用 DefineDefineRegex 塊來定義和改變變量。Define 塊如下所示:

Define {
  variable1 "a"
  variable2 "b"
}

DefineRegex 允許提取子字符串,例如:

DefineRegex.rval {
  Regex "(hello)|(regex)"
  String "hello, it's my regex"
}

結(jié)果將存儲(chǔ)到變量 rval1 中作為 hello,存儲(chǔ)到變量 rval2 中作為 regex(每個(gè)匹配的子字符串都存儲(chǔ)到帶有序列號(hào)后綴的單獨(dú)變量中)。

例如可以使用 ${var:rval1} 引用替換變量。

宏是為 Syntax 版本 6 添加的。DefineMacro 定義新的宏如下:

DefineMacro.macro1 {
  Define.a "${var:__arg1}"
  Define.b "${var:__other}"
  # Device or any other block may be defined here...
}

宏中的參數(shù)被稱為帶有雙下劃線名稱前綴的變量(如_ variable)。DefineMacro 子樹中的配置塊總是在實(shí)例化時(shí)計(jì)算(包括參數(shù)和變量)。

宏可以使用下列方式實(shí)例化(擴(kuò)展):

# short version
Macro.id1.macro1 "arg1='something 1',other='other x'"
 
# long version
Macro.id1.macro1 {
  arg1 'something 1'
  other 'other x'
}

第二個(gè)標(biāo)識(shí)符(示例中的 id1)必須是唯一的,但其內(nèi)容被忽略。它僅僅區(qū)分子樹中的項(xiàng)(允許一個(gè)宏有多個(gè)實(shí)例)。

條件

配置樹計(jì)算支持條件 - If 塊。每個(gè) If 塊必須定義一個(gè) Condition 塊和 TrueFalse 塊或兩者。TrueFalse 塊將在計(jì)算 Condition 時(shí)合并到父樹(If 塊定義的地方)。

示例:

If.uniqueid {
  Condition {
    Type String
    Haystack "abcd"
    Needle "a"
  }
  True {
    Define.a a
    define.b b
  }
}

True(Type AlwaysTrue)

僅執(zhí)行 True 塊。它可以被用于改變計(jì)算順序,就像 配置樹 段中解釋的那樣。

字符串是空 (Type String)

字段 描述
Empty 字符串

字符串相等 (Type String)

字段 描述
String1 字符串
String2 字符串中的子字符串

子字符串存在 (Type String)

字段 描述
Haystack 字符串
Needle 字符串中的子字符串

Regex 匹配 (Type RegexMatch)

字段 描述
String 字符串
Regex regex 表達(dá)式(擴(kuò)展的 posix,忽略大小寫)

ALSA 控制元素存在 (Type ControlExists)

字段 描述
Device ALSA 控制設(shè)備(參考 snd_ctl_open()
Control ASCII 形式的控制項(xiàng)(使用 snd_ctl_ascii_elem_id_parse() 解析)
ControlEnum 枚舉控制項(xiàng)的值(可選)

示例:

If.fmic {
  Condition {
    Type ControlExists
    Control "name='Front Mic Playback Switch'"
  }
  True {
    ...
  }
}

變體

為了避免在配置更改很少的情況下許多配置文件的重復(fù),而提供了變體擴(kuò)展。變體是為 語法 版本 6 添加的。

下面的示例將創(chuàng)建兩個(gè) verbs - "HiFi" 和 "HiFi 7.1",它們的 "Speaker" 設(shè)備具有不同的播放通道數(shù)(2 和 8)。

示例(主配置文件):

SectionUseCase."HiFi" {
  File "HiFi.conf"
  Variant."HiFi" {
    Comment "HiFi"
  }
  Variant."HiFi 7+1" {
    Comment "HiFi 7.1"
  }
}

示例(verb 配置文件 - HiFi.conf):

SectionDevice."Speaker" {
  Value {
    PlaybackChannels 2
  }
  Variant."HiFi 7+1".Value {
    PlaybackChannels 8
  }
}

原文

Done.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容