实现音频处理对象

本主题介绍如何实现音频处理对象 (APO)。 有关 APO 的一般信息,请参阅音频处理对象体系结构

实现自定义 APO

自定义 API 作为进程内 COM 对象实现,因此它们以用户模式运行,并打包在动态链接库 (DLL) 中。 根据在信号处理图中插入 APO 的位置,有三种类型的 APO。

  • 流效果 (SFX)
  • 模式效果 (MFX)
  • 终结点效果 (EFX)

每个逻辑设备都可以与每种类型的一个 APO 相关联。 有关模式和效果的详细信息,请参阅音频信号处理模式

可以通过基于 CBaseAudioProcessingObject 基类(在 Baseaudioprocessingobject.h 文件中声明)构建自定义类来实现 APO。 此方法涉及将新功能添加到 CBaseAudioProcessingObject 基类以创建自定义 APO。 CBaseAudioProcessingObject 基类会实现 APO 所需的大部分功能。 它为三个必需接口中的大多数方法提供默认实现。 主要例外是 IAudioProcessingObjectRT::APOProcess 方法。

执行以下步骤以实现自定义 APO。

  1. 创建自定义 APO com 对象以提供所需的音频处理。
  2. (可选)创建用户界面以使用 a 配置自定义 APO。
  3. 创建 INF 文件以安装和注册 APO 以及自定义用户界面。

自定义 APO 开发的设计注意事项

所有自定义 APO 必须具有以下一般特征:

  • APO 必须具有一个输入和一个输出连接。 这些连接是音频缓冲区,可以有多个声道。

  • APO 只能通过其 IAudioProcessingObjectRT::APOProcess 例程修改传递给它的音频数据。 APO 无法更改基础逻辑设备的设置,包括其 KS 拓扑。

  • 除了 IUnknown 之外,APOS 还必须公开以下接口:

  • 所有 ADO 都必须具有实时系统兼容性。 这表示:

    • 作为实时接口成员的所有方法都必须作为非阻止成员实现。 它们不得阻止、使用分页内存或调用任何阻塞系统例程。

    • APO 处理的所有缓冲区都必须不可分页。 进程路径中的所有代码和数据都必须不可分页。

    • ADO 不应在音频处理链中引入大量延迟。

  • 自定义 API 不得公开 IAudioProcessingObjectVBR 接口。

注意

有关所需接口的详细信息,请参阅 Windows Kits\<build number>\Include\um 文件夹中的 Audioenginebaseapo.h 和 Audioenginebaseapo.idl 文件。

使用示例代码加速开发过程

将 SYSVAD 交换 APO 代码示例用作模板可以加速自定义 APO 开发过程。 交换示例是为了说明音频处理对象的一些功能而开发的示例。 交换 APO 示例使用右声道交换左声道,并实现 SFX 和 MFX 效果。 可以使用属性对话框启用或禁用声道交换音频效果。

Windows 驱动程序示例 GitHub 上提供 SYSVAD 音频示例。

可以在此处浏览 Sysvad 音频示例:

https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad

从 GitHub 下载并提取 Sysvad 音频示例

按照以下步骤下载并打开 SYSVAD 示例。

a. 可以使用 GitHub 工具处理示例。 还可以使用一个 zip 文件下载通用驱动程序示例。

https://github.com/Microsoft/Windows-driver-samples/archive/master.zip

b. 将 master.zip 文件下载到本地硬盘。

c. 选择并按住(或右键单击)Windows-driver-samples-master.zip,然后选择“全部提取”。 指定一个新文件夹,或浏览到将存储提取文件的现有文件夹。 例如,可以指定 C:\DriverSamples\ 作为将文件提取到的新文件夹。

d. 提取文件后,导航到以下子文件夹:C:\DriverSamples\Audio\Sysvad

在 Visual Studio 中打开驱动程序解决方案

