拓?fù)?2.0

這是現(xiàn)有 ALSA conf 拓?fù)涓袷街系母呒?jí)關(guān)鍵字?jǐn)U展,旨在:

  • 通過(guò)提供高級(jí)的 “classes” 來(lái)簡(jiǎn)化 ALSA conf 拓?fù)涠x。通過(guò)這種方式,拓?fù)湓O(shè)計(jì)者可以為經(jīng)常定義的對(duì)象編寫更少的配置。
  • 允許簡(jiǎn)單地重用對(duì)象。定義一次并重用(如 M4),能夠更改默認(rèn)的對(duì)象配置屬性。
  • 允許數(shù)據(jù)類型和值驗(yàn)證。現(xiàn)在還沒有這樣做,并且經(jīng)常出現(xiàn)在固件錯(cuò)誤報(bào)告中。

要素

典型的 2.0 配置文件由以下組件組成:

  • 類(Classes)
  • 對(duì)象(Objects)
  • 參數(shù)(Arguments)
  • 條件包含(Conditional includes)

今天的拓?fù)溆幸恍┏R姷亩x,常常通過(guò)對(duì)配置進(jìn)行細(xì)微的改變來(lái)重用,例如 widgets(組件)、流水線、dais、pcm 和 controls。拓?fù)?2.0 引入了可重用的類定義的概念,你可以使用它來(lái)創(chuàng)建常用的拓?fù)鋵?duì)象。類通過(guò)一個(gè)新的關(guān)鍵字 Class 來(lái)定義。

類定義始終以 Class 關(guān)鍵字開頭,后跟兩個(gè)節(jié)點(diǎn)。第一個(gè)節(jié)點(diǎn)包含類的組,第二個(gè)節(jié)點(diǎn)包含類名。如:

Class.Base.data {}

請(qǐng)注意,‘.’ 是 alsaconf 語(yǔ)法中的節(jié)點(diǎn)分隔符。在上面的行中,Base 是類的組,data 是類名。目前,alsatplg 編譯器支持以下類組:widget、pipeline、DAI、control 和 base。大多數(shù)常用的拓?fù)鋵?duì)象都可以分為這些組之一。如果需要新的類組,則應(yīng)更新 alsatplg 編譯器以添加對(duì)其的支持。

類要素

簡(jiǎn)約的類定義應(yīng)包含以下內(nèi)容:

  • 使用關(guān)鍵字 DefineAttribute 聲明一個(gè)或多個(gè)屬性。屬性是用于描述對(duì)象的參數(shù)。比如:
DefineAttribute."name" {
        type "string"
}

“name” 是字符串類型的屬性。

  • 具有構(gòu)造函器數(shù)組和唯一屬性名稱的基本屬性限定符。屬性限定符應(yīng)該在類定義的 attributes {} 節(jié)點(diǎn)中聲明。
# attribute qualifiers
attributes {
        #
        # This tells the compiler how to construct the object's name. For example, if the
        # name attribute is set to "EQIIR-Coefficients", the object name will be
        # constructed as "class_name.EQIIR-Coefficients"
        #
        !constructor [
                "name"
        ]
        #
        # objects of the same class instantiated within the same alsaconf node have unique
        # name attribute
        #
        unique  "name"
}

一個(gè)簡(jiǎn)單的類

以下示例演示了具有兩個(gè)屬性和屬性限定符的簡(jiǎn)單類定義:

Class.Base."data" {

        # name for the data object
        DefineAttribute."name" {
                type    "string"
        }

        # bytes data
        DefineAttribute."bytes" {
                type    "string"
        }

        # attribute qualifiers
        attributes {
                #
                # This tells the compiler how to construct the object's name. For example, if the
                # name attribute is set to "EQIIR-Coefficients", the object name will be
                # constructed as "data.EQIIR-Coefficients"
                #
                !constructor [
                        "name"
                ]
                #
                # data objects instantiated within the same alsaconf node should have unique
                # name attribute
                #
                unique  "name"
        }
}

data 類定義屬于 Base 類組,它包含兩個(gè)屬性,name 和 bytes,兩者的類型都是 string。除非另有指定,默認(rèn)情況下所有屬性都是 integer 類型的,如上例所示。目前,拓?fù)?2.0 僅支持 integerstring 類型的屬性。

屬性限定符用于描述如何從類定義實(shí)例化對(duì)象,并驗(yàn)證屬性值。

在上面的定義中,constructor 數(shù)組告訴編譯器如何構(gòu)建對(duì)象的名稱。使用名稱 EQIIR-Coefficients 實(shí)例化的 data 對(duì)象將被賦予名稱 data.EQIIR-Coefficients,即類名后跟 ‘.’,后跟由 ‘.’ 分隔的構(gòu)造器屬性值。

unique 限定符指示在同一個(gè) alsaconf 節(jié)點(diǎn)中實(shí)例化的多個(gè) data 對(duì)象的 name 屬性應(yīng)該具有唯一的值。如果在同一個(gè) alsaconf 節(jié)點(diǎn)內(nèi)實(shí)例化具有相同 name 屬性的兩個(gè) data 對(duì)象,則 不會(huì) 發(fā)生錯(cuò)誤,但兩個(gè)對(duì)象實(shí)例將被合并。此外,第二個(gè)實(shí)例中的屬性值將覆蓋第一個(gè)實(shí)例中的屬性值。因此,拓?fù)渚帉懻哂胸?zé)任確保同一父節(jié)點(diǎn)中的相同類的多個(gè)實(shí)例具有不同的唯一屬性值。

