筛选器、引脚和节点属性
Microsoft Windows 驱动程序模型 (WDM) 音频驱动程序将音频设备表示为 KS 筛选器,它们将设备上的硬件缓冲区表示为筛选器上的引脚。 当客户端向其中一个筛选器或引脚对象发送属性请求时,端口驱动程序会收到请求,并将请求路由到端口驱动程序或微型端口驱动程序中的相应属性处理程序。
音频设备支持三种类型的属性:
筛选器属性
筛选器属性是整个筛选器的属性,而不是筛选器中特定引脚或节点的属性。 筛选器属性的请求指定筛选器句柄,但它们不指定节点 ID。
引脚属性
引脚属性是筛选器上特定引脚实例的属性。 这些属性的请求指定引脚句柄,但它们不指定节点 ID。
节点属性
节点属性是筛选器中拓扑节点的属性。 节点属性的请求指定筛选器句柄或引脚句柄以及节点 ID。
节点属性请求是指定筛选器还是引脚句柄取决于节点是否对筛选器唯一。 有关更多信息,请参见下面的“节点属性”部分。
下图显示了这三种类型的属性请求:发送到引脚实例的引脚属性请求、发送到节点的节点属性请求(在筛选器或引脚实例上),以及发送到筛选器实例的筛选器属性请求。
通常,端口驱动程序处理筛选器和引脚属性的大多数请求,微型端口驱动程序处理节点属性的请求。
端口驱动程序为 SysAudio 系统驱动程序使用的筛选器和引脚属性提供自己的内置处理程序(请参阅 KSPROPSETID_Sysaudio 和 KSPROPSETID_Sysaudio_Pin)和 WDMAud 系统驱动程序。 微型端口驱动程序不需要为端口驱动程序处理的属性实现处理程序。 典型的微型端口驱动程序为筛选器和引脚属性提供了很少(如果有)的处理程序。 微型端口驱动程序为表示音频设备硬件相关功能的节点属性提供处理程序。 端口驱动程序不提供节点属性的内置处理,但 KSPROPERTY_TOPOLOGY_NAME 除外。
当端口驱动程序和微型端口驱动程序都为同一属性提供处理程序时,端口驱动程序使用自己的处理程序并忽略微型端口驱动程序的处理程序。
筛选器描述符
端口驱动程序通过调用 IMiniport::GetDescription 方法来获取指向微型端口驱动程序的属性处理程序的指针。 通过此方法,端口驱动程序会检索指向微型端口驱动程序筛选器描述符的指针,该描述符是 PCFILTER_DESCRIPTOR 类型的结构。 此结构为筛选器、引脚和节点属性指定微型端口驱动程序的属性处理程序:
PCFILTER_DESCRIPTOR 结构的 AutomationTable 成员指向筛选器的自动化表。 此表为筛选器属性指定微型端口驱动程序的属性处理程序。
PCFILTER_DESCRIPTOR 结构的 Pins 成员包含引脚的自动化表。 每个表指定特定引脚类型的引脚属性的属性处理程序。
PCFILTER_DESCRIPTOR 结构的 Nodes 成员包含筛选器中拓扑节点的自动化表。 每个表指定特定节点类型的节点属性的属性处理程序。
筛选器属性
端口驱动程序通过 PCFILTER_DESCRIPTOR 的 AutomationTable 成员访问微型端口驱动程序的筛选器属性处理程序。 通常,此自动化表包含少量处理程序,因为端口驱动程序为 SysAudio 和 WDMAud 用于查询和配置音频设备的所有筛选器属性提供自己的内置处理程序。
但是,微型端口驱动程序可以提供 KSPROPERTY_GENERAL_COMPONENTID 等筛选器属性的处理程序,从而提供与硬件相关的信息,而该信息不适用于端口驱动程序。 Microsoft Windows 驱动程序工具包 (WDK) 中的两个示例音频驱动程序处理 KSPROPERTY_GENERAL_COMPONENTID 属性。 有关详细信息,请参阅 Sysvad 示例驱动程序中的微型端口驱动程序实现,这在示例音频驱动程序中进行了讨论。
Portcls.sys 中的所有端口驱动程序都提供 KSPROPSETID_Pin 和 KSPROPSETID_Topology 属性集的处理。 这些集中的所有属性都是筛选器属性,但 KSPROPERTY_TOPOLOGY_NAME 节点属性(该属性使用筛选器句柄而非引脚句柄来指定请求的目标)除外。 端口驱动程序支持 KSPROPSETID_Pin 属性的以下子集:
KSPROPERTY_PIN_CONSTRAINEDDATARANGES
KSPROPERTY_PIN_DATAINTERSECTION
KSPROPERTY_PIN_GLOBALCINSTANCES
KSPROPERTY_PIN_NECESSARYINSTANCES
KSPROPERTY_PIN_PHYSICALCONNECTION
KSPROPERTY_PIN_PROPOSEDATAFORMAT
KSPROPERTY_PIN_PROPOSEDATAFORMAT2
这些属性提供有关属于筛选器的引脚工厂的信息。 通常,客户端会在创建引脚实例之前在筛选器中查询这些属性。 端口驱动程序支持所有四个 KSPROPSETID_Topology 属性,这些属性提供有关筛选器的内部拓扑的信息。
此外,DMus 端口驱动程序为 KSPROPERTY_SYNTH_MASTERCLOCK 属性提供处理程序,该属性是 DirectMusic 筛选器的 get-only 属性。 KSPROPERTY_SYNTH_MASTERCLOCK 是 KSPROPSETID_SynthClock 属性集的成员。
引脚属性
端口驱动程序通过 PCFILTER_DESCRIPTOR 的 Pins 成员访问微型端口驱动程序的引脚属性处理程序。 此成员指向引脚描述符数组,每个描述符指向引脚类型的自动化表(由引脚 ID 标识,这只是数组索引)。
通常,这些自动化表包含少量条目,因为端口驱动程序为 SysAudio 和 WDMAud 使用的所有引脚属性提供自己的处理程序。 微型端口驱动程序可以选择为端口驱动程序不处理的一个或多个引脚属性提供处理程序,但只有知道这些属性的客户端可以为其发送属性请求。
除了拓扑端口驱动程序之外,Portcls.sys 中的所有端口驱动程序都提供以下引脚属性的内置处理程序:
KSPROPERTY_CONNECTION_DATAFORMAT
KSPROPERTY_CONNECTION_ALLOCATORFRAMING
KSPROPERTY_DRMAUDIOSTREAM_CONTENTID
此列表中的某些属性需要微型端口驱动程序中的硬件相关信息。 当端口驱动程序收到包含其中一个属性的请求的 IRP 时,它不会将 IRP 传递给微型端口驱动程序。 相反,端口驱动程序会处理请求本身,但其处理程序通过调用微型端口驱动程序中的入口点来获取所需的信息。 例如,端口驱动程序为 KSPROPERTY_AUDIO_POSITION 请求提供自己的属性处理程序。 此处理程序只需调用微型端口驱动程序流的 GetPosition 方法(例如 IMiniportWavePciStream::GetPosition)即可获取当前位置。
节点属性
端口驱动程序通过 PCFILTER_DESCRIPTOR 的 Nodes 成员访问微型端口驱动程序的节点属性处理程序。 此成员指向节点描述符数组,每个描述符指向节点类型的自动化表(由节点 ID 标识,这只是数组索引)。 通常,属于微型端口驱动程序的所有或大多数属性处理程序都驻留在 Nodes 数组中。 音频驱动程序将音频设备中的硬件控件表示为拓扑节点,并使用属性机制向客户端提供对硬件相关控制设置的访问权限。
如前所述,客户端会将筛选器属性请求发送到筛选器句柄,并将引脚属性请求发送到引脚句柄。 与筛选器或引脚实例不同,节点不是内核对象,没有句柄。 客户端将节点属性请求发送到引脚句柄或筛选器句柄,但该请求还指定节点 ID 以指示请求适用于节点属性,而非引脚或筛选器属性。
以下是用于确定节点属性应使用筛选器句柄还是引脚句柄的一般规则:
如果筛选器包含特定引脚类型的多个实例,并且该类型的每个引脚包含具有特定节点 ID 的节点,则每个引脚实例都包含该节点的实例。 在这种情况下,节点属性请求必须指定引脚句柄(而不仅仅是筛选器句柄),以区分同一节点类型的多个实例。 引脚句柄和节点 ID 的组合明确将特定节点实例标识为请求的目标。
如果筛选器仅包含特定节点的一个实例,则节点属性请求指定筛选器句柄。 筛选器句柄和节点 ID 的组合足以明确标识作为请求目标的节点。
但是,在实现特定节点属性的处理程序之前,驱动程序编写器应引用音频驱动程序属性集来检查属性的目标应指定为筛选器句柄还是引脚句柄。
目前,Portcls.sys 中的端口驱动程序不提供节点属性的内置处理,但 KSPROPERTY_TOPOLOGY_NAME 除外。
过度指定和未指定的属性请求
驱动程序应准备好处理不遵循上述规则的客户端的属性请求。 请求可能过度指定或未明确指定:
过度指定的请求
如果属性请求只需要筛选器句柄,但客户端改为将请求发送到引脚句柄,则会过度指定请求的目标。 但是,驱动程序通常将请求视为有效;也就是说,它们将请求视为已发送到包含引脚的筛选器。
未明确指定的请求
如果属性请求需要引脚句柄,但客户端改为将请求发送到筛选器句柄,则会未明确指定请求的目标。 例如,如果筛选器包含多个具有同一节点类型的引脚实例,并且客户端向筛选器句柄而非引脚句柄发送该节点类型的属性请求,驱动程序无法确定应接收请求的节点实例。 在这种情况下,具体行为取决于驱动程序。 某些驱动程序将未目前指定的 set-property 请求视为有效,而不是使所有未明确指定的请求自动失败。 在这种情况下,解释是请求设置指定节点 ID 的默认值。 当引脚工厂创建新的节点实例时,属于新节点的属性将初始化为默认值。 更改默认值的请求对在该请求之前创建的节点实例没有影响。 此外,驱动程序会使未明确指定的 get-property 请求统一失败,因为处理程序无法确定要查询该属性的节点实例。
规则的例外情况
出于历史原因,一些音频属性具有违反这些一般规则的行为规定。 以下是一些示例:
如应用扬声器配置设置中所述,客户端可以通过设置三维节点 (KSNODETYPE_3D_EFFECTS) 的 KSPROPERTY_AUDIO_CHANNEL_CONFIG 属性来更改音频设备的扬声器配置。 扬声器配置设置是全局的,因为它更改了设备通过扬声器播放的混音中的所有流的扬声器配置。 根据一般规则,影响整个筛选器的节点属性请求应指定筛选器句柄(加上节点 ID)。 但是,此特定属性需要引脚句柄而非筛选器句柄。 引脚句柄指定包含 3D 节点的引脚实例,该节点是请求的目标。
KSPROPERTY_SYNTH_VOLUME 和 KSPROPERTY_SYNTH_MASTERCLOCK 是合成器节点 (KSNODETYPE_SYNTHESIZER) 的属性。 尽管两者都是节点属性,但这些属性的请求不包含节点 ID。 (请注意,请求的属性描述符是一种类型结构 KSPROPERTY,而非 KSNODEPROPERTY。)此行为违反了节点属性要求节点 ID 遵守的一般规则。 尽管存在这种差异,但支持任一属性的微型端口驱动程序应通过 PCFILTER_DESCRIPTOR 的 Nodes 成员(而非 Pins 成员)提供属性处理程序。