在 Microsoft Visual Studio 中,选择文件>打开>项目/解决方案...,并导航到包含提取文件的文件夹(例如,C:\DriverSamples\Audio\Sysvad)。 双击 Sysvad 解决方案文件将其打开。

在 Visual Studio 中,找到“解决方案资源管理器”。 (如果尚未打开,请从视图菜单中选择解决方案资源管理器。)在解决方案资源器中,可以看到一个包含六个项目的解决方案。

SwapAPO 示例代码

SYSVAD 示例中有五个项目,APO 开发人员主要对其中一个项目感兴趣。

项目 描述
SwapAPO 示例 APO 的示例代码

下面汇总了 Sysvad 示例中的其他项目。

项目 描述
TabletAudioSample 备用音频驱动程序的示例代码。
KeywordDetectorAdapter 关键字检测器适配器的示例代码
EndpointsCommon 常见终结点的示例代码。

SwapAPO 示例的主要头文件是 swapapo.h。 下面汇总了其他主要代码元素。

文件 描述
Swap.cpp 包含交换 APO 实现的 C++ 代码。
SwapAPOMFX.cpp CSwapAPOMFX 的实现
SwapAPOSFX.cpp CSwapAPOSFX 的实现
SwapAPODll.cpp DLL 导出的实现。
SwapAPODll.idl DLL 的 COM 接口和组件类的定义。
SwapAPOInterface.idl 交换 APO 功能的接口和类型定义。
swapapodll.def COM 导出定义

实现 COM 对象音频处理代码

可以通过基于 CBaseAudioProcessingObject 基类(在 Baseaudioprocessingobject.h 文件中声明)构建自定义类来包装系统提供的 APO。 此方法涉及将新功能引入 CBaseAudioProcessingObject 基类以创建自定义 APO。 CBaseAudioProcessingObject 基类会实现 APO 所需的大部分功能。 它为三个必需接口中的大多数方法提供默认实现。 主要例外是 IAudioProcessingObjectRT::APOProcess 方法。

通过使用 CBaseAudioProcessingObject,可以更轻松地实现 APO。 如果 APO 没有特殊格式要求,并且对所需的 float32 格式进行操作,则 CBaseAudioProcessingObject 中包含的接口方法的默认实现应足够。 鉴于默认实现,只需实现三个主要方法:IAudioProcessingObject::IsInputFormatSupportedIAudioProcessingObjectRT::APOProcessValidateAndCacheConnectionInfo

若要基于 CBaseAudioProcessingObject 类开发 APO,请执行以下步骤:

  1. 创建继承自 CBaseAudioProcessingObject 的类。

    以下 C++ 代码示例演示了如何创建继承自 CBaseAudioProcessingObject 的类。 有关此概念的实际实现,请按照音频处理对象驱动程序示例部分中的说明转到交换示例,然后参考 Swapapo.h 文件。

    // Custom APO class - SFX
    Class MyCustomAPOSFX: public CBaseAudioProcessingObject
    {
     public:
    //Code for custom class goes here
    ...
    };
    

    请注意,由于 SFX APO 执行的信号处理不同于 MFX 或 EFX APO 执行的信号处理,因此必须为每个创建单独的类。

  2. 实现以下三个方法:

以下 C++ 代码示例演示了在步骤 1 中创建的示例类的 APOProcess 方法的实现。 有关此概念的实际实现,请按照音频处理对象驱动程序示例部分中的说明转到交换示例,然后参考 Swapapolfx.cpp 文件。

// Custom implementation of APOProcess method
STDMETHODIMP_ (Void) MyCustomAPOSFX::APOProcess (...)
{
// Code for method goes here. This code is the algorithm that actually
// processes the digital audio signal.
...
}

以下代码示例演示了 ValidateAndCacheConnectionInfo 方法的实现。 有关此方法的实际实现,请按照音频处理对象驱动程序示例部分中的说明转到交换示例,然后参考 Swapapogfx.cpp 文件。