讓我們考慮另一個(gè)類定義示例,屬于類組 Widgetpga widget (在 tools/topology/topology2/include/components/volume.conf 文件中定義):

Class.Widget."pga" {
        #
        # Pipeline ID for the pga widget object
        #
        DefineAttribute."index" {}

        #
        # pga object instance
        #
        DefineAttribute."instance" {}

        # attribute qualifiers
        attributes {
                #
                # The PGA widget name is constructed using the index and instance
                # attributes. For ex: "pga.1.1" or "pga.10.2" etc.
                #
                !constructor [
                        "index"
                        "instance"
                ]

                #
                # pga widget objects instantiated within the same alsaconf node should have unique
                # instance attribute
                #
                unique  "instance"
        }
}

請(qǐng)注意,pga 對(duì)象名由類名 pga 后跟兩個(gè)屬性值,index 和 instance 構(gòu)成,比如,pga.1.1。由于屬性定義未指定類型,默認(rèn)情況下,這兩個(gè)屬性的類型都為 integer。在實(shí)踐中,唯一的 instance 屬性也應(yīng)該是構(gòu)造器的一部分。

屬性默認(rèn)值

擴(kuò)展類定義以為其屬性提供默認(rèn)值是可選的。讓我們?yōu)?pga 類添加一個(gè)類型為 string 的屬性 uuid,并給它一個(gè)默認(rèn)值:

Class.Widget."pga" {
        #
        # Pipeline ID for the pga widget object
        #
        DefineAttribute."index" {}

        #
        # pga object instance
        #
        DefineAttribute."instance" {}

        DefineAttribute."uuid" {
                type "string"
        }

        # attribute qualifiers
        attributes {
                #
                # The PGA widget name is constructed using the index and instance
                # attributes. For ex: "pga.1.1" or "pga.10.2" etc.
                #
                !constructor [
                        "index"
                        "instance"
                ]

                #
                # pga widget objects instantiated within the same alsaconf node should have unique
                # instance attribute
                #
                unique  "instance"
        }

        # default attribute values
        uuid                    "7e:67:7e:b7:f4:5f:88:41:af:14:fb:a8:bd:bf:86:82"

}

所有 pga 對(duì)象將自動(dòng)獲得默認(rèn)的 uuid,如上面在類定義中指定的那樣。ALSA 拓?fù)?2.0 類定義的布局大體為 屬性聲明-對(duì)象構(gòu)造器數(shù)組聲明和屬性限定符-屬性默認(rèn)值。

高級(jí)屬性限定符

除了強(qiáng)制性的基本屬性限定符外,還可以使用以下的高級(jí)關(guān)鍵字限定類定義中的屬性:

  • Mandatory:應(yīng)在對(duì)象實(shí)例中給由 mandatory 限定的屬性提供值,否則 alsatplg 編譯器將報(bào)錯(cuò)。類定義中具有默認(rèn)值的屬性不需要被限定為 mandatory。另請(qǐng)注意,構(gòu)造器數(shù)組中的屬性默認(rèn)為 mandatory 的,因?yàn)樗鼈兪菢?gòu)建對(duì)象名稱所必需的。
  • Immutable:在類定義中設(shè)置的屬性值,不能在對(duì)象實(shí)例中修改。
  • Deprecated:已棄用且不應(yīng)在對(duì)象實(shí)例中設(shè)置的屬性。
  • Automatic:具體的值由 alsatplg 編譯器計(jì)算的屬性。

讓我們?cè)?pga 類定義中添加一些額外的屬性和高級(jí)限定符:

Class.Widget."pga" {
        # attribute definitions
        DefineAttribute.instance {
                type    "integer"
        }
        DefineAttribute.index {
                type    "integer"
        }
        DefineAttribute."type" {
                type    "string"
        }
        DefineAttribute."uuid" {
                type    "string"
        }
        DefineAttribute."preload_count" {}

        # attribute qualifiers
        attributes {
                #
                # The PGA widget name is constructed using the index and instance attributes.
                # For ex: "pga.1.1" or "pga.10.2" etc.
                #
                !constructor [
                        "index"
                        "instance"
                ]

                #
                # immutable attributes should be given default values and cannot be modified in the object instance
                #
                !immutable [
                        "uuid"
                        "type"
                ]

                #
                # deprecated attributes should not be added in the object instance
                #
                !deprecated [
                        "preload_count"
                ]

                #
                # pga widget objects instantiated within the same alsaconf node should have
                # unique instance attribute
                #
                unique  "instance"
        }

        # default attribute values
        type            "pga"
        uuid            "7e:67:7e:b7:f4:5f:88:41:af:14:fb:a8:bd:bf:86:82"
}

除了 unique 屬性限定符外,包括構(gòu)造器 constructor 在內(nèi)的其它屬性限定符,在類定義的 attributes {} 節(jié)點(diǎn)中,屬性限定符前面加感嘆號(hào)(!),后面跟屬性名數(shù)組,在屬性名數(shù)組中,不同的屬性名用空白符隔開。

自動(dòng)屬性

在某些情況下,屬性值取決于其它屬性值,并且需要在構(gòu)建時(shí)計(jì)算。在類定義中這種屬性用 automatic 關(guān)鍵字修飾。請(qǐng)參閱 buffer 以獲取完整的類定義。

