实现音频模块通信

音频模块是执行相对原子函数的不同音频处理逻辑片段。 音频模块可能驻留在音频驱动程序或音频 DSP 中。 一个示例音频模块是基于 DSP 的音频处理。

从版本 1703 Windows 10开始,有 API 和 DDI 支持从 通用 Windows 平台 (UWP) 应用和内核模式设备驱动程序进行通信。

本主题提供有关在内核设备驱动程序中实现音频模块通信的信息。

有关如何使用 UWP 应用从音频设备模块发送命令和接收更改通知的信息,请参阅 配置和查询音频设备模块

为什么使用音频模块?

OEM 通常在其系统上捆绑一个配置应用程序,使客户能够控制此音频系统的方面,并将其调整为其首选项。 音频子系统可以包含各种组件,例如主机音频处理对象、硬件 DSP 处理和专用硬件,例如智能 amp (,除了音频编解码器本身) 。 在大多数情况下,这些组件由不同的供应商创建和销售。 从历史上看,IHV 创建了自己的专用 API,以彼此集成,并在各个组件之间发送信息。 然后,现有的 WIN32 配置应用程序将利用这些专用 API。

通用 Windows 平台 (UWP) 提供了一组 API,使单个应用程序能够跨大量设备运行。 UWP 还引入了新的外观,这已成为客户对在 Windows 10 上运行的应用程序的期望。 许多 OEM 想要在 UWP 上生成其音频配置应用程序。 但是,UWP (AppContainer 沙盒的核心安全功能) 可防止将应用程序与音频子系统中的其他组件通信。 这会呈现以前在 UWP 中无法访问的配置应用使用的专用 API。

从版本 1703 Windows 10开始,音频模块 UWP API 允许配置应用程序和用户模式组件与内核和硬件层中的模块通信,这些模块可通过新的 KS 属性集发现。 音频 IHV 和 ISV 可以编写应用程序和服务,这些应用程序和服务可以使用Windows提供的定义完善的接口与其硬件模块通信。 有关音频模块 API 的详细信息,请参阅Windows。Media.Devices 命名空间

音频模块定义

这些定义特定于音频模块。