// Custom implementation of the ValidateAndCacheConnectionInfo method.
HRESULT CSwapAPOGFX::ValidateAndCacheConnectionInfo( ... )
{
// Code for method goes here.
// The code should validate the input/output format pair.
...
}

请注意,类从 CBaseAudioProcessingObject 继承的其余接口和方法在 Audioenginebaseapo.idl 文件中进行了详细说明。

替换系统提供的 APO

实现 APO 接口时有两种方法:可以编写自己的实现,也可以调用收件箱 APO。

此伪代码演示如何包装系统 APO。

CMyWrapperAPO::CMyWrapperAPO {
    CoCreateInstance(CLSID_InboxAPO, m_inbox);
}

CMyWrapperAPO::IsInputFormatSupported {
    Return m_inbox->IsInputFormatSupported(…);
}

此伪代码演示如何创建自己的自定义 APO。

CMyFromScratchAPO::IsInputFormatSupported {
    my custom logic
}

开发 APO 以替换系统提供的 APO 时,必须对接口和方法使用以下列表中的相同名称。 除了列出的必需方法之外,某些接口还有更多方法。 请参阅这些接口的参考页,以确定是要实现所有方法还是仅实现所需的方法。

其余实现步骤与自定义 APO 相同。

为 COM 组件实现以下接口和方法:

使用 Visual Studio 和 APO

在 Visual Studio 中使用 APO 时,请为每个 APO 项目执行这些任务。

面向 Windows 10 的驱动程序应针对通用 CRT 动态链接。

如果需要支持 Windows 8.1,请通过在 C/C++、Code Generation 中设置项目属性来启用静态链接。 为发行版本将“运行时库”设置为 /MT,或为调试版本将其设置为 /MTd。 进行此更改是因为对于驱动程序,很难重新分发 MSVCRT<n>.dll 二进制文件。 解决方案是静态链接 libcmt.dll。 有关详细信息,请参阅 /MD、/MT、/LD(使用运行时库)

禁用嵌入清单

通过设置 APO 项目的项目属性来禁用嵌入清单。 选择“清单工具”、“输入和输出”然后,将“嵌入清单”从默认值“是”更改为“否”。 如果你有嵌入清单,这会触发在受保护环境中禁止使用某些 API。 这意味着 APO 将使用 DisableProtectedAudioDG=1 运行,但在移除此测试键后,即使 APO 已进行 WHQL 签名,也将无法加载。

使用驱动程序打包 APO

开发自己的音频驱动程序并包装或替换系统提供的 APO 时,必须提供驱动程序包来安装驱动程序和 APO。 对于 Windows 10,请参阅适用于音频的通用 Windows 驱动程序。 音频相关驱动程序包应遵循其中详述的策略和打包模型。

自定义 APO 打包为 DLL,任何配置 UI 都打包为单独的 UWP 或桌面桥应用。 APO 设备 INF 会将 DLL 复制到关联的 INF CopyFile 指令中指示的系统文件夹。 包含 APO 的 DLL 必须通过包括 INF 文件中的 AddReg 节来注册自身。

以下段落和 INF 文件片段显示了使用标准 INF 文件复制和注册 APO 所必需的修改。

Sysvad 示例随附的 inf 文件说明了如何注册 SwapApo.dll APO。

在 INF 文件中注册用于处理模式和效果的 APO

可以使用某些允许的注册表项组合为特定模式注册 APO。 有关哪些效果可用的详细信息以及有关 APO 的一般信息,请参阅音频处理对象体系结构

有关每个 APO INF 文件设置的信息,请参阅这些参考主题。

PKEY_FX_StreamEffectClsid

PKEY_FX_ModeEffectClsid

PKEY_FX_EndpointEffectClsid

PKEY_SFX_ProcessingModes_Supported_For_Streaming

PKEY_MFX_ProcessingModes_Supported_For_Streaming

PKEY_EFX_ProcessingModes_Supported_For_Streaming