Class.Widget."buffer" {
        # Other attributes skipped for simplicity.

        #
        # Buffer size in bytes. Will be calculated based on the parameters of the pipeline to in which the
        # buffer object belongs
        #
        DefineAttribute."size" {
                # Token reference and type
                token_ref       "sof_tkn_buffer.word"
        }

        attributes {
                #
                # size attribute value for buffer objects is computed in the compiler
                #
                !automatic [
                        "size"
                ]
        }
}

在上面的示例中,buffersize 屬性值基于 buffer 所屬的流水線的參數(shù)計(jì)算。目前,alsatplg 編譯器僅支持計(jì)算 buffer 對(duì)象的自動(dòng)屬性 size。如有必要,應(yīng)在 alsatplg 編譯器中添加對(duì)新的類定義中的自動(dòng)屬性的支持。

在目前版本的 alsatplg (1.2.11) 編譯器源碼中,沒有找到對(duì)于 automaticdeprecated 屬性修飾符的處理,只找到了對(duì)于 constructorimmutable、mandatoryunique 屬性修飾符的處理。

屬性約束

拓?fù)?2.0 的重要特性之一是驗(yàn)證提供給對(duì)象的值。這通過(guò)給屬性定義添加約束來(lái)實(shí)現(xiàn)??梢允褂?constraints 關(guān)鍵字來(lái)給屬性添加約束:

DefineAttribute."foo" {
        constraints {}
}

目前,支持三種類型的約束:

  • min:屬性最小值,僅適用于整數(shù)類型的屬性。
  • max:屬性最大值,僅適用于整數(shù)類型的屬性。
    比如,pga 類定義可以擴(kuò)展為具有屬性 ramp_step_ms,其 min 和 max 值如下:
DefineAttribute."ramp_step_ms" {
        constraints {
                min 200
                max 500
        }
}
  • valid values:可接受的人類可讀值的數(shù)組,僅適用于字符串類型的屬性。
    例如,可以給 pga 類添加具有預(yù)定義值的 ramp_step_type 屬性,如下面這樣:
DefineAttribute."ramp_step_type" {
        type    "string"
        constraints {
                !valid_values [
                        "linear"
                        "log"
                        "linear_zc"
                        "log_zc"
                ]
        }
}

當(dāng)使用不屬于 valid_values 數(shù)組的 ramp_step_type 值實(shí)例化 pga 類時(shí),alsatplg 編譯器會(huì)報(bào)錯(cuò)并輸出有效值列表。

具有 token 引用的屬性

通常,許多對(duì)象包含由元組數(shù)組集合組成的私有數(shù)據(jù)部分。類定義中的某些屬性可能需要打包到元組數(shù)組中。此類屬性通過(guò) token_ref 節(jié)點(diǎn)進(jìn)行標(biāo)識(shí),該節(jié)點(diǎn)包含屬性應(yīng)構(gòu)建到的元組數(shù)組的名稱。例如,pga 類中的 ramp_step_msramp_step_type 屬性都需要添加到元組數(shù)組中。因此,它們包含 token_ref 節(jié)點(diǎn),其值為 volume.word,指示屬性應(yīng)與 word 類型的 volume 元組數(shù)組打包在一起:

#
# Volume ramp step in milliseconds
#
DefineAttribute."ramp_step_ms" {
        # Token set reference name
        token_ref       "volume.word"
        constraints {
                min 200
                max 500
        }
}
DefineAttribute."ramp_step_type" {
        type    "string"
        # Token set reference name
        token_ref       "volume.word"
        constraints {
                !valid_values [
                        "linear"
                        "log"
                        "linear_zc"
                        "log_zc"
                ]
        }
}

有時(shí),屬性的 valid_values 值可能需要從人類可讀的值轉(zhuǎn)換為整數(shù)元組值,以便內(nèi)核驅(qū)動(dòng)程序可以正確地解析它們。在上面的示例中,ramp_step_type 的有效值被定義為人類可讀的字符串值,為 linear 和 log 等。這些值在添加到元組數(shù)組之前會(huì)被轉(zhuǎn)換為元組值 (0, 1, 等)。

DefineAttribute."ramp_step_type" {
        type    "string"
        # Token set reference name
        token_ref       "volume.word"
        constraints {
                !valid_values [
                        "linear"
                        "log"
                        "linear_zc"
                        "log_zc"
                ]
                !tuple_values [
                        0
                        1
                        2
                        3
                ]
        }
}

完整的類定義

將所有內(nèi)容放在一起,以下示例演示了 pga Widget 類的完整定義 (sof/tools/topology/topology2/include/components/volume.conf):

