- 示例工程
【免费下载链接】Windows-driver-samples
This repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.
本指南以 audio/SoundWire/Samples/SdcaVad/README.md 为骨架,系统讲解 Microsoft SDCA 虚拟音频设备驱动(SdcaVad)示例:它是 Windows 驱动开发中首个同时涵盖 ACX(Audio Class eXtension)音频框架与 SDCA(Sound Device Class for Audio)规范的分层驱动样例,由虚拟 Codec、虚拟 DSP、虚拟 XU 三个内核驱动加一个关键词唤醒 APO、一个事件检测适配器组成。读完本文,你将掌握该示例解决方案的工程结构、从 Visual Studio 编译到目标机部署测试的完整流程、以及 HLK 音频测试的已知边界,并能对照仓库源码理解 ACX 复合电路(Composite Circuit)组合、SDCA 特殊流(Special Stream)创建与关键词检测(KWS)的底层实现。
示例概览:一套完整的 SDCA 音频设备分层
SdcaVad 的核心目标是展示如何基于 ACX/SDCA 开发支持 SDCA 音频设备的驱动。它不依赖真实硬件,而是用软件模拟出一个完整的 SDCA 音频设备栈——这也是 README 将其称为 "Virtual Audio Device" 的原因:虚拟 Codec、虚拟 DSP 与虚拟 XU 分别扮演 SDCA 规范中的不同角色,并以 ACX 电路(Circuit)模板的形式组合成端到端的音频通路。
README 给出了各个子目录的功能定位,下表为原文表格的完整继承:
| 目录 | 说明 |
|---|---|
| SdcaVCodec | SDCA 虚拟 Codec 驱动(Virtual Codec Driver) |
| SdcaVDsp | SDCA 虚拟 DSP 驱动(Virtual DSP Driver) |
| SdcaVXu | SDCA 虚拟 XU 驱动(Virtual XU Driver) |
| Apo\kws | 示例 APO:通过 KSPROPERTY_INTERLEAVEDAUDIO_FORMATINFORMATION 判断关键词点测(keyword spotter)引脚是否将回环(loopback)音频与麦克风音频交织,并识别哪些声道包含回环音频;若为交织,则剥离回环音频,仅向上游传递麦克风音频。由于声道数据被移除,APO 协商出的输出格式与输入格式不同 |
| EventDetectorAdapter | 示例事件检测适配器(Event Detector Adapter) |
从解决方案文件 SDCAVad.sln 可以看到,整个解决方案包含6 个项目:SDCAVCodec、SDCAVDsp、SDCAVXu 三个驱动项目,KWSApo(关键词唤醒 APO),EventDetectorContosoAdapter(事件检测适配器),以及负责打包的 package 项目,与 README 中 "one solution that has six projects" 的描述一一对应。
三种"虚拟"驱动在 SDCA 栈中的角色
从源码结构可以清晰看出三者的分工:
- SdcaVCodec(虚拟 Codec):作为根枚举设备(
ROOT\SDCAVCodec,见 SdcaVCodec.inx)加载,负责建立完整的音频通路(render + capture),并通过复合电路模板把 Codec 电路、XU 扩展电路、DSP 电路组合在一起。device.cpp 中定义了 Render/Capture 两组电路元数据:扬声器电路DSP_CIRCUIT_SPEAKER_GUID、麦克风电路DSP_CIRCUIT_MICROPHONE_GUID、DSP 工厂 URIacpi:obj-path:\_SB.PC00.HDAS以及厂商 blob(Streaming_Speaker/Streaming_MicrophoneArray)。 - SdcaVDsp(虚拟 DSP):以
SOUNDWIRETEST\DSP硬件 ID 加载(见 SdcaVDsp.inx),并且是 README 所述"可动态枚举子设备"的一端——其 INF 同时把扬声器/麦克风作为子设备({4DCB0606-...}\Render、{4DCB0606-...}\Capture)枚举。它负责流引擎(streamengine.h)与关键词检测(KeywordDetector.cpp)。 - SdcaVXu(虚拟 XU):以
Class=Extension、ExtensionId={790C1DE0-AA33-4CB8-BB0C-F523C73B4AA1}的扩展驱动形式安装(见 SdcaVXu.inx),作为 SDCAVCodec 的 LowerFilter 挂载(AddFilter=SDCAVXu),其 PDO 由 Codec 驱动枚举出来,模拟 SDCA 规范中的 XU(eXchange Unit)实体。
从 device.cpp 的Codec_AddComposites可以看到三个电路模板的组装顺序:先创建 Codec 电路模板(对应 Codec URI),若检测到 XU(devCtx->SdcaXuData.bSdcaXu)则追加 XU 扩展电路模板,最后追加 DSP 电路模板(带AcxCircuitTemplateCircuitOnDemand标志,即按需实例化的 DSP 电路),随后调用AcxCompositeTemplateAssignCircuits把三块电路绑定进复合电路,并通过AcxCompositeTemplateSetCoreCircuit将 Codec 电路指定为核心电路。这正是 ACX 框架下"多驱动协作组成单一音频端点"的标准范式,也是本样例最值得研读的架构点。
构建示例:从打开解决方案到拿到驱动包
如果只是编译该示例驱动、不打算运行或测试,则不需要目标计算机(测试计算机);若要部署、运行和测试,则需要第二台计算机作为目标机。README 对构建流程给出了四个步骤,以下完整继承并补充细节。
1. 在 Visual Studio 中打开驱动解决方案
打开 Microsoft Visual Studio,点击文件>打开>项目/解决方案…,导航到包含示例文件的目录(例如C:\Windows-driver-samples\audio\SdcaVad),双击sdcavad解决方案文件(仓库中对应 SDCAVad.sln)。若 Solution Explorer 未显示,从视图菜单打开它——可以看到一个解决方案、六个项目(三个驱动、一个 APO、一个适配器、一个打包项目)。
2. 设置示例的配置与平台
在 Solution Explorer 中右键Solution 'sdcavad' (6 of 6 projects),选择Configuration Manager。确保六个项目的配置和平台设置一致:全部设为Debug配置、x64平台。如果只改动其中某个项目的配置或平台,必须为其余所有项目做相同修改,否则打包环节会因架构混用而失败。
3. 使用 Visual Studio 构建
在 Visual Studio 中点击生成>生成解决方案。构建成功后,SDCAVCodec / SDCAVDsp / SDCAVXu 三个驱动会被编译为.sys,KWS APO 与事件检测适配器被编译为.dll,并统一收进 package 项目生成的驱动包目录。
4. 定位生成的驱动包
在文件资源管理器中进入示例目录。驱动包的存放位置取决于 Configuration Manager 中选择的配置与平台:例如选择Debug与x64时,包位于x64\Debug\package文件夹。README 给出了包的完整文件清单,逐项继承如下:
| 文件 | 说明 |
|---|---|
| SdcaVCodec.sys | SDCA 虚拟 Codec 驱动文件 |
| SdcaVCodec.inf | 安装 SDCA 虚拟 Codec 驱动所需的信息(INF)文件 |
| SdcaVDsp.sys | SDCA 虚拟 DSP 驱动文件 |
| SdcaVDsp.inf | 安装 SDCA 虚拟 DSP 驱动的信息(INF)文件 |
| SdcaVXu.sys | SDCA 虚拟 XU 驱动文件 |
| SdcaVXu.inf | 安装 SDCA 虚拟 XU 驱动的信息(INF)文件 |
| EventDetectorContosoAdapter.dll | 示例事件检测适配器 |
| SdcaVKwsApo.dll | KWS(关键词唤醒)APO |
| SdcaVApo.inf | 安装 APO 设备的信息(INF)文件 |
| sdcavad.cat | 已签名目录文件,作为整个包的签名 |
构建相关源码速览
在构建层面,三个驱动都遵循标准的 WDF + ACX 初始化模板。以 SdcaVCodec/driver.cpp 的DriverEntry为例:
- 先通过
WdfDriverCreate创建 WDF 驱动对象并注册Codec_DriverUnload; - 使用
WppRecorderLogCreate创建 WPP Recorder 日志(日志标识"SDCAVCodec"); - 调用
AcxDriverInitialize完成 ACX 框架初始化; - 用
AcxDriverIsVersionAvailable校验 ACX 库版本(要求版本 1.0 可用),并调用Test_ClientVersionHigherThanFramework演示如何用ACX_IS_FIELD_AVAILABLE宏判断较新的框架字段(如ACX_DEVICEINIT_CONFIG.SynchronizationScope)是否可用——这是编写同时兼容新旧 ACX 库的驱动时的实用技巧。
运行示例:目标机准备、安装与验证
安装驱动的机器称为目标计算机(target / test computer),编译驱动包的机器称为主机(host computer)。将驱动包移动到目标机并安装的过程称为部署(deploying),SdcaVad 支持自动部署与手动部署两种方式。
准备目标计算机
目标机需先安装最新版 Windows Driver Kit(WDK),最低版本要求为25926,对应 Canary 频道(这是 README 明确标注的硬性版本门槛,低于该版本将无法编译/加载依赖新 ACX 接口的组件)。
手动部署前,必须通过以下方式准备目标机:开启测试签名、安装证书、定位 WDK 中的 DevCon 工具。
以管理员身份打开命令提示符,输入以下命令开启测试签名:
bcdedit /set TESTSIGNING ON然后重启目标机。
[!IMPORTANT] 在使用 BCDEdit 修改启动信息之前,可能需要临时挂起 BitLocker 和 Secure Boot 等 Windows 安全功能。测试完成后应重新启用这些安全功能,并妥善管理处于安全功能关闭状态下的测试机。
重启后,进入 WDK 安装目录下的 Tools 文件夹定位 DevCon 工具,例如:
C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe将devcon.exe复制到目标机上一个容易找到的目录(例如创建C:\Tools并复制进去)。然后在目标机创建驱动包目录(如C:\SdcaVad),把主机上构建出的驱动包中所有文件复制过去。
为构建过程生成的证书单独建一个目录(如C:\Certificates),把主机上与package文件夹同级的package.cer复制过去;在目标机上右键证书文件 →安装,按提示安装测试证书。若需要更详细的手动部署准备步骤,README 指向了 "Preparing a Computer for Manual Driver Deployment" 文档。
关于签名的说明
由于这些二进制大部分在内核模式下执行,签名(可选地,接入内核调试器)至关重要:
- 无任何签名且未接内核调试器时,驱动无法安装到目标机;
- 接入内核调试器时,驱动可以安装,
.sys文件会被加载,但用户态.dll文件不会被加载; - 要让整个示例(
.sys、.dll、.cat)全部加载执行,唯一的方式是全部文件由可信证书签名——这样即使没有内核调试器,整个驱动也能被加载。
这也是 SdcaVad 的package项目默认输出sdcavad.cat已签名目录文件的原因。
安装驱动(单 INF 文件方式)
每个示例驱动各自带一个 INF 文件,用于安装对应驱动。在目标机上以管理员身份打开命令提示符,进入驱动包目录后依次执行:
devcon install SdcaVDsp.inf SOUNDWIRETEST\DSP devcon install SdcaVCodec.inf Root\SDCAVCodec随后安装 XU 的 INF(SdcaVXu.inf)与 APO 的 INF(SdcaVApo.inf)——右键 INF 文件并选择安装即可(这两者采用右键安装方式而非 devcon)。
值得注意的安装顺序与层次:devcon install SdcaVDsp.inf SOUNDWIRETEST\DSP先让 DSP 驱动以测试硬件 ID 加载,devcon install SdcaVCodec.inf Root\SDCAVCodec再让 Codec 驱动以根枚举方式出现;而 XU 作为 Codec 的 LowerFilter(SdcaVXu.inx 中的AddFilter=SDCAVXu)与 DSP 的动态枚举子设备,则由驱动的 PnP 回调自动建立。驱动安装成功后即可开始测试。
测试驱动
在目标机命令提示符输入devmgmt.msc打开设备管理器,在查看菜单选择按类型列出设备,在设备树中找到SDCA Virtual Dsp Audio Driver(通常位于声音、视频和游戏控制器节点下)。
打开控制面板 →硬件和声音→管理音频设备,在声音对话框中选择标签为SDCA Virtual Codec Audio Driver的扬声器图标,点击设为默认,但不要点击"确定"(保持对话框打开)。然后双击目标机上的 MP3 或其他音频文件播放,回到声音对话框确认SDCA Virtual Codec Audio Driver对应的音量指示条有活动。
HLK 测试与已知边界
该示例使用最新可用版本的 HLK 测试,以确保通过当前 playlist 中的全部音频测试。但由于它是虚拟音频驱动,未实现混音(mixing),并用生成的正弦音(tone)模拟采集与回环,因此存在部分依赖上述真实功能的 HLK 测试预期失败。README 明确列举了两类例外:
- Hardware Offload of Audio Processing Test:该测试面向支持 offload 能力的设备。对 SdcaVad 而言,带 offload 和 loopback 的端点会失败——offload 端点失败是因为驱动包含 offload 引脚,但未实现带音量、静音、峰值表等节点的混音器;loopback 端点失败是因为驱动用正弦音模拟回环,而不是真正混合 host/offload 引脚上的流。
- 当前版本还未通过 General Audio Test 与 Device Power State Transition Test,官方正在调查失败原因。
源码侧与这两条边界直接相关的实现证据:streamengine.h 中定义DEFAULT_FREQUENCY (220)与LOOPBACK_FREQUENCY (500),配合 ToneGenerator.h 的正弦波生成器,印证了 README"用 tone 模拟 capture 和 loopback"的描述;KeywordDetector.cpp 的 DPC 例程也以RtlZeroMemory填充采样(TODO 注释建议未来可接入 ToneGenerator),再次说明该虚拟设备不执行真实的音频信号处理。
深入源码:两条值得重点研读的实现链路
链路一:SDCA 特殊流(Special Stream)的创建与启停
circuitstream.cpp 展示了 DSP 驱动如何通过 SDCA 属性集(KSPROPERTYSETID_Sdca)向下游 Codec 电路下发特殊流路径控制:
Dsp_PrepareSpecialStreamForStream:在 host/offload 引脚准备硬件时启动IV Sense(SpecialStreamTypeIvSense)流;在 loopback 引脚上启动Reference Stream(SpecialStreamTypeReferenceStream)流。优先使用KSPROPERTY_SDCA_CREATE_PATH2(携带完整 path descriptor2),否则复制下游返回的SDCA_PATH_DESCRIPTORS,按FunctionBitMask过滤音频功能、将格式收敛到 48 kHz 单一格式、数据端口收敛到 1,再以KSPROPERTY_SDCA_CREATE_PATH下发(circuitstream.cpp);Dsp_StartSpecialStreamsForStream/Dsp_StopSpecialStreamsForStream/Dsp_ReleaseSpecialStreamsForStream:分别以KSPROPERTY_SDCA_START_PATH、KSPROPERTY_SDCA_STOP_PATH、KSPROPERTY_SDCA_DESTROY_PATH控制路径,并通过电路上下文中的InterlockedIncrement/Decrement引用计数保证多个流共享同一条特殊流硬件时只在最后一个使用者退出时才销毁路径。
这段代码是理解"ACX 多电路协作下,DSP 通过属性请求驱动 Codec 侧真实硬件通路"的极佳范本,也是 SDCA 规范中 Sense/Reference stream 机制在驱动层的完整落地。
链路二:关键词检测(KWS)与事件检测适配器的协作
KWS 链路横跨内核(DSP 驱动)与用户态(APO + 适配器)两层:
- 内核侧:KeywordDetector.cpp 定义了三态机——Disarmed(解除武装)、Armed + Suspended(武装但挂起,即 Codec 驱动需要访问硬件导致的"失聪期")、Armed + Prepared(武装且已准备,正在检测)。状态迁移通过
KSPROPERTY_SDCAKWS_CONFIGURE_VAD_PORT/KSPROPERTY_SDCAKWS_CLEANUP_VAD_PORT配置 VAD 流,并通过KSPROPERTY_SDCAKWS_ACCESS_EVENTS注册 Suspend/Resume 通知事件(KeywordDetector.cpp)。检测数据的包缓冲(packet fifo)、QPC 时间戳对齐、关键词起止时间戳均在此实现,其中起止时间戳还可通过注册表KeywordDetectorStartTimestamp/KeywordDetectorStopTimestamp(REG_QWORD)读取(KeywordDetector.cpp)。 - 用户态侧:EventDetectorContosoAdapter.cpp 实现
IEventDetectorOemAdapter:GetCapabilities声明 16 kHz 单声道 PCM({WAVE_FORMAT_PCM, 1, 16000, 32000, 2, 16, 0})、语言 0x0409(en-US)、无用户录音;GetCapabilitiesForLanguage上报两个检测事件CONTOSO_KEYWORD1 / CONTOSO_KEYWORD2(GUID 定义见 Inc/ContosoEventDetector.h);BuildArmingPatternData生成CONTOSO_KEYWORDCONFIGURATION模式数据,ParseDetectionResultData解析CONTOSO_KEYWORDDETECTIONRESULT并回填事件起止时间戳。适配器的 CLSID({207F3D0C-5C79-496F-A94C-D3D2934DBFA9})由 SdcaVDsp.inx 注册进HKCR\CLSID,README 也提示"驱动开发者应将该 CLSID 替换为自己的关键词检测 OEM 适配器"。
结合 INF 理解端点枚举与 APO 挂载
三个 INF 共同刻画了虚拟设备的端点拓扑:
- SdcaVCodec.inx 以
AddInterface注册Speaker0(KSCATEGORY_AUDIO + KSCATEGORY_TOPOLOGY)与Microphone0,并对端点写入了PKEY_AudioEndpoint_Supports_EventDriven_Mode=1等属性,显式选择拉模式(pull mode); - SdcaVDsp.inx 则同时注册 KSCATEGORY_RENDER / KSCATEGORY_CAPTURE / KSCATEGORY_REALTIME 接口(其中 render 端点的 capture 接口被注释掉,用作 loopback 说明),并把事件检测适配器 DLL 一并复制到系统目录;
- APO 的挂载由 SdcaVApo.inf 完成(位于包内,源码目录中未见单独 INX 源文件),它安装一个 APO 设备,把
SdcaVKwsApo.dll与 Codec 的麦克风端点关联。
而 KWS APO 的核心处理逻辑在 Apo/kws/KWSApo.cpp 的ProcessBuffer中一目了然:依据INTERLEAVED_AUDIO_FORMAT_INFORMATION(PrimaryChannelStartPosition/PrimaryChannelCount/InterleavedChannelCount),只把主声道(麦克风)数据拷贝到输出,跳过交织的回环声道;配合 KWSApoEfx.cpp 中Initialize通过IKsControl->KsProperty查询KSPROPERTY_INTERLEAVEDAUDIO_FORMATINFORMATION,以及IsOutputFormatSupported把输出声道数收敛为PrimaryChannelCount——这就是 README 所述"APO 协商出与输入不同的输出格式"的源码级证据。
小结
SdcaVad 是一个覆盖 ACX 驱动开发全链路的样例:构建(6 项目解决方案、Debug/x64 打包)、部署(WDK 25926+、测试签名、DevCon 单 INF 安装)、验证(设备管理器 + 声音面板)、HLK 测试(已知的 offload/loopback 例外与待调查失败项)。深入源码还可获得两条进阶主线:复合电路模板(Codec + XU + DSP)的组合机制与SDCA 特殊流 / 关键词检测的分层协作。对于准备开发真实 SDCA Codec、DSP 或关键词唤醒(KWS)驱动的开发者,这是一个可以直接作为起点并对照移植的参考实现。
- 示例工程
【免费下载链接】Windows-driver-samples
This repo contains driver samples prepared for use with Microsoft Visual Studio and the Windows Driver Kit (WDK). It contains both Universal Windows Driver and desktop-only driver samples.
相关推荐
SysVAD 虚拟音频设备驱动示例详解:基于 WaveRT 与音频卸载的 WDM 音频驱动框架(Windows-driver-samples)
SysVAD 虚拟音频设备驱动示例详解:基于 WaveRT 与音频卸载的 WDM 音频驱动框架(Windows driver samples) 本指南以 Mic
示例工程Windows 驱动开发实战:SimpleAudioSample 虚拟音频设备驱动详解(构建、部署与架构剖析)
Windows 驱动开发实战:SimpleAudioSample 虚拟音频设备驱动详解(构建、部署与架构剖析) 导读 本文围绕 Windows driver s
示例工程Windows-driver-samples 中的 NDIS 虚拟微型端口驱动示例 netvmini 深度解析
Windows driver samples 中的 NDIS 虚拟微型端口驱动示例 netvmini 深度解析 本指南围绕 Windows driver sam
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考