实现音频模块通信

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

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

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

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

为何使用音频模块?

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

通用 Windows 平台 (UWP) 提供一组 API,使单个应用程序能够跨各种设备运行。 UWP 还引入了新的外观,已成为客户对在 Windows 10 上运行的应用程序的期望。 许多 OEM 都希望在 UWP 上构建其音频配置应用程序。 但是,UWP 的核心安全功能 (AppContainer 沙盒) 阻止从应用程序与音频子系统中的其他组件进行通信。 这会使配置应用以前使用的专用 API 在 UWP 中不可访问。

从 Windows 10 版本 1703 开始,音频模块 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 和其他应用程序将只能访问通过筛选器句柄提供的模块。 在流上加载的各个 ADO 是唯一有权访问流目标音频模块的对象。

有关 ADO 的详细信息,请参阅 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 调用序列。