Class.Widget."pga" {
    #
    # Pipeline ID for the pga widget object
    #
    DefineAttribute."index" {}

    #
    # pga object instance
    #
    DefineAttribute."instance" {}

    #include common component definition
    <include/components/widget-common.conf>

    #
    # Bespoke attributes for PGA
    #

    #
    # Volume ramp step type. The values provided will be translated to integer values
    # as specified in the tuple_values array.
    # For example: "linear" is translated to 0, "log" to 1 etc.
    #
    DefineAttribute."ramp_step_type" {
        type    "string"
        # Token set reference name
        token_ref   "volume.word"
        constraints {
            !valid_values [
                "linear"
                "log"
                "linear_zc"
                "log_zc"
            ]
            !tuple_values [
                0
                1
                2
                3
            ]
        }
    }

    #
    # Volume ramp step in milliseconds
    #
    DefineAttribute."ramp_step_ms" {
        # Token set reference name
        token_ref   "volume.word"
    }

    # Attribute categories
    attributes {
        #
        # The PGA widget name would be constructed using the index and instance attributes.
        # For ex: "pga.1.1" or "pga.10.2" etc.
        #
        !constructor [
            "index"
            "instance"
        ]

        #
        # immutable attributes cannot be modified in the object instance
        #
        !immutable [
            "uuid"
            "type"
        ]

        #
        # deprecated attributes should not be added in the object instance
        #
        !deprecated [
            "preload_count"
        ]

        #
        # pga widget objects instantiated within the same alsaconf node must have unique
        # instance attribute
        #
        unique  "instance"
    }

    #
    # pga widget mixer controls
    #
    Object.Control {
        # volume mixer control
        mixer."1" {
            #Channel register and shift for Front Left/Right
            Object.Base.channel.1 {
                name    "fl"
                shift   0
            }
            Object.Base.channel.2 {
                name    "fr"
            }

            Object.Base.ops.1 {
                name    "ctl"
                info    "volsw"
                #256 binds the mixer control to volume get/put handlers
                get     256
                put     256
            }
            max 32
        }

        # mute switch control
        mixer."2" {
            Object.Base.channel.1 {
                name    "flw"
                reg 2
                shift   0
            }
            Object.Base.channel.2 {
                name    "fl"
                reg 2
                shift   1
            }
            Object.Base.channel.3 {
                name    "fr"
                reg 2
                shift   2
            }
            Object.Base.channel.4 {
                name    "frw"
                reg 2
                shift   3
            }

            Object.Base.ops.1 {
                name    "ctl"
                info "volsw"
                #259 binds the mixer control to switch get/put handlers
                get "259"
                put "259"
            }

            #max 1 indicates switch type control
            max 1
        }
    }

    # Default attribute values for pga widget
    type            "pga"
    uuid            "7e:67:7e:b7:f4:5f:88:41:af:14:fb:a8:bd:bf:86:82"
    no_pm           "true"
    ramp_step_type      "linear"
    ramp_step_ms        400
}

對(duì)象

對(duì)象用于實(shí)例化同一個(gè)類的多個(gè)實(shí)例,以避免重復(fù)的公共屬性定義。對(duì)象使用新的關(guān)鍵字 Object 后跟三個(gè)節(jié)點(diǎn)來(lái)實(shí)例化:

Object.Widget.pga."1" {}

這些節(jié)點(diǎn)指代以下元素:

  • 對(duì)象的類所屬的類組。在這個(gè)例子中,類屬于 Widget 類組。
  • 類名稱。這里是 pga。
  • 唯一的屬性值。這是在類定義中,被限定為 unique 的屬性的值。這里是 instance。在 ALSA 拓?fù)?2.0 中,對(duì)象不必須有一個(gè)字符串形式地對(duì)象名稱,或者說(shuō),對(duì)象名稱本身由對(duì)象的特定一個(gè)或幾個(gè)屬性值組成,這與 C++ 或 Java 這種面向?qū)ο缶幊陶Z(yǔ)言種的對(duì)象定義不同。這個(gè)部分通常由構(gòu)造器 constructor 數(shù)組中各個(gè)屬性的值組成。對(duì)象實(shí)例化時(shí),Object 后只有 unique 的屬性。這要求任何類定義中,都需要有且僅有一個(gè) unique 的屬性。unique 的屬性是否要放進(jìn)類的構(gòu)造器數(shù)組中可選,既可以放進(jìn)去,也可以不放進(jìn)去。

使用 完整的類定義 一節(jié)中所述的 pga 類定義,可以通過(guò)以下方式實(shí)例化一個(gè) pga Widget 對(duì)象:

Object.Widget.pga."1" {
        index 5
}

其中 1 是 pga 類定義中唯一的屬性 instance 的值,index 屬性的值為 5。由于類定義中不包含其它的 mandatory 屬性,因此上面的實(shí)例完全有效。

重要
不需要在對(duì)象實(shí)例中復(fù)制公共屬性值。對(duì)象自動(dòng)從其類定義中繼承屬性的默認(rèn)值。

修改默認(rèn)屬性

類定義中具有默認(rèn)值的屬性,可以通過(guò)在對(duì)象實(shí)例中指定新值來(lái)覆蓋:

Object.Widget.pga."1" {
        index           5
        ramp_step_ms    300
}

上面的對(duì)象,將類定義中 ramp_step_ms 的默認(rèn)值 200 ms 覆蓋為新值 300 ms。

類中的對(duì)象

類定義中還可以選擇包含需要為類對(duì)象的每個(gè)實(shí)例實(shí)例化的子對(duì)象。例如,pga Widget 對(duì)象通常始終包含音量混音器 Control。混音器 Control 類定義如下:

Class.Control."mixer" {
        #
        # Pipeline ID for the mixer object
        #
        DefineAttribute."index" {}

        #
        # Instance of mixer object in the same alsaconf node
        #
        DefineAttribute."instance" {}

        #
        # Mixer name. A mixer object is included in the built topology only if it is given a
        # name
        #
        DefineAttribute."name" {
                type    "string"
        }

        #
        # Max volume setting
        #
        DefineAttribute."max" {}

        DefineAttribute."invert" {
                type    "string"
                constraints {
                        !valid_values [
                                "true"
                                "false"
                        ]
                }
        }

        # use mute LED
        DefineAttribute."mute_led_use" {
                token_ref       "sof_tkn_mute_led.word"
        }

        # LED direction
        DefineAttribute."mute_led_direction" {
                token_ref       "sof_tkn_mute_led.word"
        }

        #
        # access control for mixer
        #
        DefineAttribute."access" {
                type    "compound"
                constraints {
                        !valid_values [
                                "read_write"
                                "tlv_read_write"
                                "read"
                                "write"
                                "volatile"
                                "tlv_read"
                                "tlv_write"
                                "tlv_command"
                                "inactive"
                                "lock"
                                "owner"
                                "tlv_callback"
                        ]
                }
        }

        attributes {
                #
                # The Mixer object name is constructed using the index and instance arguments.
                # For ex: "mixer.1.1" or "mixer.10.2" etc.
                #
                !constructor [
                        "index"
                        "instance"
                ]
                !mandatory [
                        "max"
                ]
                #
                # mixer control objects instantiated within the same alsaconf node should have unique
                # index attribute
                #
                unique  "instance"
        }

        # Default attribute values for mixer control
        invert          "false"
        mute_led_use            0
        mute_led_direction      0
}

可以將混音器 Control 對(duì)象添加到 pga Widget 類定義中:

Class.Widget."pga" {
        # Attributes, qualifiers and default values are skipped for simplicity.
        # Refer to the complete class definition in "Complete Class Definition" for details

        # volume control for pga widget
        Object.Control.mixer."1" {
                        name "My Volume Control"
                        max 32
                }
        }
}

混音器 Control My Volume Control 將以編程方式添加到所有 pga 對(duì)象中。

對(duì)象屬性繼承

在上面的對(duì)象實(shí)例化中需要注意的一件事是,混音器對(duì)象有兩個(gè)強(qiáng)制性(構(gòu)造器)屬性,index 和 instance,但實(shí)例化中卻少 index 屬性值。這是因?yàn)榛煲羝?Control 對(duì)象在實(shí)例化時(shí),從其父 pga 對(duì)象繼承了 index 屬性值。例如,考慮如下的 pga 對(duì)象實(shí)例:

Object.Widget.pga.1 {
        index 5
}

pga 類定義中的混音器 Control 對(duì)象繼承索引值 5。僅當(dāng)子對(duì)象的類定義與其父類(子對(duì)象所屬的類,而不是類繼承)定義具有同名屬性時(shí),才會(huì)發(fā)生繼承。對(duì)于混音器 Control 類和 pga Widget 類,共同具有的屬性為 index

設(shè)置子對(duì)象的屬性

讓我們?cè)俅慰紤]具有混音器 Control 對(duì)象的 pga 類定義:

Class.Widget."pga" {
        # Attributes, qualifiers and default values are skipped for simplicity.
        # Please refer to the complete class definition above for details

        # volume control for pga widget
        Object.Control.mixer."1" {
                        name "My Volume Control"
                        max 32
                }
        }
}

請(qǐng)注意,在 pga Widget 類定義中,設(shè)置了混音器 Control 對(duì)象的名稱。但是,理想情況下,每當(dāng)實(shí)例化新的 pga Widget 對(duì)象時(shí),我們都希望為混音器 Control 子對(duì)象指定一個(gè)新名稱。可以這樣做:

Object.Widget.pga."1" {
        index 5

        # volume control'
        Object.Control.mixer."1" {
                        name "My Control Volume 5"
                }
        }
}

現(xiàn)在,混音器 Control 對(duì)象被賦予了名稱 My Control Volume 5。

嵌套對(duì)象

對(duì)象還可以實(shí)例化為其它對(duì)象實(shí)例中的子對(duì)象。例如,可以在實(shí)例化期間將開關(guān) Control 添加到 pga Widget 對(duì)象:

Object.Widget.pga."1" {
        index 5

        # volume control
        Object.Control.mixer."1" {
                        name "My Control Volume 5"
                }
        }

        # mute control
        Object.Control.mixer."2" {
                        name "Mute Switch Control"
                        max 1
                }
        }
}

請(qǐng)注意兩個(gè)混音器 Control 對(duì)象的 unique 屬性如何不同以保持混音器實(shí)例的唯一性。為對(duì)象實(shí)例添加嵌套對(duì)象與上面的設(shè)置子對(duì)象的屬性類似,兩者的區(qū)別在于,嵌套的對(duì)象是沒有出現(xiàn)在其父類定義中的。

遞歸對(duì)象屬性繼承

對(duì)象可以嵌套在對(duì)象內(nèi),而后者又嵌套在其它對(duì)象內(nèi)。在這種情況下,屬性值可以從頂層父對(duì)象一路繼承。例如,考慮以下的 volume-playback 流水線的類定義:

Class.Pipeline."volume-playback" {
        # Other attributes and qualifiers ommitted for simplicity
        DefineAttribute."index" {}

        DefineAttribute."format" {
                type    "string"
        }

        # pipeline objects
        Object.Widget {
                # Other objects ommitted for simplicity

                pga."1" {}
        }
}

請(qǐng)注意,上面的 pga Widget 對(duì)象沒有 index 屬性值。volume-playback 類對(duì)象像這樣實(shí)例化:

Object.Pipeline.volume-playback.1 {
        index 1
        format s24le
}