以下 INF 文件示例演示如何为特定模式注册音频处理对象 (APO)。 它们说明了此列表中可用的可能组合。

  • 带 PKEY_SFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_StreamEffectClsid
  • 带 PKEY_MFX_ProcessingModes_Suppoted_For_Streaming 的 PKEY_FX_ModeEffectClsid
  • 不带 PKEY_MFX_ProcessingModes_Suppoted_For_Streaming 的 PKEY_FX_ModeEffectClsid
  • 不带 PKEY_EFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_EndpointEffectClsid

这些示例中未显示另外一个有效组合。

  • 带 PKEY_EFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_EndpointEffectClsid

SYSVAD 平板电脑多模式流式处理效果 APO INF 示例

此示例演示了使用 SYSVAD 平板电脑 INF 文件中的 AddReg 条目注册的多模式流式处理效果。

此示例代码取自 SYSVAD 音频示例,可在 GitHub 上获取:https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad

此示例演示了系统效果的这种组合:

  • 带 PKEY_SFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_StreamEffectClsid
  • 带 PKEY_MFX_ProcessingModes_Suppoted_For_Streaming 的 PKEY_FX_ModeEffectClsid
[SWAPAPO.I.Association0.AddReg]
; Instruct audio endpoint builder to set CLSID for property page provider into the
; endpoint property store
HKR,EP\0,%PKEY_AudioEndpoint_ControlPanelPageProvider%,,%AUDIOENDPOINT_EXT_UI_CLSID%

; Instruct audio endpoint builder to set the CLSIDs for stream, mode, and endpoint APOs
; into the effects property store
HKR,FX\0,%PKEY_FX_StreamEffectClsid%,,%FX_STREAM_CLSID%
HKR,FX\0,%PKEY_FX_ModeEffectClsid%,,%FX_MODE_CLSID%
HKR,FX\0,%PKEY_FX_UserInterfaceClsid%,,%FX_UI_CLSID%

; Driver developer would replace the list of supported processing modes here
; Concatenate GUIDs for DEFAULT, MEDIA, MOVIE
HKR,FX\0,%PKEY_SFX_ProcessingModes_Supported_For_Streaming%,%REG_MULTI_SZ%,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%,%AUDIO_SIGNALPROCESSINGMODE_MEDIA%,%AUDIO_SIGNALPROCESSINGMODE_MOVIE%

; Concatenate GUIDs for DEFAULT, MEDIA, MOVIE
HKR,FX\0,%PKEY_MFX_ProcessingModes_Supported_For_Streaming%,%REG_MULTI_SZ%,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%,%AUDIO_SIGNALPROCESSINGMODE_MEDIA%,%AUDIO_SIGNALPROCESSINGMODE_MOVIE%

;HKR,FX\0,%PKEY_EFX_ProcessingModes_Supported_For_Streaming%,0x00010000,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%

请注意,在示例 INF 文件中,EFX_Streaming 属性被注释掉,因为音频处理已转换为该层上方的内核模式,因此不需要且不会使用流式处理属性。 为发现目的指定 PKEY_FX_EndpointEffectClsid 是有效的,但指定 PKEY_EFX_ProcessingModes_Supported_For_Streaming 将是一个错误。 这是因为模式 mix/ tee 在堆栈中的位置较低,因此无法插入终结点 APO。

组件化 APO 安装

从 Windows 10 版本 1809 开始,使用音频引擎进行的 APO 注册使用组件化音频驱动程序模型。 使用音频组件化可打造更流畅、更可靠的安装体验,并更好地支持组件服务。 有关详细信息,请参阅创建组件化音频驱动程序安装

以下示例代码是从公共 ComponentizedAudioSampleExtension.inf 和 ComponentizedApoSample.inf 中提取的。 请参阅 GitHub 上提供的 SYSVAD 音频示例:https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad

将 APO 注册到音频引擎是使用新创建的 APO 设备完成的。 要使音频引擎能够使用新的 APO 设备,它必须是音频设备的 PNP 子级,音频终结点的同级。 新的分组件化 APO 设计不允许全局注册 APO 并使其供多个不同驱动程序使用。 每个驱动程序必须注册自己的 APO。

APO 的安装分两个部分完成。 首先,驱动程序扩展 INF 会将 APO 组件添加到系统:

[DeviceExtension_Install.Components]
AddComponent = SwapApo,,Apo_AddComponent

[Apo_AddComponent]
ComponentIDs = VEN_SMPL&CID_APO
Description = "Audio Proxy APO Sample"

此 APO 组件会在 SYSVAD 示例中触发第二部分,即 APO INF 安装,这是在 ComponentizedApoSample.inf 中完成的。 此 INF 文件专用于 APO 组件。 它将组件类指定为 AudioProcessingObject,并添加 CLSID 注册的所有 APO 属性,并在音频引擎中注册。

注意

INF 文件示例显示了使用 HKR 注册表项支持驱动程序包隔离。 在 Windows 11 版本 22000 之前,这些示例使用 HKCR 存储 CLSID 注册的永久值,而不是 HKR。 从 Windows 10 版本 1809 开始,就已支持使用 HKR 注册 APO。 有关详细信息,请参阅使用通用 INF 文件

[Version]
...
Class       = AudioProcessingObject
ClassGuid   = {5989fce8-9cd0-467d-8a6a-5419e31529d4}
...

[ApoComponents.NT$ARCH$]
%Apo.ComponentDesc% = ApoComponent_Install,APO\VEN_SMPL&CID_APO

[Apo_AddReg]
; CLSID registration
HKR,Classes\CLSID\%SWAP_FX_STREAM_CLSID%,,,%SFX_FriendlyName%
HKR,Classes\CLSID\%SWAP_FX_STREAM_CLSID%\InProcServer32,,0x00020000,%%SystemRoot%%\System32\swapapo.dll
HKR,Classes\CLSID\%SWAP_FX_STREAM_CLSID%\InProcServer32,ThreadingModel,,"Both"
...
;Audio engine registration
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"FriendlyName",,%SFX_FriendlyName%
...

当此 INF 安装组件化 APO 时,将在 Windows 设备管理器中显示桌面系统上的“音频处理对象”。

发布新的 APO 版本时,更新 CLSID

发布新的 APO 版本后,最好而且通常建议更新 COM 类 CLSID。 使用 GUIDGEN 等工具创建新的 GUID。

从 HKCR 迁移到 HKR 时更新 CLSID 的要求

这是从全局 COM 注册 (HKCR) 切换到设备相对 HKR COM 注册以更改 COM 类 GUID 时的要求。 此方法可减少新 COM 对象未正确注册且无法加载的可能性。

蓝牙音频示例 APO INF 示例

此示例演示了系统效果的这种组合:

  • 带 PKEY_SFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_StreamEffectClsid

  • 带 PKEY_MFX_ProcessingModes_Suppoted_For_Streaming 的 PKEY_FX_ModeEffectClsid

此示例代码支持蓝牙免提和立体声设备。