术语 定义
音频模块 执行相对原子函数的不同音频处理逻辑片段。 可能驻留在音频驱动程序或音频 DSP 中。 一个示例音频模块是 APO) (音频处理对象。

常见音频定义

这些定义通常用于处理音频驱动程序。

术语 定义
OEM 原始设备制造商
IHV 独立硬件供应商
ISV 独立软件供应商
HSA 硬件支持应用程序
UWP 通用 Windows 平台
载 脂蛋白 音频处理对象
DSP 数字信号处理

体系结构

音频模块放置了一种支持Windows的机制,用于在用户模式和内核模式音频组件之间发送消息。 一个重要区别是音频模块标准化传输管道。 它不通过该传输建立通信协议,并且依赖于 ISV 和 IHV 来定义协议。 目的是允许现有的第三方设计轻松迁移到几乎没有变化的音频模块。

<待处理关系图>

音频模块 API 通过两种不同的目标方法提供对模块的访问:KS 波形筛选器和初始化的 KS 引脚 (流) 。 对特定模块的放置和访问特定于实现。

HSA 和其他应用程序只能访问通过筛选器句柄提供的模块。 在流上加载的单个 API 是唯一有权访问流目标音频模块的对象。

有关 API 的详细信息,请参阅Windows音频处理对象

发送命令

音频模块客户端查询和更改参数的途径是将命令发送到音频子系统的内核和硬件组件中的音频模块。 音频模块 API 的命令结构是松散定义的,并正式化模块的发现和标识方式。 但是,必须由所涉及的 ISV 和 IHV 设计和实现详细的命令结构,以便为可以发送的消息和预期的响应建立协议。

音频模块客户端的模块通知

如果客户端订阅了特定模块上的通知,则音频微型端口还可以向音频模块客户端通知和传递信息。 这些通知中传递的信息不是由音频模块 API 定义,而是由 ISV 和/或 IHV 定义。

启用、禁用和常规拓扑信息

音频模块 API 定义如何枚举命令并将其发送到模块。 但是,API 未显式定义音频模块客户端如何启用或禁用特定模块。 此外,它不会为客户端建立一种方法来查找拓扑信息或彼此相关的模块放置。 IHV 和 ISV 可以确定是否需要此功能,以确定如何实现此功能。

建议的方法是公开全局驱动程序模块。 全局驱动程序模块将处理这些拓扑特定请求的自定义命令。

音频模块 DDI

内核流式处理音频模块属性

为特定于音频模块的三个属性定义了 由KSPROPSETID_AudioModule标识的新 KS 属性集。

PortCls 微型端口驱动程序需要直接处理每个属性的响应,因为未提供帮助程序接口。

ksmedia.h:

#define STATIC_KSPROPSETID_AudioModule \
    0xc034fdb0, 0xff75, 0x47c8, 0xaa, 0x3c, 0xee, 0x46, 0x71, 0x6b, 0x50, 0xc6
DEFINE_GUIDSTRUCT("C034FDB0-FF75-47C8-AA3C-EE46716B50C6", KSPROPSETID_AudioModule);
#define KSPROPSETID_AudioModule DEFINE_GUIDNAMED(KSPROPSETID_AudioModule)

typedef enum {
    KSPROPERTY_AUDIOMODULE_DESCRIPTORS            = 1,  
    KSPROPERTY_AUDIOMODULE_COMMAND                = 2,
    KSPROPERTY_AUDIOMODULE_NOTIFICATION_DEVICE_ID = 3,
} KSPROPERTY_AUDIOMODULE;

音频模块描述符

KSPROPERTY_AUDIOMODULE_DESCRIPTORS 属性的支持将驱动程序标识为音频模块感知。 将通过筛选器或引脚句柄查询该属性,并将 KSPROPERTY 作为 DeviceIoControl 调用的输入缓冲区传递。 KSAUDIOMODULE_DESCRIPTOR 已定义,用于描述音频硬件中的每个模块。 返回这些描述符的数组以响应此请求

ksmedia.h:

#define AUDIOMODULE_MAX_NAME_SIZE 128

typedef struct _KSAUDIOMODULE_DESCRIPTOR
{
    GUID    ClassId; 
    ULONG   InstanceId;
    ULONG   VersionMajor;
    ULONG   VersionMinor;
    WCHAR   Name[AUDIOMODULE_MAX_NAME_SIZE];
} KSAUDIOMODULE_DESCRIPTOR, *PKSAUDIOMODULE_DESCRIPTOR;

有关详细信息,请参阅 KSAUDIOMODULE_DESCRIPTOR

音频模块命令

KSPROPERTY_AUDIOMODULE_COMMAND 属性的支持允许音频模块客户端发送自定义命令来查询和设置音频模块上的参数。 该属性可以通过筛选器或引脚句柄发送, KSAUDIOMODULE_PROPERTY 作为 DeviceIoControl 调用的输入缓冲区传递。 客户端可以选择在输入缓冲区中的 KSAUDIOMODULE_PROPERTY 旁边发送其他信息,以发送自定义命令。

ksmedia.h:

#define AUDIOMODULE_MAX_DATA_SIZE 64000

typedef struct _KSPAUDIOMODULE_PROPERTY
{
    KSPROPERTY Property;
    GUID       ClassId;
    ULONG      InstanceId;
} KSAUDIOMODULE_PROPERTY, *PKSPAUDIOMODULE_PROPERTY;

有关详细信息,请参阅 KSAUDIOMODULE_PROPERTY

音频模块通知设备 ID

需要对 KSPROPERTY_AUDIOMODULE_NOTIFICATION_DEVICE_ID 的支持才能使微型端口能够发出通知,并将信息传递给音频模块客户端。 此 ID 的生存期与要公开和处于活动状态的音频设备的生存期相关联,并绑定到Windows音频堆栈。 该属性可以通过筛选器或引脚句柄发送,KSPROPERTY 作为 DeviceIoControl 调用的输入缓冲区传递。

有关详细信息,请参阅 KSAUDIOMODULE_PROPERTY

PortCls 帮助程序 - 音频模块通知

添加了新的端口接口,可帮助驱动程序开发人员向音频模块客户端发送通知。

PortCls.h:

typedef struct _PCNOTIFICATION_BUFFER 
{
    UCHAR NotificationBuffer[1];
} PCNOTIFICATION_BUFFER, *PPCNOTIFICATION_BUFFER;

DECLARE_INTERFACE_(IPortClsNotifications,IUnknown)
{
    DEFINE_ABSTRACT_UNKNOWN()   // For IUnknown

    STDMETHOD_(NTSTATUS, AllocNotificationBuffer)
    (   THIS_
        _In_    POOL_TYPE       PoolType,
        _In_    USHORT          NumberOfBytes,
        _Out_   PPCNOTIFICATION_BUFFER* NotificationBuffer
    )   PURE;
    
    STDMETHOD_(void, FreeNotificationBuffer)
    (   THIS_
        _In_    PPCNOTIFICATION_BUFFER NotificationBuffer
    )   PURE;
    
    STDMETHOD_(void, SendNotificationBuffer)
    (   THIS_
        _In_    const GUID*     NotificationId,
        _In_    PPCNOTIFICATION_BUFFER NotificationBuffer
    )   PURE;
};

//
// Audio module notification definitions.
//
#define STATIC_KSNOTIFICATIONID_AudioModule \
    0x9C2220F0, 0xD9A6, 0x4D5C, 0xA0, 0x36, 0x57, 0x38, 0x57, 0xFD, 0x50, 0xD2
DEFINE_GUIDSTRUCT("9C2220F0-D9A6-4D5C-A036-573857FD50D2", KSNOTIFICATIONID_AudioModule);
#define KSNOTIFICATIONID_AudioModule DEFINE_GUIDNAMED(KSNOTIFICATIONID_AudioModule)

typedef struct _KSAUDIOMODULE_NOTIFICATION {
    union {
        struct {
            GUID        DeviceId;
            GUID        ClassId;
            ULONG       InstanceId;
            ULONG       Reserved;
        } ProviderId;
        LONGLONG        Alignment;
    };
} KSAUDIOMODULE_NOTIFICATION, *PKSAUDIOMODULE_NOTIFICATION;


有关详细信息,请参阅:

IPortClsNotifications

IPortClsNotifications::AllocNotificationBuffer

IPortClsNotifications::FreeNotificationBuffer

IPortClsNotifications::SendNotificationBuffer

调用序列

微型端口将调用其端口以创建和发送通知。 此图中显示了常规调用序列。

AudioIPortClsNotifications Calling Sequence.