這確保 volume-playback 對(duì)象中的所有子對(duì)象都將從它繼承 index 屬性值,因此 pga Widget 對(duì)象將具有相同的 index 值。按照同樣的規(guī)則,pga Widget 對(duì)象中的混音器 Control 對(duì)象也將具有相同的 index 屬性值 1。

在父對(duì)象樹的深處設(shè)置子對(duì)象屬性

設(shè)置子對(duì)象的屬性 一節(jié)中,我們看到我們可以從父對(duì)象實(shí)例設(shè)置子對(duì)象的屬性值。例如,可以從 pga Widget 對(duì)象實(shí)例設(shè)置混音器 Control 對(duì)象的名稱。這可以進(jìn)一步擴(kuò)展,可以從 pga 對(duì)象的父對(duì)象設(shè)置混音器 Control 名稱??紤]上一節(jié)中的 volume-playback 對(duì)象實(shí)例。我們可以為 pga 對(duì)象設(shè)置其混音器 Control 名稱,如下所示:

Object.Pipeline.volume-playback.1 {
        index 1
        format s24le
        Object.Widget.pga.1 {
                Object.Control.mixer.1 {
                        name    "My Control Volume 1"
                }
        }
}

頂層配置文件中的參數(shù)

參數(shù)用于傳遞構(gòu)建時(shí)參數(shù),它們可用于從同一個(gè)配置文件構(gòu)建出多個(gè)二進(jìn)制文件??紤]以下具有兩個(gè)流水線的頂層拓?fù)渑渲梦募?/p>

# arguments
@args [ DYNAMIC_PIPELINE ]
@args.DYNAMIC_PIPELINE {
       type integer
       default 0
}

Object.Pipeline {
        volume-playback.1 {
                dynamic_pipeline $DYNAMIC_PIPELINE
                index 1
                Object.Widget.pipeline.1 {
                        stream_name 'dai.HDA.0.playback'
                }
                Object.Widget.host.playback {
                        stream_name 'Passthrough Playback 0'
                }
                Object.Widget.pga.1 {
                        Object.Control.mixer.1 {
                                name '1 My Playback Volume'
                        }
                }
                format s24le
        }
        volume-playback.3 {
                dynamic_pipeline $DYNAMIC_PIPELINE
                index 3
                Object.Widget.pipeline.1 {
                        stream_name 'dai.HDA.2.playback'
                }
                Object.Widget.host.playback {
                        stream_name 'Passthrough Playback 1'
                }
                Object.Widget.pga.1 {
                        Object.Control.mixer.1 {
                                name '3 My Playback Volume'
                        }
                }
                format s24le
        }
}

在這個(gè)例子中,volume-playback 對(duì)象中的 dynamic_pipeline 屬性值,從編譯拓?fù)涠M(jìn)制文件時(shí),提供的 -DDYNAMIC_PIPELINE=1-DDYNAMIC_PIPELINE=0 選項(xiàng)給 DYNAMIC_PIPELINE 參數(shù)的值中擴(kuò)展。

注意
alsatplg 編譯器僅解析機(jī)器拓?fù)湮募许攲庸?jié)點(diǎn)定義的參數(shù)。

包含

構(gòu)建頂層配置文件時(shí),它應(yīng)該包含正在實(shí)例化的所有對(duì)象的類定義,否則編譯器將報(bào)錯(cuò),指出缺少類定義。所有路徑均相對(duì)于環(huán)境變量 ALSA_CONFIG_DIR 指定的目錄。你可以像下面這樣為依賴指定包含路徑:

<searchdir:include>
<searchdir:include/controls>
<searchdir:include/components>

像下面這樣包含類定義:

<dai.conf>
<data.conf>
<pcm.conf>
<volume-playback.conf>

簡(jiǎn)單的機(jī)器拓?fù)?/h2>

一個(gè)機(jī)器拓?fù)渫ǔS梢韵虏糠纸M成:

  • 包含路徑,指向類定義的搜索目錄
  • Conf 文件 Includes,包含類定義
  • 參數(shù)
  • 流水線對(duì)象
  • BE DAI 鏈接對(duì)象
  • PCM 對(duì)象
  • 頂層流水線連接

讓我們考慮一個(gè)簡(jiǎn)單的機(jī)器拓?fù)渑渲?/strong>文件,它包含一個(gè) volume-playback 流水線,一個(gè) HDA 類型的 DAI 鏈接,一個(gè)播放 PCM,和頂層連接:

# Include paths
<searchdir:include>
<searchdir:include/common>
<searchdir:include/components>
<searchdir:include/controls>
<searchdir:include/dais>
<searchdir:include/pipelines>

# Include class definitions
<vendor-token.conf>
<tokens.conf>
<volume-playback.conf>
<dai.conf>
<data.conf>
<pcm.conf>
<pcm_caps.conf>
<fe_dai.conf>
<hda.conf>
<hw_config.conf>
<manifest.conf>
<route.conf>

# arguments
@args.DYNAMIC_PIPELINE {
       type integer
       default 0
}

# DAI definition
Object.Dai {
        HDA.0 {
                name 'Analog Playback and Capture'
                id 4
                default_hw_conf_id 4
                Object.Base.hw_config.HDA0 {}
                Object.Widget.dai.1 {
                        direction playback
                        index 1
                        type dai_in
                        stream_name 'Analog Playback and Capture'
                        period_sink_count 0
                        period_source_count 2
                        format s32le
                }
        }
}