; wdma_bt.inf – example usage
...
[BthA2DP]
Include=ks.inf, wdmaudio.inf, BtaMpm.inf
Needs=KS.Registration,WDMAUDIO.Registration,BtaMPM.CopyFilesOnly,mssysfx.CopyFilesAndRegister
...
[BTAudio.SysFx.Render]
HKR,"FX\\0",%PKEY_ItemNameDisplay%,,%FX_FriendlyName%
HKR,"FX\\0",%PKEY_FX_StreamEffectClsid%,,%FX_STREAM_CLSID%
HKR,"FX\\0",%PKEY_FX_ModeEffectClsid%,,%FX_MODE_CLSID%
HKR,"FX\\0",%PKEY_FX_UiClsid%,,%FX_UI_CLSID%
HKR,"FX\\0",%PKEY_FX_Association%,,%KSNODETYPE_ANY%
HKR,"FX\\0",%PKEY_SFX_ProcessingModes_Supported_For_Streaming%,0x00010000,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%
HKR,"FX\\0",%PKEY_MFX_ProcessingModes_Supported_For_Streaming%,0x00010000,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%
...
[Strings]
FX_UI_CLSID      = "{5860E1C5-F95C-4a7a-8EC8-8AEF24F379A1}"
FX_STREAM_CLSID  = "{62dc1a93-ae24-464c-a43e-452f824c4250}"
PKEY_FX_StreamEffectClsid   = "{D04E05A6-594B-4fb6-A80D-01AF5EED7D1D},5"
PKEY_FX_ModeEffectClsid     = "{D04E05A6-594B-4fb6-A80D-01AF5EED7D1D},6"
PKEY_SFX_ProcessingModes_Supported_For_Streaming = "{D3993A3F-99C2-4402-B5EC-A92A0367664B},5"
PKEY_MFX_ProcessingModes_Supported_For_Streaming = "{D3993A3F-99C2-4402-B5EC-A92A0367664B},6"
AUDIO_SIGNALPROCESSINGMODE_DEFAULT = "{C18E2F7E-933D-4965-B7D1-1EEF228D2AF3}"

APO INF 音频示例

此示例 INF 文件演示了以下系统效果组合:

  • 带 PKEY_SFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_StreamEffectClsid

  • 带 PKEY_MFX_ProcessingModes_Suppoted_For_Streaming 的 PKEY_FX_ModeEffectClsid

  • 不带 PKEY_EFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_EndpointEffectClsid

[MyDevice.Interfaces]
AddInterface=%KSCATEGORY_AUDIO%,%MyFilterName%,MyAudioInterface

[MyAudioInterface]
AddReg=MyAudioInterface.AddReg

[MyAudioInterface.AddReg]
;To register an APO for discovery, use the following property keys in the .inf (or at runtime when registering the KSCATEGORY_AUDIO device interface):
HKR,"FX\\0",%PKEY_FX_StreamEffectClsid%,,%FX_STREAM_CLSID%
HKR,"FX\\0",%PKEY_FX_ModeEffectClsid%,,%FX_MODE_CLSID%
HKR,"FX\\0",%PKEY_FX_EndpointEffectClsid%,,%FX_MODE_CLSID%

;To register an APO for streaming and discovery, add the following property keys as well (to the same section):
HKR,"FX\\0",%PKEY_SFX_ProcessingModes_For_Streaming%,%REG_MULTI_SZ%,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%,%AUDIO_SIGNALPROCESSINGMODE_MOVIE%,%AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS%

;To register an APO for streaming in multiple modes, use a REG_MULTI_SZ property and include all the modes:
HKR,"FX\\0",%PKEY_MFX_ProcessingModes_For_Streaming%,%REG_MULTI_SZ%,%AUDIO_SIGNALPROCESSINGMODE_DEFAULT%,%AUDIO_SIGNALPROCESSINGMODE_MOVIE%,%AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS%

定义自定义 APO 和 CLSID APO INF 示例

此示例演示如何为自定义 APO 定义自己的 CLSID。 此示例使用 MsApoFxProxy CLSID {889C03C8-ABAD-4004-BF0A-BC7BB825E166}。 对此 GUID 进行共同创建会在 MsApoFxProxy.dll 中实例化一个类,该类会实现 IAudioProcessingObject 接口,并通过 KSPROPSETID_AudioEffectsDiscovery 属性集查询基础驱动程序。

此 INF 文件示例会显示 [BthHfAud] 节,以从 wdmaudio.inf [BthHfAud.AnlgACapture.AddReg.Wave] 中拉取 [MsApoFxProxy.Registration],后者随后将 PKEY_FX_EndpointEffectClsid 注册为 MsApoFxProxy.dll 的已知 CLSID。

