实现音频模块通信

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

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

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

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

为何使用音频模块?

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

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

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

音频模块定义

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

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

常见音频定义

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

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

体系结构

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

<待定关系图>

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

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

有关 APO 的详细信息,请参阅 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

调用序列

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

Diagram showing the calling sequence for AudioIPortClsNotifications.