# Pipeline Definition
Object.Pipeline {
        volume-playback.1 {
                dynamic_pipeline $DYNAMIC_PIPELINE
                index 1
                Object.Widget.pipeline.1 {
                        stream_name 'dai.HDA.0.playback'
                }
                Object.Widget.host.playback {
                        stream_name 'Passthrough Playback 0'
                }
                Object.Widget.pga.1 {
                        Object.Control.mixer.1 {
                                name '1 My Playback Volume'
                        }
                }
                format s24le
        }
}

# PCM Definitions
Object.PCM {
        pcm.0 {
                name 'HDA Analog'
                Object.Base.fe_dai.'HDA Analog' {}
                Object.PCM.pcm_caps.playback {
                        name 'Passthrough Playback 0'
                        formats 'S24_LE,S16_LE'
                }
                direction playback
                id 0
        }
}

# Top-level pipeline connection
# Buffer.1. -> dai.HDA.1.playback
Object.Base.route.1 {
        source 'buffer.1.1'
        sink 'dai.HDA.1.playback'
}

注意上面的配置文件,只包含 volume-playback 流水線中的緩沖區(qū) Widget buffer.1.1 和 dai Widget dai.HDA.1.playback 之間的頂層路由。volume-playback 流水線中的 widgets 之間的連接在類定義中定義。

讓我們深入了解一下 volume-playback 流水線的類定義,看看類定義中包含的路由對(duì)象。關(guān)于完整的類定義,請(qǐng)參閱 volume-playback。

Class.Pipeline."volume-playback" {
        # pipeline attributes skipped for simplicity

        attributes {
                # pipeline name is constructed as "volume-playback.1"
                !constructor [
                        "index"
                ]
                !mandatory [
                        "format"
                ]
                !immutable [
                        "direction"
                ]
                #
                # volume-playback objects instantiated within the same alsaconf node should have
                # unique instance attribute
                #
                unique  "instance"
        }

        # Widget objects that constitute the volume-playback pipeline
        Object.Widget {
                pipeline."1" {}

                host."playback" {
                        type            "aif_in"
                }

                buffer."1" {
                        periods 2
                        caps            "host"
                }

                pga."1" {
                        Object.Control.mixer.1 {
                                Object.Base.tlv."vtlv_m64s2" {
                                        Object.Base.scale."m64s2" {}
                                }
                        }
                }

                buffer."2" {
                        periods 2
                        caps            "dai"
                }
        }

        # Pipeline connections.
        # The index attribute values for the source/sink widgets will be populated
        # when the route objects are built
        Object.Base {
                route."1" {
                        source  "host..playback"
                        sink    "buffer..1"
                }

                route."2" {
                        source  "buffer..1"
                        sink    "pga..1"
                }

                route."3" {
                        source  "pga..1"
                        sink    "buffer..2"
                }
        }

        # Default attribute values
        direction       "playback"
        time_domain     "timer"
        period          1000
        channels        2
        rate            48000
        priority        0
        core            0
        frames          0
        mips            5000
}

流水線類定義相當(dāng)容易理解,除了路由對(duì)象實(shí)例外。我們?cè)龠M(jìn)一步分析一下。 路由類定義如下:

Class.Base."route" {
        # sink widget name
        DefineAttribute."sink" {
                type    "string"
        }

        # source widget name for route
        DefineAttribute."source" {
                type    "string"
        }

        # control name for the route
        DefineAttribute."control" {
                type    "string"
        }

        #
        # Pipeline ID of the pipeline the route object belongs to
        #
        DefineAttribute."index" {}

        # unique instance for route object in the same alsaconf node
        DefineAttribute."instance" {}

        attributes {
                !constructor [
                        "instance"
                ]
                !mandatory [
                        "source"
                        "sink"
                ]
                #
                # route objects instantiated within the same alsaconf node should have unique
                # index attribute
                #
                unique  "instance"
        }
}

請(qǐng)注意,一個(gè)路由對(duì)象應(yīng)具有 instance、source 和 sink 屬性。

讓我們?cè)俅慰紤] volume-playback 類中的路由對(duì)象:

Object.Base {
        route."1" {
                source  "host..playback"
                sink    "buffer..1"
        }

        route."2" {
                source  "buffer..1"
                sink    "pga..1"
        }

        route."3" {
                source  "pga..1"
                sink    "buffer..2"
        }
}

請(qǐng)注意,source 和 sink 屬性是為所有路由定義的。比如,第二個(gè)路由對(duì)象 Object.Base.route.2,其 sink 屬性值為 pga..1。參閱 一個(gè)簡(jiǎn)單的類定義 中的 pga Widget 類定義,我們知道 pga Widget 對(duì)象的構(gòu)造器具有兩個(gè)屬性,indexinstance。通過(guò)查看 widgets 列表,我們知道 volume-playback 類中的 pga Widget 實(shí)例為 1。但流水線中的 pga Widget 的 index 屬性值未知。它只能從頂級(jí)拓?fù)渑渲梦募性O(shè)置,如 簡(jiǎn)單機(jī)器拓?fù)?/a> 中所示。因此,在類定義中,index 屬性留空。當(dāng)構(gòu)建路由對(duì)象時(shí),alsatplg 編譯器將使用適當(dāng)?shù)闹堤畛?index 屬性。對(duì)于上面的機(jī)器拓?fù)洌瑢⑹褂谜_的流水線 ID 構(gòu)建路由對(duì)象 Object.base.route.2,如下所示:

Object.base.route.2 {
        source  "buffer.1.1"
        sink "pga.1.1"
}

目前,alsatplg 只能為路由對(duì)象 source 和 sink 屬性填寫屬性值。如果需要,可以將此功能擴(kuò)展到其它類型的對(duì)象。

路由中設(shè)置 source 和 sink 屬性,指定 Widget 的方法是,類名后跟對(duì)象名,對(duì)象名的構(gòu)成為,以點(diǎn)號(hào)分割的對(duì)象所屬類定義中構(gòu)造器 constructor 數(shù)組中各屬性的值,如 host 類定義 (sof/tools/topology/topology2/include/components/host.conf):

Class.Widget."host" {
    #
    # Attributes for host widget
    #

    #
    # Pipeline ID that the host widget belongs to
    #
    DefineAttribute."index" {}

    #
    # Host direction
    #
    DefineAttribute."direction" {
        type    "string"
        constraints {
            !valid_values [
                "playback"
                "capture"
            ]

        }
    }
 . . . . . .
    attributes {
        #
        # host objects instantiated within the same alsaconf node must have unique value for
        # direction attribute
        #
        unique  "direction"

        #
        # The host object name is constructed using the index and direction arguments.
        # E.g. "host.0.capture" or "host.2.playback" etc
        #
        !constructor [
            "index"
            "direction"
        ]

路由中指定的 host 屬性為 host.$index.playback

機(jī)器拓?fù)渑渲弥校鱾€(gè)組成部分各具有什么樣的含義?它們之間有什么關(guān)系,是如何關(guān)聯(lián)起來(lái)的?

條件包含

條件包含允許從同一輸入配置文件構(gòu)建多個(gè)拓?fù)涠M(jìn)制文件。例如,讓我們考慮 HDA 通用機(jī)器拓?fù)?。DMIC 的數(shù)量決定是否應(yīng)包含 DMIC 配置文件。這可以通過(guò)以下方式實(shí)現(xiàn):

@args.DMIC_COUNT {
       type integer
       default 0
}

# include DMIC config if needed
IncludeByKey.DMIC_INCLUDE {
        "[1-4]" "include/platform/intel/dmic-generic.conf"
}

正則表達(dá)式 [1-4] 指示,如果 DMIC_COUNT 參數(shù)值在 1 到 4 之間,則應(yīng)包含 dmic-generic.conf 文件。假設(shè)頂層文件名為 sof-hda-generic.conf,你可以使用以下命令構(gòu)建兩個(gè)單獨(dú)的拓?fù)涠M(jìn)制文件:

  • 對(duì)于沒有 DMIC 的機(jī)器:
alsatplg -p -c sof-hda-generic.conf -o sof-hda-generic.tplg
  • 對(duì)于具有兩個(gè) DMIC 的機(jī)器:
alsatplg -D DMIC_COUNT=2 -p -c sof-hda-generic.conf -o sof-hda-generic-2ch.tplg

條件包含不僅限于頂層配置文件。你可以將它們添加到配置文件中的任何節(jié)點(diǎn),以在指定節(jié)點(diǎn)處包含配置。例如,我們可以為 EQIIR widget 的 byte controls 條件包含正確的過(guò)濾器系數(shù)。

在頂層拓?fù)湮募袨橄禂?shù)定義參數(shù):

@args.EQIIR_BYTES {
       type string
       default "highpass_40hz_0db_48khz"
}

然后包含系數(shù):

Object.Widget.eqiir.1 {
        Object.Control.bytes.1 {
                name "my eqiir byte control"
                # EQIIR filter coefficients
                IncludeByKey.EQIIR_BYTES {
                        "[highpass.40hz.0db.48khz]" "include/components/eqiir/highpass_40hz_0db_48khz.conf"
                        "[highpass.40hz.20db.48khz]" "include/components/eqiir/highpass_40hz_20db_48khz.conf"
                }
        }
}

構(gòu)建 2.0 配置文件

你可以使用 alsatplg 編譯拓?fù)?2.0 配置文件并生成拓?fù)涠M(jìn)制文件:

alsatplg <-D args=values> -p -c input.conf -o output.tplg

-D 開關(guān)用于給頂層配置文件傳遞逗號(hào)分隔的參數(shù)值。

你可以使用 -P 開關(guān)將 2.0 配置文件轉(zhuǎn)為 1.0 配置文件:

alsatplg <-D args=values> -P input.conf -o output.conf

拓?fù)涮嵝?/h2>

查看以下拓?fù)渥⒁馐马?xiàng):

  • “index” 指流水線,widget 和 control 類組中的流水線 ID。
  • DAI 類組對(duì)象中的 “id” 指的是內(nèi)核中機(jī)器驅(qū)動(dòng)程序中定義的鏈接 ID。

Alsaconf 提醒

查看以下 alsaconf 注意事項(xiàng):

  • “.” 指節(jié)點(diǎn)分割符?!癴oo.bar value” 相當(dāng)于以下內(nèi)容:
foo {
        bar value
}
  • 數(shù)組用 [] 定義。例如:
!constructor [
        "foo"
        "bar"
]

我們建議在類定義中的數(shù)組定義中使用感嘆號(hào) (!)。如果從不同源多次包含類配置文件,則使用它可以確保數(shù)組項(xiàng)不重復(fù)。

原文

Done.

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

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

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