此 INF 文件示例还演示了如何使用此系统效果组合:

  • 不带 PKEY_EFX_ProcessingModes_Supported_For_Streaming 的 PKEY_FX_EndpointEffectClsid
;wdma_bt.inf
[BthHfAud]
Include=ks.inf, wdmaudio.inf, BtaMpm.inf
Needs=KS.Registration, WDMAUDIO.Registration, BtaMPM.CopyFilesOnly, MsApoFxProxy.Registration
CopyFiles=BthHfAud.CopyList
AddReg=BthHfAud.AddReg

; Called by needs entry in oem inf
[BthHfAudOEM.CopyFiles]
CopyFiles=BthHfAud.CopyList

[BthHfAud.AnlgACapture.AddReg.Wave]
HKR,,CLSID,,%KSProxy.CLSID%
HKR,"FX\\0",%PKEY_FX_Association%,,%KSNODETYPE_ANY%
HKR,"FX\\0",%PKEY_FX_EndpointEffectClsid%,,%FX_DISCOVER_EFFECTS_APO_CLSID%
#endif

示例 APO 效果注册

此示例显示了 Sysvad ComponentizedApoSample.inx 中的 [Apo_AddReg] 节。 本节向 COM 注册交换流 GUID 并注册交换流 APO 效果。 [Apo_CopyFiles] 节的 DestinationDirs 为 13,它将 swapapo.dll 复制到 Driverstore。 有关详细信息,请参阅驱动程序包隔离中的“从驱动程序存储运行”。

有关 INF 文件的一般信息,请参阅 INF 文件概述

; ComponentizedApoSample.inx

...

[ApoComponent_Install]
CopyFiles = Apo_CopyFiles
AddReg    = Apo_AddReg

[Apo_CopyFiles]
swapapo.dll

...

[Apo_AddReg]
; Swap Stream effect APO COM registration
HKCR,CLSID\%SWAP_FX_STREAM_CLSID%,,,%SFX_FriendlyName%
HKCR,CLSID\%SWAP_FX_STREAM_CLSID%\InProcServer32,,0x00020000,%13%\swapapo.dll
HKCR,CLSID\%SWAP_FX_STREAM_CLSID%\InProcServer32,ThreadingModel,,"Both"

'''
; Swap Stream effect APO registration
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"FriendlyName",,%SFX_FriendlyName%
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"Copyright",,%Copyright%
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MajorVersion",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MinorVersion",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"Flags",0x00010001,%APO_FLAG_DEFAULT%
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MinInputConnections",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MaxInputConnections",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MinOutputConnections",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MaxOutputConnections",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"MaxInstances",0x00010001,0xffffffff
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"NumAPOInterfaces",0x00010001,1
HKR,AudioEngine\AudioProcessingObjects\%SWAP_FX_STREAM_CLSID%,"APOInterface0",,"{FD7F2B29-24D0-4B5C-B177-592C39F9CA10}"
...

[Strings]
; Driver developers would replace these CLSIDs with those of their own APOs
SWAP_FX_STREAM_CLSID   = "{B48DEA3F-D962-425a-8D9A-9A5BB37A9904}"

...

APO 注册

APO 注册用于支持使用加权计算动态匹配终结点效果的过程。 加权计算使用以下属性存储。 每个音频接口都有零个或多个终结点属性存储以及通过 .inf 或运行时注册的效果属性存储。 最具体的终结点属性存储和最具体的效果属性存储具有最高的权重,并且使用。 将忽略所有其他属性存储。

具体性的计算方式如下:

终结点属性存储权重

  1. 具有特定 KSNODETYPE 的 FX
  2. 具有 KSNODETYPE_ANY 的 FX
  3. 具有特定 KSNODETYPE 的 MSFX
  4. 具有 KSNODETYPE_ANY 的 MSFX

效果属性存储权重

  1. 具有特定 KSNODETYPE 的 EP
  2. 具有 KSNODETYPE_ANY 的 EP
  3. 具有特定 KSNODETYPE 的 MSEP
  4. 具有 KSNODETYPE_ANY 的 MSEP

数字必须从 0 开始并按顺序增加:MSEP\0、MSEP\1、…、MSEP\n如果(例如)缺少 EP\3,则 Windows 将停止查找 EP\n,并且不会看到 EP\4,即使它存在也是如此

PKEY_FX_Association(对于效果属性存储)或 PKEY_EP_Association(对于终结点属性存储)的值与信号路径硬件端引脚工厂的 KSPINDESCRIPTOR.Category 值(由内核流式处理公开)进行比较。

只有 Microsoft 收件箱类驱动程序(可由第三方开发人员包装)才应使用 MSEP 和 MSFX;所有第三方驱动程序都应使用 EP 和 FX。

APO 节点类型兼容性

以下 INF 文件示例演示如何将 PKEY_FX_Association 键设置为与 APO 关联的 GUID。

;; Property Keys
PKEY_FX_Association = "{D04E05A6-594B-4fb6-A80D-01AF5EED7D1D},0"
"
;; Key value pairs
HKR,"FX\\0",%PKEY_FX_Association%,,%KSNODETYPE_ANY%

由于音频适配器能够支持多个输入和输出,因此你必须显式指示自定义 APO 与之兼容的内核流式处理 (KS) 节点类型。 在前面的 INF 文件片段中,系统显示 APO 与 %KSNODETYPE_ANY% 的 KS 节点类型相关联。 在此 INF 文件的后面部分,KSNODETYPE_ANY 定义如下:

[Strings]
;; Define the strings used in MyINF.inf
...
KSNODETYPE_ANY      = "{00000000-0000-0000-0000-000000000000}"
KSNODETYPE_SPEAKER  = "{DFF21CE1-F70F-11D0-B917-00A0C9223196}"
...

KSNODETYPE_ANY 的 NULL 值表示此 APO 与任何类型的 KS 节点类型兼容。 例如,若要指示 APO 仅与 KSNODETYPE_SPEAKER KS 节点类型兼容,INF 文件将显示 KS 节点类型和 APO 关联,如下所示:

;; Key value pairs
...
HKR,"FX\\0",%PKEY_FX_Association%,,%KSNODETYPE_SPEAKER%
...

有关不同 KS 节点类型的 GUID 值的详细信息,请参阅 Ksmedia.h 头文件。

排查 APO 加载失败问题

提供了以下信息,可帮助你了解如何监视 API 的失败。 可以使用此信息排查无法合并到音频图中的 APO。

音频系统会监视 APO 返回代码,以确定是否成功将 APO 合并到图形中。 它通过跟踪由任一指定方法返回的 HRESULT 值来监视返回代码。 系统会为每个要合并到图形中的 SFX、MFX 和 EFX APO 维护单独的失败计数值。

音频系统会从以下四种方法监视所返回的 HRESULT 值。

  • CoCreateInstance

  • IsInputFormatSupported

  • IsOutputFormatSupported

  • LockForProcess

每次这些方法之一返回失败代码时,APO 的失败计数值都会递增。 当 APO 返回指示已成功合并到音频图中的代码时,失败计数将重置为零。 成功调用 LockForProcess 方法可很好地表明已成功合并 APO。

特别是对于 CoCreateInstance,返回的 HRESULT 代码可能指示失败的原因有很多。 三个主要原因如下:

  • 图形正在运行受保护的内容,并且 APO 未正确签名。

  • 未注册 APO。

  • APO 已重命名或被篡改。

此外,如果 SFX、MFX 或 EFX APO 的失败计数值达到系统指定的限制,则通过将 PKEY_Endpoint_Disable_SysFx 注册表项设置为“1”来禁用 SFX、MFX 和 EFX APO。 系统指定的限制当前值为 10。

Windows 音频处理对象

创建组件化音频驱动程序安装

驱动程序包隔离